将控件替换为AndroidX ,修改说明文档

old
zlj 6 years ago
parent 5c9d92b4dd
commit 27040c5e2f
  1. 4
      README.md
  2. 4
      app/build.gradle
  3. 55
      app/src/main/AndroidManifest.xml
  4. 21
      app/src/main/assets/litepal.xml
  5. 12
      app/src/main/java/com/novel/read/MainActivity.kt
  6. 286
      app/src/main/java/com/novel/read/activity/NovelBookDetailActivity.java
  7. 120
      app/src/main/java/com/novel/read/activity/NovelBookTypeListActivity.java
  8. 258
      app/src/main/java/com/novel/read/activity/NovelMainActivity.java
  9. 131
      app/src/main/java/com/novel/read/activity/NovelRankListActivity.java
  10. 813
      app/src/main/java/com/novel/read/activity/NovelReadActivity.java
  11. 105
      app/src/main/java/com/novel/read/activity/NovelRecommendBookListActivity.java
  12. 295
      app/src/main/java/com/novel/read/activity/NovelSearchActivity.java
  13. 174
      app/src/main/java/com/novel/read/activity/NovelSettingActivity.java
  14. 102
      app/src/main/java/com/novel/read/activity/NovelSplashActivity.java
  15. 188
      app/src/main/java/com/novel/read/adapter/BookAdapter.java
  16. 146
      app/src/main/java/com/novel/read/adapter/BookListAdapter.java
  17. 34
      app/src/main/java/com/novel/read/adapter/CategoryAdapter.java
  18. 87
      app/src/main/java/com/novel/read/adapter/EasyAdapter.java
  19. 85
      app/src/main/java/com/novel/read/adapter/EditRecommendAdapter.java
  20. 76
      app/src/main/java/com/novel/read/adapter/HistoryAdapter.java
  21. 73
      app/src/main/java/com/novel/read/adapter/HotAdapter.java
  22. 76
      app/src/main/java/com/novel/read/adapter/HumanAdapter.java
  23. 15
      app/src/main/java/com/novel/read/adapter/IViewHolder.java
  24. 81
      app/src/main/java/com/novel/read/adapter/LoveLyAdapter.java
  25. 97
      app/src/main/java/com/novel/read/adapter/MarkAdapter.java
  26. 74
      app/src/main/java/com/novel/read/adapter/PageStyleAdapter.java
  27. 77
      app/src/main/java/com/novel/read/adapter/RankAdapter.java
  28. 146
      app/src/main/java/com/novel/read/adapter/RankListAdapter.java
  29. 183
      app/src/main/java/com/novel/read/adapter/SearchAdapter.java
  30. 76
      app/src/main/java/com/novel/read/adapter/StackAdapter.java
  31. 38
      app/src/main/java/com/novel/read/adapter/ViewHolderImpl.java
  32. 31
      app/src/main/java/com/novel/read/adapter/ViewPageAdapter.java
  33. 53
      app/src/main/java/com/novel/read/adapter/holder/CategoryHolder.java
  34. 13
      app/src/main/java/com/novel/read/adapter/holder/EmptyHolder.java
  35. 23
      app/src/main/java/com/novel/read/adapter/holder/MoreHolder.java
  36. 26
      app/src/main/java/com/novel/read/base/BaseService.java
  37. 71
      app/src/main/java/com/novel/read/base/MyApp.java
  38. 139
      app/src/main/java/com/novel/read/base/NovelBaseActivity.java
  39. 59
      app/src/main/java/com/novel/read/base/NovelBaseFragment.java
  40. 110
      app/src/main/java/com/novel/read/constants/Constant.java
  41. 17
      app/src/main/java/com/novel/read/event/AddBookSignEvent.java
  42. 15
      app/src/main/java/com/novel/read/event/BookArticleEvent.kt
  43. 13
      app/src/main/java/com/novel/read/event/DeleteBookSignEvent.java
  44. 17
      app/src/main/java/com/novel/read/event/DeleteResponseEvent.java
  45. 16
      app/src/main/java/com/novel/read/event/DeleteTaskEvent.java
  46. 15
      app/src/main/java/com/novel/read/event/EditEvent.kt
  47. 12
      app/src/main/java/com/novel/read/event/ErrorChapterEvent.java
  48. 12
      app/src/main/java/com/novel/read/event/FinishChapterEvent.java
  49. 15
      app/src/main/java/com/novel/read/event/GetBookDetailEvent.kt
  50. 14
      app/src/main/java/com/novel/read/event/GetBookSignEvent.kt
  51. 18
      app/src/main/java/com/novel/read/event/GetCategoryTypeEvent.java
  52. 15
      app/src/main/java/com/novel/read/event/GetRecommendBookEvent.kt
  53. 12
      app/src/main/java/com/novel/read/event/HideBottomBarEvent.java
  54. 18
      app/src/main/java/com/novel/read/event/HotSearchEvent.java
  55. 16
      app/src/main/java/com/novel/read/event/HumanEvent.kt
  56. 10
      app/src/main/java/com/novel/read/event/LoginEvent.kt
  57. 18
      app/src/main/java/com/novel/read/event/RankByUpdateEvent.java
  58. 6
      app/src/main/java/com/novel/read/event/ReStartEvent.java
  59. 15
      app/src/main/java/com/novel/read/event/RecommendListEvent.kt
  60. 79
      app/src/main/java/com/novel/read/event/RxBus.java
  61. 15
      app/src/main/java/com/novel/read/event/SearchListEvent.kt
  62. 8
      app/src/main/java/com/novel/read/event/SetAdsBgEvent.java
  63. 13
      app/src/main/java/com/novel/read/event/SwitchFragmentEvent.java
  64. 13
      app/src/main/java/com/novel/read/event/UpdateBookEvent.java
  65. 14
      app/src/main/java/com/novel/read/event/VersionEvent.kt
  66. 302
      app/src/main/java/com/novel/read/fragment/BookFragment.java
  67. 119
      app/src/main/java/com/novel/read/fragment/BookListFragment.java
  68. 173
      app/src/main/java/com/novel/read/fragment/ManFragment.java
  69. 152
      app/src/main/java/com/novel/read/fragment/MoreFragment.java
  70. 67
      app/src/main/java/com/novel/read/fragment/RecommendFragment.java
  71. 104
      app/src/main/java/com/novel/read/fragment/StackFragment.java
  72. 209
      app/src/main/java/com/novel/read/fragment/WomanFragment.java
  73. 315
      app/src/main/java/com/novel/read/http/AccountManager.java
  74. 37
      app/src/main/java/com/novel/read/http/CommonHeadersInterceptor.java
  75. 59
      app/src/main/java/com/novel/read/http/ServiceGenerator.java
  76. 29
      app/src/main/java/com/novel/read/http/Urls.kt
  77. 94
      app/src/main/java/com/novel/read/http/service/AccountService.java
  78. 9
      app/src/main/java/com/novel/read/inter/OnLoadMoreListener.kt
  79. 161
      app/src/main/java/com/novel/read/model/db/BookChapterBean.java
  80. 43
      app/src/main/java/com/novel/read/model/db/BookRecordBean.java
  81. 98
      app/src/main/java/com/novel/read/model/db/ChapterInfoBean.java
  82. 198
      app/src/main/java/com/novel/read/model/db/CollBookBean.java
  83. 157
      app/src/main/java/com/novel/read/model/db/DownloadTaskBean.java
  84. 42
      app/src/main/java/com/novel/read/model/db/SearchListTable.java
  85. 223
      app/src/main/java/com/novel/read/model/db/dbManage/BookManager.java
  86. 371
      app/src/main/java/com/novel/read/model/db/dbManage/BookRepository.java
  87. 92
      app/src/main/java/com/novel/read/model/protocol/BookArticleResp.java
  88. 203
      app/src/main/java/com/novel/read/model/protocol/BookDetailResp.java
  89. 57
      app/src/main/java/com/novel/read/model/protocol/CategoryTypeResp.java
  90. 21
      app/src/main/java/com/novel/read/model/protocol/ChapterInfoPackage.java
  91. 18
      app/src/main/java/com/novel/read/model/protocol/HotSearchResp.java
  92. 120
      app/src/main/java/com/novel/read/model/protocol/MarkResp.java
  93. 115
      app/src/main/java/com/novel/read/model/protocol/RankByUpadateResp.java
  94. 112
      app/src/main/java/com/novel/read/model/protocol/RecommendBookResp.java
  95. 167
      app/src/main/java/com/novel/read/model/protocol/RecommendListResp.java
  96. 135
      app/src/main/java/com/novel/read/model/protocol/SearchResp.java
  97. 18
      app/src/main/java/com/novel/read/model/protocol/UidResp.java
  98. 138
      app/src/main/java/com/novel/read/model/protocol/VersionResp.java
  99. 17
      app/src/main/java/com/novel/read/service/DownloadMessage.java
  100. 448
      app/src/main/java/com/novel/read/service/DownloadService.java
  101. Some files were not shown because too many files have changed in this diff Show More

@ -5,6 +5,10 @@
## 使用技术
Kt、AndroidX、Retrofit、Okhttp3、Glide等
## TIP
目前书源为轻小说书源,书中大多带了插图,因此屏蔽了tts语音朗读功能,之后会切换成正常小说书源并添加语音朗读功能
因为书籍为爬取的数据,服务器在美国,所以国内监管比较严的时候可能需要翻墙或切换网络去多尝试几次,同时请各位大神手下留情不要攻击或者爬取数据,供大家学习使用。之后会切换成网络多数源。
## 项目截图
**主页**

@ -34,4 +34,8 @@ dependencies {
androidTestImplementation rootProject.ext.dependencies["espresso_core"]
implementation project(path: ':net_serivce')
implementation project(path: ':common_lib')
//
implementation "com.jakewharton:butterknife:10.0.0"
annotationProcessor "com.jakewharton:butterknife-compiler:10.0.0"
implementation 'com.allenliu.versionchecklib:library:2.2.0'
}

@ -3,21 +3,70 @@
xmlns:tools="http://schemas.android.com/tools"
package="com.novel.read">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<application
android:name=".base.MyApp"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:icon="@mipmap/logo"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme"
android:theme="@style/AppDartTheme"
android:networkSecurityConfig="@xml/network_security_config"
tools:ignore="GoogleAppIndexingWarning">
<activity android:name="com.novel.read.MainActivity">
<activity
android:name="com.novel.read.activity.NovelRankListActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.novel.read.activity.NovelReadActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.novel.read.activity.NovelSearchActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.novel.read.activity.NovelSplashActivity"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name="com.novel.read.activity.NovelRecommendBookListActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.novel.read.activity.NovelBookTypeListActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.novel.read.activity.NovelBookDetailActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.novel.read.activity.NovelSettingActivity"
android:screenOrientation="portrait" />
<activity
android:name="com.novel.read.activity.NovelMainActivity"
android:screenOrientation="portrait" />
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.fileProvider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
<service android:name="com.novel.read.service.DownloadService" />
</application>
</manifest>

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<litepal>
<dbname value="readDb" />
<version value="6" />
<list>
<!--搜索记录表-->
<mapping class="com.novel.read.model.db.SearchListTable"/>
<!--收藏书籍表-->
<mapping class="com.novel.read.model.db.CollBookBean"/>
<!--章节表-->
<mapping class="com.novel.read.model.db.BookChapterBean"/>
<!--阅读记录表-->
<mapping class="com.novel.read.model.db.BookRecordBean"/>
<!--章节详情表-->
<mapping class="com.novel.read.model.db.ChapterInfoBean" />
<!--章节详情表-->
<mapping class="com.novel.read.model.db.DownloadTaskBean" />
</list>
</litepal>

@ -1,12 +0,0 @@
package com.novel.read
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
}

@ -0,0 +1,286 @@
package com.novel.read.activity;
import android.annotation.SuppressLint;
import android.app.ProgressDialog;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.appcompat.widget.Toolbar;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.common_lib.base.utils.ToastUtils;
import com.mango.mangolib.event.EventManager;
import com.novel.read.R;
import com.novel.read.adapter.LoveLyAdapter;
import com.novel.read.base.NovelBaseActivity;
import com.novel.read.constants.Constant;
import com.novel.read.event.BookArticleEvent;
import com.novel.read.event.GetBookDetailEvent;
import com.novel.read.event.GetRecommendBookEvent;
import com.novel.read.event.UpdateBookEvent;
import com.novel.read.http.AccountManager;
import com.novel.read.model.db.BookChapterBean;
import com.novel.read.model.db.CollBookBean;
import com.novel.read.model.db.dbManage.BookRepository;
import com.novel.read.model.protocol.BookDetailResp;
import com.novel.read.model.protocol.RecommendBookResp;
import com.novel.read.utlis.DateUtli;
import com.novel.read.utlis.GlideImageLoader;
import com.novel.read.widget.RefreshLayout;
import com.squareup.otto.Subscribe;
import org.litepal.LitePal;
import java.util.ArrayList;
import java.util.List;
import butterknife.BindView;
import butterknife.OnClick;
import static com.novel.read.constants.Constant.RequestCode.REQUEST_READ;
import static com.novel.read.constants.Constant.ResultCode.RESULT_IS_COLLECTED;
public class NovelBookDetailActivity extends NovelBaseActivity {
@BindView(R.id.toolbar)
Toolbar toolbar;
@BindView(R.id.iv_book)
ImageView mIvBook;
@BindView(R.id.tv_book_name)
TextView mTvBookName;
@BindView(R.id.tv_book_author)
TextView mTvBookAuthor;
@BindView(R.id.tv_book_length)
TextView mTvBookLength;
@BindView(R.id.tv_new_title)
TextView mTvNewTitle;
@BindView(R.id.tv_update_time)
TextView mTvUpdateTime;
@BindView(R.id.tv_human_num)
TextView mTvHumanNum;
@BindView(R.id.tv_love_look_num)
TextView mTvLoveLookNum;
@BindView(R.id.tv_Intro)
TextView mTvIntro;
@BindView(R.id.rlv_lovely)
RecyclerView mRlvLovely;
@BindView(R.id.tv_add_book)
TextView mTvAddBook;
@BindView(R.id.tv_start_read)
TextView mTvStartRead;
@BindView(R.id.refresh)
RefreshLayout refreshLayout;
private LoveLyAdapter mAdapter;
private List<RecommendBookResp.BookBean> mList = new ArrayList<>();
private int mBookId;
private boolean isCollected = false;
private CollBookBean mCollBookBean;
private ProgressDialog mProgressDialog;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
protected int getLayoutId() {
return R.layout.activity_book_detail;
}
@Override
protected void initView() {
mBookId = getIntent().getIntExtra(Constant.Bundle.BookId,0);
mRlvLovely.setLayoutManager(new LinearLayoutManager(this));
mAdapter = new LoveLyAdapter(mList);
mRlvLovely.setAdapter(mAdapter);
}
@Override
protected void initData() {
refreshLayout.showLoading();
refreshLayout.setOnReloadingListener(new RefreshLayout.OnReloadingListener() {
@Override
public void onReload() {
getData();
}
});
getData();
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
finish();
}
});
}
private void getData(){
AccountManager.getInstance().getRecommendBook(String.valueOf(mBookId), "10");
AccountManager.getInstance().getBookDetail(String.valueOf(mBookId));
}
@OnClick({R.id.tv_add_book, R.id.tv_start_read})
public void onViewClicked(View view) {
switch (view.getId()) {
case R.id.tv_add_book:
//点击存储
if (isCollected) {
//放弃点击
BookRepository.getInstance().deleteCollBookInRx(mCollBookBean);
mTvAddBook.setText(getResources().getString(R.string.add_book));
isCollected = false;
} else {
if (mProgressDialog == null) {
mProgressDialog = new ProgressDialog(this);
mProgressDialog.setTitle("正在添加到书架中");
}
mProgressDialog.show();
AccountManager.getInstance().getBookArticle(String.valueOf(mBookId),"2","1","100000");
}
break;
case R.id.tv_start_read:
// if (mCollBookBean.getInclude_image()==Constant.HasImage.has){
// startActivityForResult(new Intent(this, NovelWebReadActivity.class)
// .putExtra(NovelReadActivity.EXTRA_IS_COLLECTED, isCollected)
// .putExtra(NovelReadActivity.EXTRA_COLL_BOOK, mCollBookBean), REQUEST_READ);
// }else {
startActivityForResult(new Intent(this, NovelReadActivity.class)
.putExtra(NovelReadActivity.EXTRA_IS_COLLECTED, isCollected)
.putExtra(NovelReadActivity.EXTRA_COLL_BOOK, mCollBookBean), REQUEST_READ);
// }
break;
}
}
@SuppressLint("SetTextI18n")
@Subscribe
public void getBookDetail(GetBookDetailEvent event) {
refreshLayout.showFinish();
if (event.isFail()) {
refreshLayout.showError();
} else {
BookDetailResp.BookBean bookBean = event.getResult().getBook();
GlideImageLoader.displayCornerImage(this, bookBean.getCover(), mIvBook);
mTvBookName.setText(bookBean.getTitle());
mTvBookAuthor.setText(bookBean.getAuthor() + " | ");
mTvBookLength.setText(getString(R.string.book_word, bookBean.getWords() / 10000));
if (event.getResult().getLast_article()!=null){
mTvNewTitle.setText(getString(R.string.new_chapter,event.getResult().getLast_article().getTitle()));
mTvUpdateTime.setText(DateUtli.dateConvert(event.getResult().getLast_article().getCreate_time(),0));
}
mTvHumanNum.setText(bookBean.getHot() + "");
mTvLoveLookNum.setText(bookBean.getLike());
mTvIntro.setText(bookBean.getDescription());
mCollBookBean = BookRepository.getInstance().getCollBook(String.valueOf(bookBean.getId()));
//判断是否收藏
if (mCollBookBean != null) {
isCollected = true;
mTvAddBook.setText(getResources().getString(R.string.already_add));
mTvStartRead.setText("继续阅读");
} else {
mCollBookBean = event.getResult().getCollBookBean();
}
}
}
@Subscribe
public void getRecommendBook(GetRecommendBookEvent event) {
if (event.isFail()) {
} else {
mList.clear();
mList.addAll(event.getResult().getBook());
mAdapter.notifyDataSetChanged();
}
}
@Override
protected void onResume() {
super.onResume();
EventManager.Companion.getInstance().registerSubscriber(this);
}
@Override
protected void onPause() {
super.onPause();
EventManager.Companion.getInstance().unregisterSubscriber(this);
}
@Subscribe
public void getArticle(BookArticleEvent event){
if (event.isFail()){
dismiss();
ToastUtils.showNormalToast(this,getString(R.string.net_error));
}else {
//存储收藏
boolean success = false;
if (mCollBookBean!=null){
success = mCollBookBean.saveOrUpdate("bookId=?",mCollBookBean.getId());
}
if (success){
List<BookChapterBean> bookChapterBean = event.getResult().getChapterBean();
for (int i = 0; i <bookChapterBean.size() ; i++) {
bookChapterBean.get(i).setCollBookBean(mCollBookBean);
}
LitePal.saveAllAsync(bookChapterBean).listen(success1 -> {
if (success1) {
if (mTvAddBook!=null) {
mTvAddBook.setText(getResources().getString(R.string.already_add));
}
isCollected = true;
}else {
LitePal.deleteAll(CollBookBean.class,"bookId =?",mCollBookBean.getId());
ToastUtils.showNormalToast(this,getString(R.string.net_error));
}
dismiss();
});
}else {
ToastUtils.showNormalToast(this,getString(R.string.net_error));
dismiss();
}
}
}
private void dismiss(){
if (mProgressDialog != null) {
mProgressDialog.dismiss();
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
//如果进入阅读页面收藏了,页面结束的时候,就需要返回改变收藏按钮
if (requestCode == REQUEST_READ) {
if (data == null) {
return;
}
isCollected = data.getBooleanExtra(RESULT_IS_COLLECTED, false);
if (isCollected) {
mTvAddBook.setText(getResources().getString(R.string.already_add));
mTvStartRead.setText("继续阅读");
}
}
}
@Override
protected void onDestroy() {
super.onDestroy();
EventManager.Companion.getInstance().postEvent(new UpdateBookEvent());
}
}

@ -0,0 +1,120 @@
package com.novel.read.activity;
import android.os.Bundle;
import androidx.appcompat.widget.Toolbar;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.mango.mangolib.event.EventManager;
import com.novel.read.R;
import com.novel.read.adapter.BookListAdapter;
import com.novel.read.base.NovelBaseActivity;
import com.novel.read.constants.Constant;
import com.novel.read.event.SearchListEvent;
import com.novel.read.http.AccountManager;
import com.novel.read.model.protocol.SearchResp;
import com.novel.read.widget.RefreshLayout;
import com.squareup.otto.Subscribe;
import java.util.ArrayList;
import java.util.List;
import butterknife.BindView;
import static com.novel.read.constants.Constant.COMMENT_SIZE;
public class NovelBookTypeListActivity extends NovelBaseActivity {
@BindView(R.id.toolbar)
Toolbar toolbar;
@BindView(R.id.rlv_type_list)
RecyclerView mRlvTypeList;
@BindView(R.id.refresh)
RefreshLayout refreshLayout;
private List<SearchResp.BookBean> mList;
private BookListAdapter mAdapter;
private String mCategoryId;
private String mTitle;
private int page = 1;
private int loadSize;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
protected int getLayoutId() {
return R.layout.activity_book_type_list;
}
@Override
protected void initView() {
EventManager.Companion.getInstance().registerSubscriber(this);
mCategoryId = getIntent().getStringExtra(Constant.Bundle.CategoryId);
mTitle = getIntent().getStringExtra(Constant.Bundle.mTitle);
mRlvTypeList.setLayoutManager(new LinearLayoutManager(this));
mList = new ArrayList<>();
mAdapter = new BookListAdapter(mList, mRlvTypeList);
mRlvTypeList.setAdapter(mAdapter);
mAdapter.setOnLoadMoreListener(() -> {
if (mAdapter.isLoadingMore()) {
} else {
if (loadSize >= COMMENT_SIZE) {
mAdapter.setLoadingMore(true);
mList.add(null);
mAdapter.notifyDataSetChanged();
page++;
getData();
}
}
});
}
@Override
protected void initData() {
refreshLayout.showLoading();
refreshLayout.setOnReloadingListener(this::getData);
getData();
toolbar.setTitle(mTitle);
toolbar.setNavigationOnClickListener(view -> finish());
}
private void getData() {
AccountManager.getInstance().getSearchBookList(mCategoryId, "", page);
}
@Subscribe
public void getSearchList(SearchListEvent event) {
refreshLayout.showFinish();
if (event.isFail()) {
refreshLayout.showError();
} else {
loadSize = event.getResult().getBook().size();
if (mAdapter.isLoadingMore()){
mList.remove(mList.size() - 1);
mList.addAll(event.getResult().getBook());
mAdapter.notifyDataSetChanged();
mAdapter.setLoadingMore(false);
}else {
mList.clear();
mList.addAll(event.getResult().getBook());
mAdapter.notifyDataSetChanged();
}
}
}
@Override
protected void onDestroy() {
super.onDestroy();
EventManager.Companion.getInstance().unregisterSubscriber(this);
}
}

@ -0,0 +1,258 @@
package com.novel.read.activity;
import android.annotation.SuppressLint;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.Log;
import android.view.KeyEvent;
import android.view.MenuItem;
import android.view.View;
import android.widget.FrameLayout;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentTransaction;
import com.google.android.material.bottomnavigation.BottomNavigationView;
import com.mango.mangolib.event.EventManager;
import com.novel.read.R;
import com.novel.read.base.NovelBaseActivity;
import com.novel.read.constants.Constant;
import com.novel.read.event.HideBottomBarEvent;
import com.novel.read.event.LoginEvent;
import com.novel.read.event.SwitchFragmentEvent;
import com.novel.read.event.UpdateBookEvent;
import com.novel.read.event.VersionEvent;
import com.novel.read.fragment.BookFragment;
import com.novel.read.fragment.MoreFragment;
import com.novel.read.fragment.RecommendFragment;
import com.novel.read.fragment.StackFragment;
import com.novel.read.http.AccountManager;
import com.novel.read.model.db.dbManage.BookRepository;
import com.novel.read.utlis.DateUtli;
import com.novel.read.utlis.SpUtil;
import com.novel.read.utlis.ToastUtil;
import com.novel.read.utlis.VersionUtil;
import com.novel.read.widget.dialog.AppraiseDialog;
import com.squareup.otto.Subscribe;
import java.util.List;
import butterknife.BindView;
public class NovelMainActivity extends NovelBaseActivity {
@BindView(R.id.fl_content)
FrameLayout flContent;
BottomNavigationView bottomBar;
private List<Fragment> mFragmentList;
private Fragment mCurrentFrag;
private BookFragment mMainFragment;
private RecommendFragment mRecommendFragment;
private StackFragment mStackFragment;
private MoreFragment mMoreFragment;
@SuppressLint("MissingSuperCall")
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
protected int getLayoutId() {
return R.layout.activity_main;
}
@Override
protected void initView() {
bottomBar = findViewById(R.id.bottom_bar);
mCurrentFrag = new Fragment();
mMainFragment = BookFragment.newInstance();
mRecommendFragment = RecommendFragment.newInstance();
mStackFragment = StackFragment.newInstance();
mMoreFragment = MoreFragment.newInstance();
//计算apk的启动次数
int count = SpUtil.getIntValue(Constant.InstallCount, 0);
SpUtil.setIntValue(Constant.InstallCount, count + 1);
Log.e("count", "count: " + count);
AccountManager.getInstance().login(this);
AccountManager.getInstance().checkVersion(VersionUtil.getPackageCode(this));
}
@Override
protected void initData() {
bottomBar.setOnNavigationItemSelectedListener(menuItem -> {
switch (menuItem.getItemId()) {
case R.id.tab_one:
switchFragment(mMainFragment);
return true;
case R.id.tab_two:
switchFragment(mRecommendFragment);
return true;
case R.id.tab_three:
switchFragment(mStackFragment);
return true;
case R.id.tab_four:
switchFragment(mMoreFragment);
return true;
}
return false;
});
if (BookRepository.getInstance().getCollBooks().size() > 0) {
switchFragment(mMainFragment);
} else {
bottomBar.setSelectedItemId(R.id.tab_two);
}
}
private void switchFragment(Fragment targetFragment) {
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
if (!targetFragment.isAdded()) {
//第一次使用switchFragment()时currentFragment为null,所以要判断一下
if (mCurrentFrag != null) {
transaction.hide(mCurrentFrag);
}
transaction.add(R.id.fl_content, targetFragment, targetFragment.getClass().getName());
} else {
transaction.hide(mCurrentFrag).show(targetFragment);
}
mCurrentFrag = targetFragment;
transaction.commit();
}
@Override
protected void onResume() {
super.onResume();
EventManager.Companion.getInstance().registerSubscriber(this);
if (SpUtil.getLongValue(Constant.InstallTime) == 0) {
SpUtil.setLongValue(Constant.InstallTime, System.currentTimeMillis());
} else {
if (DateUtli.checkInstallTime()&&!SpUtil.getBooleanValue(Constant.AppraiseShow)) {
SpUtil.setBooleanValue(Constant.AppraiseShow, true);
final AppraiseDialog dialog = new AppraiseDialog(this);
dialog.AppraiseDialog(view -> {
goToMarket(this, VersionUtil.getPackage(this));
dialog.dismiss();
});
dialog.show();
}
}
}
@Override
protected void onPause() {
super.onPause();
EventManager.Companion.getInstance().unregisterSubscriber(this);
}
public static void goToMarket(Context context, String packageName) {
Uri uri = Uri.parse("market://details?id=" + packageName);
Intent goToMarket = new Intent(Intent.ACTION_VIEW, uri);
final String GOOGLE_PLAY = "com.android.vending";//这里对应的是谷歌商店,跳转别的商店改成对应的即可
goToMarket.setPackage(GOOGLE_PLAY);//这里对应的是谷歌商店,跳转别的商店改成对应的即可
try {
context.startActivity(goToMarket);
} catch (ActivityNotFoundException e) {
if (goToMarket.resolveActivity(context.getPackageManager()) != null) { //有浏览器
context.startActivity(goToMarket);
}else {
ToastUtil.show(context,"未检测到Google应用商店");
}
e.printStackTrace();
}
}
@Subscribe
public void checkVersion(VersionEvent event) {
if (event.isFail()) {
} else {
if (TextUtils.isEmpty(event.getResult().getVersion().getSize())) {
return;
}
//版本大小不为空 去更新。
}
}
@Subscribe
public void login(LoginEvent event) {
if (event.isFail()) {
Log.e("NovelMainActivity", "login: " + event.getEr().getMsg());
} else {
SpUtil.setStringValue(Constant.Uid, String.valueOf(event.getResult().getUid()));
}
}
//记录用户首次点击返回键的时间
private long firstTime = 0;
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_UP) {
if (!isVisible(bottomBar)) {
bottomBar.setVisibility(View.VISIBLE);
mMainFragment.updateBook(new UpdateBookEvent());
} else {
long secondTime = System.currentTimeMillis();
if (secondTime - firstTime > 1000) {
firstTime = secondTime;
ToastUtil.show(NovelMainActivity.this, "再次点击退出界面");
} else {
finish();
}
}
return true;
}
return super.onKeyUp(keyCode, event);
}
@Subscribe
public void setBottomBar(HideBottomBarEvent event) {
if (event.getResult()) {
bottomBar.setVisibility(View.GONE);
} else {
bottomBar.setVisibility(View.VISIBLE);
}
}
@Override
protected void onDestroy() {
super.onDestroy();
}
public static void reStart(Context context) {
Intent intent = new Intent(context, NovelMainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
}
@Subscribe
public void toRecommendFragment(SwitchFragmentEvent event) {
// switchFragment(mRecommendFragment);
bottomBar.setSelectedItemId(R.id.tab_two);
}
}

@ -0,0 +1,131 @@
package com.novel.read.activity;
import android.os.Bundle;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.appcompat.widget.Toolbar;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.novel.read.R;
import com.novel.read.adapter.RankListAdapter;
import com.novel.read.base.NovelBaseActivity;
import com.novel.read.constants.Constant;
import com.novel.read.http.AccountManager;
import com.novel.read.model.protocol.RankByUpadateResp;
import java.util.ArrayList;
import java.util.List;
import butterknife.BindView;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import static com.novel.read.constants.Constant.COMMENT_SIZE;
/**
* 推荐fragment中点击更多跳转来的
*/
public class NovelRankListActivity extends NovelBaseActivity {
@BindView(R.id.toolbar)
Toolbar toolbar;
@BindView(R.id.rlv_book_list)
RecyclerView mRlvBookList;
private RankListAdapter mAdapter;
private List<RankByUpadateResp.BookBean> mList;
private int page = 1;
private int loadSize;
private String type;
private String sex;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
protected int getLayoutId() {
return R.layout.activity_rank_list;
}
@Override
protected void initView() {
mList = new ArrayList<>();
mRlvBookList.setLayoutManager(new LinearLayoutManager(this));
mAdapter = new RankListAdapter(mList, mRlvBookList);
mRlvBookList.setAdapter(mAdapter);
sex = getIntent().getStringExtra(Constant.Sex);
type = getIntent().getStringExtra(Constant.Type);
switch (type) {
case Constant.ListType.Human:
toolbar.setTitle(getString(R.string.popular_selection));
break;
case Constant.ListType.EditRecommend:
toolbar.setTitle(getString(R.string.edit_recommend));
break;
case Constant.ListType.HotSearch:
toolbar.setTitle(getString(R.string.hot_search));
break;
}
getData();
}
@Override
protected void initData() {
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
finish();
}
});
mAdapter.setOnLoadMoreListener(() -> {
if (mAdapter.isLoadingMore()) {
} else {
if (loadSize >= COMMENT_SIZE) {
mAdapter.setLoadingMore(true);
mList.add(null);
mAdapter.notifyDataSetChanged();
page++;
getData();
}
}
});
}
private void getData() {
AccountManager.getInstance().getRankList(type, sex, Constant.DateTyp.Week, String.valueOf(page), new RankCallBack());
}
private class RankCallBack implements Callback<RankByUpadateResp> {
@Override
public void onResponse(@NonNull Call<RankByUpadateResp> call, @NonNull Response<RankByUpadateResp> response) {
if (response.isSuccessful()) {
if (response.body() != null) {
loadSize = response.body().getBook().size();
if (mAdapter.isLoadingMore()) {
mList.remove(mList.size() - 1);
mList.addAll(response.body().getBook());
mAdapter.notifyDataSetChanged();
mAdapter.setLoadingMore(false);
} else {
mList.clear();
mList.addAll(response.body().getBook());
mAdapter.notifyDataSetChanged();
}
}
}
}
@Override
public void onFailure(@NonNull Call<RankByUpadateResp> call, @NonNull Throwable t) {
}
}
}

@ -0,0 +1,813 @@
package com.novel.read.activity;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.util.Log;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.View;
import android.view.WindowManager;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.SeekBar;
import android.widget.TextView;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.widget.LinearLayoutCompat;
import androidx.appcompat.widget.Toolbar;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.core.content.ContextCompat;
import androidx.core.view.GravityCompat;
import androidx.core.widget.ContentLoadingProgressBar;
import androidx.drawerlayout.widget.DrawerLayout;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.common_lib.base.utils.ToastUtils;
import com.google.android.material.appbar.AppBarLayout;
import com.mango.mangolib.event.EventManager;
import com.novel.read.BuildConfig;
import com.novel.read.R;
import com.novel.read.adapter.CategoryAdapter;
import com.novel.read.adapter.MarkAdapter;
import com.novel.read.base.MyApp;
import com.novel.read.base.NovelBaseActivity;
import com.novel.read.constants.Constant;
import com.novel.read.event.AddBookSignEvent;
import com.novel.read.event.BookArticleEvent;
import com.novel.read.event.DeleteBookSignEvent;
import com.novel.read.event.ErrorChapterEvent;
import com.novel.read.event.FinishChapterEvent;
import com.novel.read.event.GetBookSignEvent;
import com.novel.read.event.RxBus;
import com.novel.read.event.SetAdsBgEvent;
import com.novel.read.http.AccountManager;
import com.novel.read.model.db.BookChapterBean;
import com.novel.read.model.db.CollBookBean;
import com.novel.read.model.db.DownloadTaskBean;
import com.novel.read.model.db.dbManage.BookRepository;
import com.novel.read.model.protocol.MarkResp;
import com.novel.read.service.DownloadMessage;
import com.novel.read.service.DownloadService;
import com.novel.read.utlis.BrightnessUtils;
import com.novel.read.utlis.ScreenUtils;
import com.novel.read.utlis.SpUtil;
import com.novel.read.utlis.SystemBarUtils;
import com.novel.read.widget.dialog.ReadSettingDialog;
import com.novel.read.widget.page.PageLoader;
import com.novel.read.widget.page.PageView;
import com.novel.read.widget.page.ReadSettingManager;
import com.novel.read.widget.page.TxtChapter;
import com.squareup.otto.Subscribe;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import butterknife.BindView;
import static android.view.View.GONE;
import static android.view.View.LAYER_TYPE_SOFTWARE;
import static android.view.View.VISIBLE;
import static com.novel.read.constants.Constant.ResultCode.RESULT_IS_COLLECTED;
public class NovelReadActivity extends NovelBaseActivity implements DownloadService.OnDownloadListener {
@BindView(R.id.read_pv_page)
PageView mPvPage;
@BindView(R.id.read_abl_top_menu)
AppBarLayout mAblTopMenu;
@BindView(R.id.toolbar)
Toolbar toolbar;
@BindView(R.id.read_ll_bottom_menu)
LinearLayoutCompat mLlBottomMenu;
@BindView(R.id.read_dl_slide)
DrawerLayout mDlSlide;
@BindView(R.id.read_tv_category)
TextView mTvCategory;
@BindView(R.id.tv_light)
TextView mTvLight;
@BindView(R.id.read_setting_sb_brightness)
SeekBar mSbBrightness;
@BindView(R.id.tvBookReadMode)
TextView mTvNightMode;
@BindView(R.id.ll_light)
LinearLayoutCompat mLLight;
@BindView(R.id.tv_cache)
TextView mTvCache;
@BindView(R.id.tv_setting)
TextView mTvSetting;
@BindView(R.id.rlv_list)
ListView mLvCategory;
@BindView(R.id.tv_book_name)
TextView mTvBookName;
@BindView(R.id.read_tv_brief)
TextView mTvBrief;
@BindView(R.id.read_tv_community)
TextView mTvMark;
@BindView(R.id.rlReadMark)
ConstraintLayout rlReadMark;
@BindView(R.id.tvAddMark)
TextView mTvAddMark;
@BindView(R.id.tvClear)
TextView mTvClear;
@BindView(R.id.rlv_mark)
RecyclerView mRlvMark;
@BindView(R.id.ll_download)
LinearLayoutCompat mLlDownLoad;
@BindView(R.id.pb_loading)
ContentLoadingProgressBar loadingProgressBar;
@BindView(R.id.tv_progress)
TextView mTvProgress;
@BindView(R.id.cl_layout)
ConstraintLayout mClLayout;
@BindView(R.id.iv_guide)
ImageView mIvGuide;
private CategoryAdapter mCategoryAdapter;
private List<TxtChapter> mChapters = new ArrayList<>();
private TxtChapter mCurrentChapter; //当前章节
private int currentChapter = 0;
private MarkAdapter mMarkAdapter;
private List<MarkResp.SignBean> mMarks = new ArrayList<>();
private PageLoader mPageLoader;
private Animation mTopInAnim;
private Animation mTopOutAnim;
private Animation mBottomInAnim;
private Animation mBottomOutAnim;
private ReadSettingDialog mSettingDialog;
private boolean isCollected = false; // isFromSDCard
private boolean isNightMode = false;
private boolean isFullScreen = false;
private boolean isRegistered = false;
private CollBookBean mCollBook;
private String mBookId;
private static final String TAG = "NovelReadActivity";
public static final String EXTRA_COLL_BOOK = "extra_coll_book";
public static final String EXTRA_IS_COLLECTED = "extra_is_collected";
private static final int WHAT_CATEGORY = 1;
private static final int WHAT_CHAPTER = 2;
@SuppressLint("HandlerLeak")
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case WHAT_CATEGORY:
mLvCategory.setSelection(mPageLoader.getChapterPos());
break;
case WHAT_CHAPTER:
mPageLoader.openChapter();
break;
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
protected int getLayoutId() {
return R.layout.activity_read;
}
@Override
protected void initView() {
EventManager.Companion.getInstance().registerSubscriber(this);
mCollBook = (CollBookBean) getIntent().getSerializableExtra(EXTRA_COLL_BOOK);
isCollected = getIntent().getBooleanExtra(EXTRA_IS_COLLECTED, false);
mBookId = mCollBook.getId();
initService();
// 如果 API < 18 取消硬件加速
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) {
mPvPage.setLayerType(LAYER_TYPE_SOFTWARE, null);
}
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
//获取页面加载器
mPageLoader = mPvPage.getPageLoader(mCollBook);
mSettingDialog = new ReadSettingDialog(this, mPageLoader);
//禁止滑动展示DrawerLayout
mDlSlide.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
//侧边打开后,返回键能够起作用
mDlSlide.setFocusableInTouchMode(false);
//半透明化StatusBar
SystemBarUtils.transparentStatusBar(this);
//隐藏StatusBar
mPvPage.post(
this::hideSystemBar
);
mAblTopMenu.setPadding(0, ScreenUtils.getStatusBarHeight(), 0, 0);
mLlDownLoad.setPadding(0, ScreenUtils.getStatusBarHeight(), 0, ScreenUtils.dpToPx(15));
WindowManager.LayoutParams lp = getWindow().getAttributes();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
lp.layoutInDisplayCutoutMode = 1;
}
getWindow().setAttributes(lp);
//设置当前Activity的Brightness
if (ReadSettingManager.getInstance().isBrightnessAuto()) {
BrightnessUtils.setDefaultBrightness(this);
} else {
BrightnessUtils.setBrightness(this, ReadSettingManager.getInstance().getBrightness());
}
//注册广播
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED);
intentFilter.addAction(Intent.ACTION_TIME_TICK);
registerReceiver(mReceiver, intentFilter);
if (!SpUtil.getBooleanValue(Constant.BookGuide,false)){
mIvGuide.setVisibility(VISIBLE);
toggleMenu(false);
}
Log.e(TAG, "mBookId: " + mBookId);
if (isCollected) {
mPageLoader.getCollBook().setBookChapters(BookRepository.getInstance().getBookChaptersInRx(mBookId));
// 刷新章节列表
mPageLoader.refreshChapterList();
// 如果是网络小说并被标记更新的,则从网络下载目录
if (mCollBook.isUpdate() && !mCollBook.isLocal()) {
AccountManager.getInstance().getBookArticle(mBookId, "2", "1", "10000");
}
} else {
AccountManager.getInstance().getBookArticle(mBookId, "2", "1", "10000");
}
setAdsBg(new SetAdsBgEvent());
}
@Override
protected void initData() {
mTvBookName.setText(mCollBook.getTitle());
mCategoryAdapter = new CategoryAdapter();
mLvCategory.setAdapter(mCategoryAdapter);
mLvCategory.setFastScrollEnabled(true);
mRlvMark.setLayoutManager(new LinearLayoutManager(this));
mMarkAdapter = new MarkAdapter(mMarks);
mRlvMark.setAdapter(mMarkAdapter);
isNightMode = ReadSettingManager.getInstance().isNightMode();
//夜间模式按钮的状态
toggleNightMode();
isFullScreen = ReadSettingManager.getInstance().isFullScreen();
toolbar.setNavigationOnClickListener(view -> finish());
mSbBrightness.setProgress(ReadSettingManager.getInstance().getBrightness());
mPageLoader.setOnPageChangeListener(
new PageLoader.OnPageChangeListener() {
@Override
public void onChapterChange(int pos) {
mCategoryAdapter.setChapter(pos);
mCurrentChapter = mChapters.get(pos);
currentChapter = pos;
}
@Override
public void requestChapters(List<TxtChapter> requestChapters) {
AccountManager.getInstance().getBookArticleDetail(mBookId, requestChapters);
mHandler.sendEmptyMessage(WHAT_CATEGORY);
}
@Override
public void onCategoryFinish(List<TxtChapter> chapters) {
mChapters.clear();
mChapters.addAll(chapters);
mCategoryAdapter.refreshItems(mChapters);
}
@Override
public void onPageCountChange(int count) {
}
@Override
public void onPageChange(int pos) {
}
}
);
mPvPage.setTouchListener(new PageView.TouchListener() {
@Override
public boolean onTouch() {
return !hideReadMenu();
}
@Override
public void center() {
toggleMenu(true);
}
@Override
public void prePage() {
}
@Override
public void nextPage() {
}
@Override
public void cancel() {
}
});
mTvCategory.setOnClickListener(
(v) -> {
//移动到指定位置
if (mCategoryAdapter.getCount() > 0) {
mLvCategory.setSelection(mPageLoader.getChapterPos());
}
//切换菜单
toggleMenu(true);
//打开侧滑动栏
mDlSlide.openDrawer(GravityCompat.START);
}
);
mTvLight.setOnClickListener(view -> {
mLLight.setVisibility(GONE);
rlReadMark.setVisibility(GONE);
if (isVisible(mLLight)) {
mLLight.setVisibility(GONE);
} else {
mLLight.setVisibility(VISIBLE);
}
});
mTvSetting.setOnClickListener(view -> {
mLLight.setVisibility(GONE);
rlReadMark.setVisibility(GONE);
toggleMenu(false);
mSettingDialog.show();
});
mSbBrightness.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
int progress = seekBar.getProgress();
//设置当前 Activity 的亮度
BrightnessUtils.setBrightness(NovelReadActivity.this, progress);
//存储亮度的进度条
ReadSettingManager.getInstance().setBrightness(progress);
}
});
mTvNightMode.setOnClickListener(
(v) -> {
isNightMode = !isNightMode;
mPageLoader.setNightMode(isNightMode);
toggleNightMode();
}
);
mTvBrief.setOnClickListener(view -> {
Intent intent = new Intent(this, NovelBookDetailActivity.class);
intent.putExtra(Constant.Bundle.BookId, Integer.valueOf(mBookId));
startActivity(intent);
});
mTvMark.setOnClickListener(view -> {
if (isVisible(mLlBottomMenu)) {
if (isVisible(rlReadMark)) {
gone(rlReadMark);
} else {
gone(mLLight);
updateMark();
visible(rlReadMark);
}
}
});
mTvAddMark.setOnClickListener(view -> {
if (mCurrentChapter != null) {
mMarkAdapter.setEdit(false);
AccountManager.getInstance().addSign(mBookId, mCurrentChapter.getChapterId(), mCurrentChapter.getTitle());
}
});
mTvClear.setOnClickListener(view -> {
if (mMarkAdapter.getEdit()) {
String sign = mMarkAdapter.getSelectList();
if (!sign.equals("")) {
AccountManager.getInstance().deleteSign(sign);
}
mMarkAdapter.setEdit(false);
} else {
mMarkAdapter.setEdit(true);
}
});
mTvCache.setOnClickListener(view -> {
if (!isCollected) { //没有收藏 先收藏 然后弹框
//设置为已收藏
isCollected = true;
//设置阅读时间
mCollBook.setLastRead(String.valueOf(System.currentTimeMillis()));
BookRepository.getInstance().saveCollBookWithAsync(mCollBook);
}
showDownLoadDialog();
});
mLvCategory.setOnItemClickListener((parent, view, position, id) -> {
mDlSlide.closeDrawer(GravityCompat.START);
mPageLoader.skipToChapter(position);
});
mIvGuide.setOnClickListener(view -> {
mIvGuide.setVisibility(GONE);
SpUtil.setBooleanValue(Constant.BookGuide, true);
});
}
private void showDownLoadDialog() {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(getString(R.string.d_cache_num))
.setItems(new String[]{getString(R.string.d_cache_last_50), getString(R.string.d_cache_last_all), getString(R.string.d_cache_all)}, (dialog, which) -> {
switch (which) {
case 0: //50章
int last = currentChapter + 50;
if (last > mCollBook.getBookChapters().size()) {
downLoadCache(mCollBook.getBookChapters(), mCollBook.getBookChapters().size());
} else {
downLoadCache(mCollBook.getBookChapters(), last);
}
break;
case 1: //后面所有
List<BookChapterBean> lastBeans = new ArrayList<>();
for (int i = currentChapter; i < mCollBook.getBookChapters().size(); i++) {
lastBeans.add(mCollBook.getBookChapters().get(i));
}
downLoadCache(lastBeans, mCollBook.getBookChapters().size() - currentChapter);
break;
case 2: //所有
downLoadCache(mCollBook.getBookChapters(), mCollBook.getBookChapters().size());
break;
default:
break;
}
toggleMenu(true);
});
builder.show();
}
private void downLoadCache(List<BookChapterBean> beans, int size) {
DownloadTaskBean task = new DownloadTaskBean();
task.setTaskName(mCollBook.getTitle());
task.setBookId(mCollBook.getId());
task.setBookChapters(beans); //计算要缓存的章节
task.setCurrentChapter(currentChapter);
task.setLastChapter(size);
RxBus.getInstance().post(task);
startService(new Intent(this, DownloadService.class));
}
private void toggleNightMode() {
if (isNightMode) {
mTvNightMode.setText(getResources().getString(R.string.book_read_mode_day));
Drawable drawable = ContextCompat.getDrawable(this, R.drawable.ic_read_menu_moring);
mTvNightMode.setCompoundDrawablesWithIntrinsicBounds(null, drawable, null, null);
mClLayout.setBackgroundColor(getResources().getColor(R.color.nb_read_bg_night));
} else {
mTvNightMode.setText(getResources().getString(R.string.book_read_mode_day));
Drawable drawable = ContextCompat.getDrawable(this, R.drawable.ic_read_menu_night);
mTvNightMode.setCompoundDrawablesWithIntrinsicBounds(null, drawable, null, null);
mClLayout.setBackgroundColor(getResources().getColor(ReadSettingManager.getInstance().getPageStyle().getBgColor()));
}
}
/**
* 隐藏阅读界面的菜单显示
*
* @return 是否隐藏成功
*/
private boolean hideReadMenu() {
hideSystemBar();
if (mAblTopMenu.getVisibility() == VISIBLE) {
toggleMenu(true);
return true;
} else if (mSettingDialog.isShowing()) {
mSettingDialog.dismiss();
return true;
}
return false;
}
private void showSystemBar() {
//显示
SystemBarUtils.showUnStableStatusBar(this);
if (isFullScreen) {
SystemBarUtils.showUnStableNavBar(this);
}
}
private void hideSystemBar() {
//隐藏
SystemBarUtils.hideStableStatusBar(this);
if (isFullScreen) {
SystemBarUtils.hideStableNavBar(this);
}
}
/**
* 切换菜单栏的可视状态
* 默认是隐藏的
*/
private void toggleMenu(boolean hideStatusBar) {
initMenuAnim();
gone(mLLight, rlReadMark);
if (mAblTopMenu.getVisibility() == View.VISIBLE) {
//关闭
mAblTopMenu.startAnimation(mTopOutAnim);
mLlBottomMenu.startAnimation(mBottomOutAnim);
mAblTopMenu.setVisibility(GONE);
mLlBottomMenu.setVisibility(GONE);
if (hideStatusBar) {
hideSystemBar();
}
} else {
mAblTopMenu.setVisibility(View.VISIBLE);
mLlBottomMenu.setVisibility(View.VISIBLE);
mAblTopMenu.startAnimation(mTopInAnim);
mLlBottomMenu.startAnimation(mBottomInAnim);
showSystemBar();
}
}
//初始化菜单动画
private void initMenuAnim() {
if (mTopInAnim != null) return;
mTopInAnim = AnimationUtils.loadAnimation(this, R.anim.slide_top_in);
mTopOutAnim = AnimationUtils.loadAnimation(this, R.anim.slide_top_out);
mBottomInAnim = AnimationUtils.loadAnimation(this, R.anim.slide_bottom_in);
mBottomOutAnim = AnimationUtils.loadAnimation(this, R.anim.slide_bottom_out);
//退出的速度要快
mTopOutAnim.setDuration(200);
mBottomOutAnim.setDuration(200);
}
@Subscribe
public void getBookArticle(BookArticleEvent event) {
Log.e(TAG, "getBookArticle: ");
if (event.isFail()) {
} else {
List<BookChapterBean> chapterBeans = event.getResult().getChapterBean();
mPageLoader.getCollBook().setBookChapters(chapterBeans);
mPageLoader.refreshChapterList();
// 如果是目录更新的情况,那么就需要存储更新数据
if (mCollBook.isUpdate() && isCollected) {
BookRepository.getInstance().saveBookChaptersWithAsync(event.getResult().getChapterBean(), mCollBook);
}
}
}
@Subscribe
public void finishChapter(FinishChapterEvent event) {
if (mPageLoader.getPageStatus() == PageLoader.STATUS_LOADING) {
mHandler.sendEmptyMessage(WHAT_CHAPTER);
}
// 当完成章节的时候,刷新列表
mCategoryAdapter.notifyDataSetChanged();
}
@Subscribe
public void errorChapter(ErrorChapterEvent event) {
if (mPageLoader.getPageStatus() == PageLoader.STATUS_LOADING) {
mPageLoader.chapterError();
}
}
private void updateMark() {
AccountManager.getInstance().getSignList(mBookId);
}
@Subscribe
public void addSign(AddBookSignEvent event) {
if (event.isFail()) {
ToastUtils.showNormalToast(this, "添加书签失败,请检查网络设置");
} else {
ToastUtils.showNormalToast(this, "添加书签成功");
updateMark();
}
}
@Subscribe
public void deleteSigin(DeleteBookSignEvent event) {
if (event.isFail()) {
ToastUtils.showNormalToast(this, event.getEr().getMsg());
} else {
ToastUtils.showNormalToast(this, event.getResult().getMsg());
updateMark();
}
}
@Subscribe
public void getSignList(GetBookSignEvent event) {
if (event.isFail()) {
ToastUtils.showNormalToast(this, "获取书签失败,请检查网络设置");
} else {
mMarks.clear();
mMarks.addAll(event.getResult().getSign());
mMarkAdapter.notifyDataSetChanged();
}
}
// 接收电池信息和时间更新的广播
private BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (Objects.requireNonNull(intent.getAction()).equals(Intent.ACTION_BATTERY_CHANGED)) {
int level = intent.getIntExtra("level", 0);
mPageLoader.updateBattery(level);
}
// 监听分钟的变化
else if (intent.getAction().equals(Intent.ACTION_TIME_TICK)) {
mPageLoader.updateTime();
}
}
};
@Subscribe
public void setAdsBg(SetAdsBgEvent event) {
mClLayout.setBackgroundColor(getResources().getColor(ReadSettingManager.getInstance().getPageStyle().getBgColor()));
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
switch (keyCode) {
case KeyEvent.KEYCODE_VOLUME_UP:
return mPageLoader.skipToPrePage();
case KeyEvent.KEYCODE_VOLUME_DOWN:
return mPageLoader.skipToNextPage();
}
return super.onKeyDown(keyCode, event);
}
@Override
public void onBackPressed() {
if (mAblTopMenu.getVisibility() == View.VISIBLE) {
// 非全屏下才收缩,全屏下直接退出
if (!ReadSettingManager.getInstance().isFullScreen()) {
toggleMenu(true);
return;
}
} else if (mSettingDialog.isShowing()) {
mSettingDialog.dismiss();
return;
}else if (mDlSlide.isDrawerOpen(GravityCompat.START)) {
mDlSlide.closeDrawer(GravityCompat.START);
return;
}
Log.e(TAG, "onBackPressed: " + mCollBook.getBookChapters().isEmpty());
if (!mCollBook.isLocal() && !isCollected && !mCollBook.getBookChapters().isEmpty()) {
AlertDialog alertDialog = new AlertDialog.Builder(this)
.setTitle(getString(R.string.add_book))
.setMessage(getString(R.string.like_book))
.setPositiveButton(getString(R.string.sure), (dialog, which) -> {
//设置为已收藏
isCollected = true;
//设置阅读时间
mCollBook.setLastRead(String.valueOf(System.currentTimeMillis()));
BookRepository.getInstance().saveCollBookWithAsync(mCollBook);
exit();
})
.setNegativeButton(getString(R.string.cancel), (dialog, which) -> exit()).create();
alertDialog.show();
} else {
exit();
}
}
// 退出
private void exit() {
// 返回给BookDetail。
Intent result = new Intent();
result.putExtra(RESULT_IS_COLLECTED, isCollected);
setResult(Activity.RESULT_OK, result);
// 退出
super.onBackPressed();
}
@Override
protected void onPause() {
super.onPause();
if (isCollected) {
mPageLoader.saveRecord();
}
}
@Override
protected void onDestroy() {
super.onDestroy();
EventManager.Companion.getInstance().unregisterSubscriber(this);
mPageLoader.closeBook();
mPageLoader = null;
unbindService(mConn);
unregisterReceiver(mReceiver);
}
private DownloadService.IDownloadManager mService;
private ServiceConnection mConn;
private void initService() {
mConn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mService = (DownloadService.IDownloadManager) service;
mService.setOnDownloadListener(NovelReadActivity.this);
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
//绑定
bindService(new Intent(this, DownloadService.class), mConn, Service.BIND_AUTO_CREATE);
}
@Override
public void onDownloadChange(int pos, int status, String msg) {
// DownloadTaskBean bean = mDownloadAdapter.getItem(pos);
// bean.setStatus(status);
// if (DownloadTaskBean.STATUS_LOADING == status){
// bean.setCurrentChapter(Integer.valueOf(msg));
// }
// mDownloadAdapter.notifyItemChanged(pos);
Log.e(TAG, "onDownloadChange: " + pos + " " + status + " " + msg);
if (msg.equals(getString(R.string.download_success)) || msg.equals(getString(R.string.download_error))) {
//下载成功或失败后隐藏下载视图
if (mLlDownLoad != null) {
mLlDownLoad.setVisibility(GONE);
ToastUtils.showNormalToast(this, msg);
}
} else {
if (mLlDownLoad != null) {
mLlDownLoad.setVisibility(VISIBLE);
mTvProgress.setText(getString(R.string.download_loading,
mService.getDownloadTaskList().get(pos).getCurrentChapter(),
mService.getDownloadTaskList().get(pos).getLastChapter()));
loadingProgressBar.setMax(mService.getDownloadTaskList().get(pos).getLastChapter());
loadingProgressBar.setProgress(mService.getDownloadTaskList().get(pos).getCurrentChapter());
}
}
}
@Override
public void onDownloadResponse(int pos, int status) {
// DownloadTaskBean bean = mDownloadAdapter.getItem(pos);
// bean.setStatus(status);
// mDownloadAdapter.notifyItemChanged(pos);
Log.e(TAG, "onDownloadResponse: " + pos + " " + status);
}
@Subscribe
public void onDownLoadEvent(DownloadMessage message) {
ToastUtils.showNormalToast(this, message.message);
}
}

@ -0,0 +1,105 @@
package com.novel.read.activity;
import android.os.Bundle;
import android.view.View;
import androidx.appcompat.widget.Toolbar;
import androidx.fragment.app.Fragment;
import androidx.viewpager.widget.ViewPager;
import com.novel.read.R;
import com.novel.read.adapter.ViewPageAdapter;
import com.novel.read.base.NovelBaseActivity;
import com.novel.read.constants.Constant;
import com.novel.read.fragment.BookListFragment;
import com.novel.read.widget.VpTabLayout;
import java.util.ArrayList;
import java.util.List;
import butterknife.BindView;
public class NovelRecommendBookListActivity extends NovelBaseActivity {
@BindView(R.id.toolbar)
Toolbar toolbar;
@BindView(R.id.vp_tab)
VpTabLayout mVpTab;
@BindView(R.id.vp_recommend_type)
ViewPager mVpRecommendType;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
protected int getLayoutId() {
return R.layout.activity_recommend_book_list;
}
@Override
protected void initView() {
List<Fragment> fragmentList = new ArrayList<>();
String sex = getIntent().getStringExtra(Constant.Sex);
String type = getIntent().getStringExtra(Constant.Type);
if (type.equals(Constant.ListType.Human)){
toolbar.setTitle(getString(R.string.popular_selection));
}else if (type.equals(Constant.ListType.EditRecommend)){
toolbar.setTitle(getString(R.string.edit_recommend));
}else if (type.equals(Constant.ListType.HotSearch)){
toolbar.setTitle(getString(R.string.hot_search));
}
BookListFragment generalFragment = BookListFragment.newInstance(type, Constant.DateTyp.General, sex);
BookListFragment monthFragment = BookListFragment.newInstance(type, Constant.DateTyp.Month, sex);
BookListFragment weekFragment = BookListFragment.newInstance(type, Constant.DateTyp.Week, sex);
fragmentList.add(generalFragment);
fragmentList.add(monthFragment);
fragmentList.add(weekFragment);
ViewPageAdapter pageAdapter = new ViewPageAdapter(getSupportFragmentManager(), fragmentList);
mVpRecommendType.setAdapter(pageAdapter);
mVpRecommendType.setOffscreenPageLimit(2);
mVpRecommendType.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
mVpTab.setAnim(position, mVpRecommendType);
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
}
@Override
protected void initData() {
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
finish();
}
});
mVpTab.setOnTabBtnClickListener(new VpTabLayout.OnTabClickListener() {
@Override
public void onTabBtnClick(VpTabLayout.CommonTabBtn var1, View var2) {
switch (var1) {
case ONE:
mVpTab.setAnim(0, mVpRecommendType);
break;
case TWO:
mVpTab.setAnim(1, mVpRecommendType);
break;
case THREE:
mVpTab.setAnim(2, mVpRecommendType);
break;
}
}
});
}
}

@ -0,0 +1,295 @@
package com.novel.read.activity;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.view.KeyEvent;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.google.android.flexbox.AlignItems;
import com.google.android.flexbox.FlexDirection;
import com.google.android.flexbox.FlexWrap;
import com.google.android.flexbox.FlexboxLayoutManager;
import com.mango.mangolib.event.EventManager;
import com.novel.read.R;
import com.novel.read.adapter.HistoryAdapter;
import com.novel.read.adapter.HotAdapter;
import com.novel.read.adapter.SearchAdapter;
import com.novel.read.base.NovelBaseActivity;
import com.novel.read.event.HotSearchEvent;
import com.novel.read.event.SearchListEvent;
import com.novel.read.http.AccountManager;
import com.novel.read.model.db.SearchListTable;
import com.novel.read.model.protocol.SearchResp;
import com.novel.read.utlis.DialogUtils;
import com.novel.read.widget.HeadLayout;
import com.novel.read.widget.RefreshLayout;
import com.spreada.utils.chinese.ZHConverter;
import com.squareup.otto.Subscribe;
import org.litepal.LitePal;
import java.util.ArrayList;
import java.util.List;
import butterknife.BindView;
import butterknife.OnClick;
import static com.novel.read.constants.Constant.COMMENT_SIZE;
public class NovelSearchActivity extends NovelBaseActivity {
@BindView(R.id.tv_search)
EditText mTvSearch;
@BindView(R.id.tv_cancel)
TextView tvCancel;
@BindView(R.id.head_hot)
HeadLayout headHot;
@BindView(R.id.rlv_hot)
RecyclerView mRlvHot;
@BindView(R.id.head_history)
HeadLayout headHistory;
@BindView(R.id.rlv_history)
RecyclerView mRlvHistory;
@BindView(R.id.rlv_search)
RecyclerView mRlvSearch;
@BindView(R.id.refresh)
RefreshLayout refreshLayout;
private List<String> mHotList = new ArrayList<>();
private HotAdapter mHotAdapter;
private List<SearchListTable> mHisList = new ArrayList<>();
private HistoryAdapter mHisAdapter;
private List<SearchResp.BookBean> mSearchList = new ArrayList<>();
private SearchAdapter mSearchAdapter;
private int page = 1;
private int loadSize;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
protected int getLayoutId() {
return R.layout.activity_search;
}
@Override
protected void initView() {
EventManager.Companion.getInstance().registerSubscriber(this);
FlexboxLayoutManager manager = new FlexboxLayoutManager(this);
//设置主轴排列方式
manager.setFlexDirection(FlexDirection.ROW);
//设置是否换行
manager.setFlexWrap(FlexWrap.WRAP);
manager.setAlignItems(AlignItems.STRETCH);
mRlvHot.setLayoutManager(manager);
mHotAdapter = new HotAdapter(mHotList);
mRlvHot.setAdapter(mHotAdapter);
mHisList = LitePal.order("saveTime desc").limit(5).find(SearchListTable.class);
FlexboxLayoutManager manager2 = new FlexboxLayoutManager(this);
//设置主轴排列方式
manager2.setFlexDirection(FlexDirection.ROW);
//设置是否换行
manager2.setFlexWrap(FlexWrap.WRAP);
manager2.setAlignItems(AlignItems.STRETCH);
mHisAdapter = new HistoryAdapter(mHisList);
mRlvHistory.setLayoutManager(manager2);
mRlvHistory.setAdapter(mHisAdapter);
mRlvSearch.setLayoutManager(new LinearLayoutManager(this));
mSearchAdapter = new SearchAdapter(mSearchList, mRlvSearch);
mRlvSearch.setAdapter(mSearchAdapter);
mSearchAdapter.setOnLoadMoreListener(() -> {
if (mSearchAdapter.isLoadingMore()) {
} else {
if (loadSize >= COMMENT_SIZE) {
mSearchAdapter.setLoadingMore(true);
mSearchList.add(null);
mSearchAdapter.notifyDataSetChanged();
page++;
getData();
}
}
});
AccountManager.getInstance().getHotSearch();
}
private void getData() {
String str = convertCC(mTvSearch.getText().toString().trim());
AccountManager.getInstance().getSearchBookList("", str, page);
}
//繁簡轉換
public String convertCC(String input) {
if (TextUtils.isEmpty(input) || input.length() == 0)
return "";
return ZHConverter.getInstance(ZHConverter.SIMPLIFIED).convert(input);
}
@Override
protected void initData() {
//输入框
mTvSearch.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
if (s.toString().trim().equals("")) {
refreshLayout.setVisibility(View.GONE);
headHot.setVisibility(View.VISIBLE);
headHistory.setVisibility(View.VISIBLE);
mRlvHot.setVisibility(View.VISIBLE);
mRlvHistory.setVisibility(View.VISIBLE);
} else {
refreshLayout.setVisibility(View.VISIBLE);
headHot.setVisibility(View.GONE);
headHistory.setVisibility(View.GONE);
mRlvHot.setVisibility(View.GONE);
mRlvHistory.setVisibility(View.GONE);
refreshLayout.showLoading();
page = 1;
getData();
}
}
@Override
public void afterTextChanged(Editable s) {
}
});
//键盘的搜索
mTvSearch.setOnKeyListener((v, keyCode, event) -> {
//修改回车键功能
if (keyCode == KeyEvent.KEYCODE_ENTER) {
mSearchAdapter.setHolderType(true);
saveKey();
return true;
}
return false;
});
mHotAdapter.setOnItemClickListener((view, pos) -> {
mSearchAdapter.setHolderType(true);
refreshLayout.setVisibility(View.VISIBLE);
mTvSearch.setText(mHotList.get(pos));
saveKey();
});
mHisAdapter.setOnItemClickListener((view, pos) -> {
mSearchAdapter.setHolderType(true);
refreshLayout.setVisibility(View.VISIBLE);
mTvSearch.setText(mHisList.get(pos).getKey());
saveKey();
});
mSearchAdapter.setOnItemClickListener((view, pos) -> {
mSearchAdapter.setHolderType(true);
mTvSearch.setText(mSearchList.get(pos).getTitle());
saveKey();
});
headHistory.setOnClickListener(view -> DialogUtils.getInstance()
.showAlertDialog(NovelSearchActivity.this,
getString(R.string.clear_search), (dialogInterface, i) -> {
LitePal.deleteAll(SearchListTable.class);
mHisList.clear();
mHisList.addAll(LitePal.order("saveTime desc").limit(5).find(SearchListTable.class));
mHisAdapter.notifyDataSetChanged();
}));
refreshLayout.setOnReloadingListener(new RefreshLayout.OnReloadingListener() {
@Override
public void onReload() {
getData();
}
});
}
private void saveKey() {
if (mTvSearch.getText().toString().trim().equals("")) {
return;
}
SearchListTable searchListTable = new SearchListTable();
searchListTable.setKey(mTvSearch.getText().toString().trim());
searchListTable.setSaveTime(System.currentTimeMillis());
searchListTable.saveOrUpdate("key=?", mTvSearch.getText().toString().trim());
mHisList.clear();
mHisList.addAll(LitePal.order("saveTime desc").limit(5).find(SearchListTable.class));
mHisAdapter.notifyDataSetChanged();
}
@Override
public void onBackPressed() {
if (refreshLayout.getVisibility() == View.VISIBLE) {
mTvSearch.setText("");
mSearchAdapter.setHolderType(false);
page = 1;
} else {
super.onBackPressed();
overridePendingTransition(R.anim.message_fade_in, R.anim.message_fade_out);
}
}
@OnClick(R.id.tv_cancel)
public void onViewClicked() {
onBackPressed();
}
@Subscribe
public void getHotSearch(HotSearchEvent event) {
if (event.isFail()) {
} else {
mHotList.clear();
mHotList.addAll(event.getResult().getKey());
mHotAdapter.notifyDataSetChanged();
}
}
@Subscribe
public void getSearchList(SearchListEvent event) {
refreshLayout.showFinish();
if (event.isFail()) {
refreshLayout.showError();
} else {
loadSize = event.getResult().getBook().size();
if (mSearchAdapter.isLoadingMore()){
mSearchList.remove(mSearchList.size() - 1);
mSearchList.addAll(event.getResult().getBook());
mSearchAdapter.notifyDataSetChanged();
mSearchAdapter.setLoadingMore(false);
}else {
mSearchList.clear();
mSearchList.addAll(event.getResult().getBook());
mSearchAdapter.notifyDataSetChanged();
}
}
}
@Override
protected void onDestroy() {
super.onDestroy();
EventManager.Companion.getInstance().unregisterSubscriber(this);
}
}

@ -0,0 +1,174 @@
package com.novel.read.activity;
import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
import android.widget.TextView;
import androidx.appcompat.widget.Toolbar;
import com.allenliu.versionchecklib.v2.AllenVersionChecker;
import com.allenliu.versionchecklib.v2.builder.DownloadBuilder;
import com.allenliu.versionchecklib.v2.builder.UIData;
import com.mango.mangolib.event.EventManager;
import com.novel.read.R;
import com.novel.read.base.NovelBaseActivity;
import com.novel.read.constants.Constant;
import com.novel.read.event.UpdateBookEvent;
import com.novel.read.event.VersionEvent;
import com.novel.read.http.AccountManager;
import com.novel.read.model.protocol.VersionResp;
import com.novel.read.utlis.CleanCacheUtils;
import com.novel.read.utlis.LocalManageUtil;
import com.novel.read.utlis.SpUtil;
import com.novel.read.utlis.VersionUtil;
import com.squareup.otto.Subscribe;
import butterknife.BindView;
import butterknife.OnClick;
public class NovelSettingActivity extends NovelBaseActivity {
@BindView(R.id.toolbar)
Toolbar toolbar;
@BindView(R.id.tv_language)
TextView mTvLanguage;
@BindView(R.id.tv_cache_num)
TextView mTvCacheNum;
@BindView(R.id.tv_version)
TextView mTvVersion;
@BindView(R.id.tv_check)
TextView mTvCheck;
private VersionResp resp;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
protected int getLayoutId() {
return R.layout.activity_setting;
}
@Override
protected void initView() {
EventManager.Companion.getInstance().registerSubscriber(this);
}
@SuppressLint("SetTextI18n")
@Override
protected void initData() {
mTvLanguage.setText(getResources().getStringArray(R.array.setting_dialog_language_choice)[SpUtil.getIntValue(Constant.Language, 1)]);
mTvVersion.setText("V" + VersionUtil.getPackageName(this));
try {
final String cacheSize = CleanCacheUtils.getInstance().getTotalCacheSize(NovelSettingActivity.this);
mTvCacheNum.setText(cacheSize);
} catch (Exception e) {
e.printStackTrace();
}
toolbar.setNavigationOnClickListener(view -> finish());
AccountManager.getInstance().checkVersion(VersionUtil.getPackageCode(this));
}
@OnClick({R.id.ll_choose_language, R.id.ll_clear_cache, R.id.tv_check})
public void onViewClicked(View view) {
switch (view.getId()) {
case R.id.ll_choose_language:
showLanguageDialog();
break;
case R.id.ll_clear_cache:
//默认不勾选清空书架列表,防手抖!!
final boolean[] selected = {true, false};
new AlertDialog.Builder(this)
.setTitle(getString(R.string.clear_cache))
.setCancelable(true)
.setMultiChoiceItems(new String[]{getString(R.string.clear_cache), getString(R.string.clear_book)}, selected, (dialog, which, isChecked) -> selected[which] = isChecked)
.setPositiveButton(getString(R.string.sure), (dialog, which) -> {
new Thread(() -> {
CleanCacheUtils.getInstance().clearCache(selected[0], selected[1], NovelSettingActivity.this);
String cacheSize = "";
try {
cacheSize = CleanCacheUtils.getInstance().getTotalCacheSize(NovelSettingActivity.this);
} catch (Exception e) {
e.printStackTrace();
}
String finalCacheSize = cacheSize;
runOnUiThread(() -> {
EventManager.Companion.getInstance().postEvent(new UpdateBookEvent());
mTvCacheNum.setText(finalCacheSize);
});
}).start();
dialog.dismiss();
})
.setNegativeButton(getString(R.string.cancel), (dialog, which) -> dialog.dismiss())
.create().show();
break;
case R.id.tv_check:
//版本大小不为空 去更新。
updateApk(resp);
break;
}
}
public void showLanguageDialog() {
new AlertDialog.Builder(this)
.setTitle(getString(R.string.choose_language))
.setSingleChoiceItems(getResources().getStringArray(R.array.setting_dialog_language_choice),
SpUtil.getIntValue(Constant.Language, 1),
(dialog, which) -> {
String language = getResources().getStringArray(R.array.setting_dialog_language_choice)[which];
mTvLanguage.setText(language);
SpUtil.setIntValue(Constant.Language, which);
dialog.dismiss();
if (which == 0) {
selectLanguage(0);
} else {
selectLanguage(1);
}
})
.create().show();
}
private void selectLanguage(int select) {
LocalManageUtil.saveSelectLanguage(this, select);
NovelMainActivity.reStart(this);
}
@Subscribe
public void checkVersion(VersionEvent event){
if (event.isFail()){
}else {
if (TextUtils.isEmpty(event.getResult().getVersion().getSize())){
return;
}
resp = event.getResult();
mTvCheck.setVisibility(View.VISIBLE);
}
}
private void updateApk(VersionResp resp){
VersionResp.VersionBean versionBean = resp.getVersion();
DownloadBuilder builder = AllenVersionChecker
.getInstance()
.downloadOnly(UIData.create()
.setTitle(getString(R.string.new_version,versionBean.getVersion()))
.setContent(versionBean.getContent())
.setDownloadUrl(versionBean.getDownload())
);
builder.executeMission(this);
}
@Override
protected void onDestroy() {
super.onDestroy();
EventManager.Companion.getInstance().unregisterSubscriber(this);
}
}

@ -0,0 +1,102 @@
package com.novel.read.activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import com.novel.read.R;
import com.novel.read.utlis.PermissionUtil;
import com.novel.read.utlis.StatusBarUtil;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.Unbinder;
public class NovelSplashActivity extends AppCompatActivity implements PermissionUtil.PermissionCallBack {
@BindView(R.id.tvSkip)
TextView tvSkip;
private boolean flag = false;
private Runnable runnable;
protected PermissionUtil mPermissionUtil;
private static final int PERMISSION_CODE = 999;
private Unbinder unbinder;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
StatusBarUtil.setBarsStyle(this, R.color.colorPrimary, true);
setContentView(R.layout.activity_splash);
unbinder = ButterKnife.bind(this);
mPermissionUtil = PermissionUtil.getInstance();
mPermissionUtil.requestPermissions(this, PERMISSION_CODE, this);
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
mPermissionUtil.requestResult(this, permissions, grantResults, this);
}
private void init() {
runnable = new Runnable() {
@Override
public void run() {
goHome();
}
};
tvSkip.postDelayed(runnable, 2000);
tvSkip.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
goHome();
}
});
}
private synchronized void goHome() {
if (!flag) {
flag = true;
startActivity(new Intent(this, NovelMainActivity.class));
finish();
}
}
@Override
protected void onDestroy() {
super.onDestroy();
flag = true;
tvSkip.removeCallbacks(runnable);
unbinder.unbind();
}
@Override
protected void onResume() {
super.onResume();
}
@Override
protected void onPause() {
super.onPause();
}
@Override
public void onPermissionSuccess() {
init();
}
@Override
public void onPermissionReject(String strMessage) {
finish();
}
@Override
public void onPermissionFail() {
mPermissionUtil.requestPermissions(this, PERMISSION_CODE,this);
}
}

@ -0,0 +1,188 @@
package com.novel.read.adapter;
import android.content.Context;
import android.content.Intent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.novel.read.R;
import com.novel.read.activity.NovelReadActivity;
import com.novel.read.model.db.CollBookBean;
import com.novel.read.utlis.GlideImageLoader;
import java.util.ArrayList;
import java.util.List;
public class BookAdapter extends RecyclerView.Adapter {
private List<CollBookBean> mList;
private Context mContext;
private final int VALUE_ITEM = 100; //正常item
private final int EMPTY_ITEM = 101; //空白item
protected OnItemClickListener mClickListener;
private boolean mEdit;
public BookAdapter(List<CollBookBean> mList) {
this.mList = mList;
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
if (mContext == null) {
mContext = viewGroup.getContext();
}
View view;
if (i == VALUE_ITEM) {
view = LayoutInflater.from(mContext).inflate(R.layout.rlv_item_book, viewGroup, false);
return new ViewHolder(view);
} else if (i == EMPTY_ITEM) {
view = LayoutInflater.from(mContext).inflate(R.layout.rlv_empty_add_book, viewGroup, false);
return new EmptyHolder(view);
}
return null;
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int i) {
if (viewHolder instanceof ViewHolder) {
if (mEdit) { //编辑模式
((ViewHolder) viewHolder).mIvCheck.setSelected(mList.get(i).isSelect());
((ViewHolder) viewHolder).mIvCheck.setVisibility(View.VISIBLE);
((ViewHolder) viewHolder).mTvBookName.setText(mList.get(i).getTitle());
((ViewHolder) viewHolder).mTvBookAuthor.setText(mList.get(i).getAuthor());
if (mList.get(i).isUpdate()) {
((ViewHolder) viewHolder).mIvGeng.setVisibility(View.VISIBLE);
} else {
((ViewHolder) viewHolder).mIvGeng.setVisibility(View.GONE);
}
GlideImageLoader.displayCornerImage(mContext, mList.get(i).getCover(), ((ViewHolder) viewHolder).mIvBook);
viewHolder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
((ViewHolder) viewHolder).mIvCheck.setSelected(!mList.get(i).isSelect());
mList.get(i).setSelect(!mList.get(i).isSelect());
}
});
} else { //正常模式
((ViewHolder) viewHolder).mIvCheck.setVisibility(View.GONE);
if (mList.size() == i) { //最后的条目
((ViewHolder) viewHolder).mTvBookName.setText("");
((ViewHolder) viewHolder).mTvBookAuthor.setText("");
((ViewHolder) viewHolder).mIvBook.setImageResource(R.drawable.ic_book_add);
((ViewHolder) viewHolder).mIvGeng.setVisibility(View.GONE);
viewHolder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mClickListener.onItemClick(view, i);
}
});
} else {
((ViewHolder) viewHolder).mTvBookName.setText(mList.get(i).getTitle());
((ViewHolder) viewHolder).mTvBookAuthor.setText(mList.get(i).getAuthor());
if (mList.get(i).isUpdate()) {
((ViewHolder) viewHolder).mIvGeng.setVisibility(View.VISIBLE);
} else {
((ViewHolder) viewHolder).mIvGeng.setVisibility(View.GONE);
}
GlideImageLoader.displayCornerImage(mContext, mList.get(i).getCover(), ((ViewHolder) viewHolder).mIvBook);
viewHolder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(mContext, NovelReadActivity.class);
intent.putExtra(NovelReadActivity.EXTRA_IS_COLLECTED, true);
intent.putExtra(NovelReadActivity.EXTRA_COLL_BOOK, mList.get(i));
mContext.startActivity(intent);
}
});
}
}
} else if (viewHolder instanceof EmptyHolder) { //空条目
((EmptyHolder) viewHolder).mBtnAdd.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mClickListener.onItemClick(view, i);
}
});
}
}
@Override
public int getItemCount() {
if (mList.size() == 0) {
return 1;
}
if (mEdit) {
return mList.size();
} else {
return mList.size() + 1;
}
}
@Override
public int getItemViewType(int position) {
if (mList == null || mList.size() == 0) {
return EMPTY_ITEM;
} else {
return VALUE_ITEM;
}
}
static class ViewHolder extends RecyclerView.ViewHolder {
ImageView mIvBook;
TextView mTvBookName, mTvBookAuthor;
ImageView mIvCheck;
ImageView mIvGeng;
public ViewHolder(@NonNull View itemView) {
super(itemView);
mIvBook = itemView.findViewById(R.id.iv_book);
mTvBookName = itemView.findViewById(R.id.tv_book_name);
mTvBookAuthor = itemView.findViewById(R.id.tv_book_author);
mIvCheck = itemView.findViewById(R.id.iv_check);
mIvGeng = itemView.findViewById(R.id.iv_geng);
}
}
static class EmptyHolder extends RecyclerView.ViewHolder {
Button mBtnAdd;
public EmptyHolder(@NonNull View itemView) {
super(itemView);
mBtnAdd = itemView.findViewById(R.id.btn_add);
}
}
public void setOnItemClickListener(OnItemClickListener mListener) {
this.mClickListener = mListener;
}
public interface OnItemClickListener {
void onItemClick(View view, int pos);
}
public void setEdit(boolean edit) { //开启编辑模式
mEdit = edit;
notifyDataSetChanged();
}
public List<CollBookBean> getSelectList() {
List<CollBookBean> collBookBeans = new ArrayList<>();
for (int i = 0; i < mList.size(); i++) {
if (mList.get(i).isSelect()) {
collBookBeans.add(mList.get(i));
}
}
return collBookBeans;
}
}

@ -0,0 +1,146 @@
package com.novel.read.adapter;
import android.content.Context;
import android.content.Intent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.novel.read.R;
import com.novel.read.activity.NovelBookDetailActivity;
import com.novel.read.adapter.holder.EmptyHolder;
import com.novel.read.adapter.holder.MoreHolder;
import com.novel.read.constants.Constant;
import com.novel.read.inter.OnLoadMoreListener;
import com.novel.read.model.protocol.SearchResp;
import com.novel.read.utlis.GlideImageLoader;
import java.util.List;
import static com.novel.read.constants.Constant.COMMENT_SIZE;
public class BookListAdapter extends RecyclerView.Adapter {
private List<SearchResp.BookBean> mList;
private Context mContext;
private final int VALUE_ITEM = 100; //正常item
private final int EMPTY_ITEM = 101; //空白item
private final int PROCESS_ITEM = 102;
private boolean loadingMore;
private int lastVisibleItem, totalItemCount;
private int visibleThreshold = 1;
private OnLoadMoreListener mOnLoadMoreListener;
public BookListAdapter(List<SearchResp.BookBean> mList, RecyclerView recyclerView) {
this.mList = mList;
if (recyclerView.getLayoutManager() instanceof LinearLayoutManager) {
final LinearLayoutManager llMangager = (LinearLayoutManager) recyclerView.getLayoutManager();
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
totalItemCount = llMangager.getItemCount();
lastVisibleItem = llMangager.findLastVisibleItemPosition();
if (!loadingMore && totalItemCount == (lastVisibleItem + visibleThreshold) && totalItemCount >= (COMMENT_SIZE)) {
if (mOnLoadMoreListener != null) {
mOnLoadMoreListener.onLoadMore();
}
}
}
});
}
}
public void setLoadingMore(boolean loadingMore) {
this.loadingMore = loadingMore;
}
public boolean isLoadingMore() {
return loadingMore;
}
public void setOnLoadMoreListener(OnLoadMoreListener listener) {
this.mOnLoadMoreListener = listener;
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int viewType) {
if (mContext == null) {
mContext = viewGroup.getContext();
}
View view;
if (viewType == VALUE_ITEM) {
view = LayoutInflater.from(mContext).inflate(R.layout.rlv_item_book_list, viewGroup, false);
return new ViewHolder(view);
} else if (viewType == EMPTY_ITEM) {
view = LayoutInflater.from(mContext).inflate(R.layout.rlv_empty_view, viewGroup, false);
return new EmptyHolder(view);
}else if (viewType==PROCESS_ITEM){
view = LayoutInflater.from(mContext).inflate(R.layout.load_more_layout, viewGroup, false);
return new MoreHolder(view);
}
return null;
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, final int i) {
if (viewHolder instanceof ViewHolder){
SearchResp.BookBean bookBean = mList.get(i);
((ViewHolder) viewHolder).tvBookName.setText(bookBean.getTitle());
((ViewHolder) viewHolder).tvBookAuthor.setText(bookBean.getAuthor());
((ViewHolder) viewHolder).tvBookDescription.setText(bookBean.getDescription());
GlideImageLoader.displayCornerImage(mContext,bookBean.getCover(),((ViewHolder) viewHolder).ivBook);
viewHolder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent=new Intent(mContext, NovelBookDetailActivity.class);
intent.putExtra(Constant.Bundle.BookId, bookBean.getId());
mContext.startActivity(intent);
}
});
}
}
@Override
public int getItemCount() {
if (mList.size() == 0) {
return 1;
}
return mList.size();
}
@Override
public int getItemViewType(int position) {
if (mList == null || mList.size() == 0) {
return EMPTY_ITEM;
} else if (mList.get(position) == null) {
return PROCESS_ITEM;
} else {
return VALUE_ITEM;
}
}
static class ViewHolder extends RecyclerView.ViewHolder {
ImageView ivBook;
TextView tvBookName;
TextView tvBookAuthor;
TextView tvBookDescription;
public ViewHolder(@NonNull View itemView) {
super(itemView);
ivBook = itemView.findViewById(R.id.iv_book);
tvBookName = itemView.findViewById(R.id.tv_book_name);
tvBookAuthor = itemView.findViewById(R.id.tv_book_author);
tvBookDescription = itemView.findViewById(R.id.tv_book_description);
}
}
}

@ -0,0 +1,34 @@
package com.novel.read.adapter;
import android.view.View;
import android.view.ViewGroup;
import com.novel.read.adapter.holder.CategoryHolder;
import com.novel.read.widget.page.TxtChapter;
public class CategoryAdapter extends EasyAdapter<TxtChapter> {
private int currentSelected = 0;
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = super.getView(position, convertView, parent);
CategoryHolder holder = (CategoryHolder) view.getTag();
if (position == currentSelected){
holder.setSelectedChapter();
}
return view;
}
@Override
protected IViewHolder<TxtChapter> onCreateViewHolder(int viewType) {
return new CategoryHolder();
}
public void setChapter(int pos){
currentSelected = pos;
notifyDataSetChanged();
}
}

@ -0,0 +1,87 @@
package com.novel.read.adapter;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public abstract class EasyAdapter<T> extends BaseAdapter {
private List<T> mList = new ArrayList<T>();
@Override
public int getCount() {
return mList.size();
}
@Override
public T getItem(int position) {
return mList.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
public void addItem(T value){
mList.add(value);
notifyDataSetChanged();
}
public void addItem(int index,T value){
mList.add(index, value);
notifyDataSetChanged();
}
public void addItems(List<T> values){
mList.addAll(values);
notifyDataSetChanged();
}
public void removeItem(T value){
mList.remove(value);
notifyDataSetChanged();
}
public List<T> getItems(){
return Collections.unmodifiableList(mList);
}
public int getItemSize(){
return mList.size();
}
public void refreshItems(List<T> list){
mList.clear();
mList.addAll(list);
notifyDataSetChanged();
}
public void clear(){
mList.clear();
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
IViewHolder holder;
if (convertView == null){
holder = onCreateViewHolder(getItemViewType(position));
convertView = holder.createItemView(parent);
convertView.setTag(holder);
//初始化
holder.initView();
}
else {
holder = (IViewHolder)convertView.getTag();
}
//执行绑定
holder.onBind(getItem(position),position);
return convertView;
}
protected abstract IViewHolder<T> onCreateViewHolder(int viewType);
}

@ -0,0 +1,85 @@
package com.novel.read.adapter;
import android.content.Context;
import android.content.Intent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.novel.read.R;
import com.novel.read.activity.NovelBookDetailActivity;
import com.novel.read.constants.Constant;
import com.novel.read.model.protocol.RecommendListResp;
import com.novel.read.utlis.GlideImageLoader;
import java.util.List;
/**
* create by 赵利君 on 2019/6/19
* describe:
*/
public class EditRecommendAdapter extends RecyclerView.Adapter<EditRecommendAdapter.ViewHolder> {
private List<RecommendListResp.ListBean> mList;
private Context mContext;
public EditRecommendAdapter(List<RecommendListResp.ListBean> mList) {
this.mList = mList;
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
if (mContext==null){
mContext = viewGroup.getContext();
}
View view = LayoutInflater.from(mContext).inflate(R.layout.rlv_edit_recommend_item, viewGroup, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull ViewHolder viewHolder, int i) {
RecommendListResp.ListBean listBean = mList.get(i);
viewHolder.mTvBookName.setText(listBean.getBook_title());
viewHolder.mTvAuthor.setText(listBean.getAuthor());
viewHolder.mTvDescription.setText(listBean.getDescription());
viewHolder.mTvHumanNum.setText(listBean.getHot());
viewHolder.mTvLoveNum.setText(listBean.getLike());
GlideImageLoader.displayCornerImage(mContext,listBean.getBook_cover(),viewHolder.mIvBook);
viewHolder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent=new Intent(mContext, NovelBookDetailActivity.class);
intent.putExtra(Constant.Bundle.BookId, listBean.getBook_id());
mContext.startActivity(intent);
}
});
}
@Override
public int getItemCount() {
return mList.size();
}
static class ViewHolder extends RecyclerView.ViewHolder{
ImageView mIvBook;
TextView mTvBookName;
TextView mTvAuthor;
TextView mTvDescription;
TextView mTvHumanNum;
TextView mTvLoveNum;
public ViewHolder(@NonNull View itemView) {
super(itemView);
mIvBook = itemView.findViewById(R.id.iv_book);
mTvBookName = itemView.findViewById(R.id.tv_book_name);
mTvAuthor = itemView.findViewById(R.id.tv_book_author);
mTvDescription = itemView.findViewById(R.id.tv_book_description);
mTvHumanNum = itemView.findViewById(R.id.tv_human_num);
mTvLoveNum = itemView.findViewById(R.id.tv_love_look_num);
}
}
}

@ -0,0 +1,76 @@
package com.novel.read.adapter;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.novel.read.R;
import com.novel.read.model.db.SearchListTable;
import java.util.List;
/**
* create by 赵利君 on 2019/6/17
* describe:
*/
public class HistoryAdapter extends RecyclerView.Adapter<HistoryAdapter.ViewHolder> {
private List<SearchListTable> mList;
private Context mContext;
protected OnItemClickListener mClickListener;
public HistoryAdapter(List<SearchListTable> mList) {
this.mList = mList;
}
static class ViewHolder extends RecyclerView.ViewHolder{
TextView mTvLabel;
public ViewHolder(@NonNull View itemView) {
super(itemView);
mTvLabel = itemView.findViewById(R.id.tv_label);
}
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
if (mContext == null) {
mContext = viewGroup.getContext();
}
View view = LayoutInflater.from(mContext).inflate(R.layout.item_label, viewGroup, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull ViewHolder viewHolder, int i) {
viewHolder.mTvLabel.setText(mList.get(i).getKey());
viewHolder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mClickListener.onItemClick(view,i);
}
});
}
@Override
public int getItemCount() {
return mList.size();
}
public void setOnItemClickListener(OnItemClickListener mListener) {
this.mClickListener = mListener;
}
public interface OnItemClickListener{
void onItemClick(View view, int pos);
}
}

@ -0,0 +1,73 @@
package com.novel.read.adapter;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.novel.read.R;
import com.novel.read.constants.Constant;
import java.util.List;
/**
* create by 赵利君 on 2019/6/17
* describe:
*/
public class HotAdapter extends RecyclerView.Adapter<HotAdapter.ViewHolder> {
private List<String> mList;
private Context mContext;
protected OnItemClickListener mClickListener;
public HotAdapter(List<String> mList) {
this.mList = mList;
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
if (mContext==null){
mContext = viewGroup.getContext();
}
View view = LayoutInflater.from(mContext).inflate(R.layout.item_label, viewGroup, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull ViewHolder viewHolder, final int i) {
viewHolder.mTvLabel.setText(mList.get(i));
viewHolder.mTvLabel.setBackgroundColor(Constant.tagColors[i]);
viewHolder.itemView.setOnClickListener(view -> mClickListener.onItemClick(view,i));
}
@Override
public int getItemCount() {
if (mList.size()>8){
return 8;
}
return mList.size();
}
static class ViewHolder extends RecyclerView.ViewHolder{
TextView mTvLabel;
public ViewHolder(@NonNull View itemView) {
super(itemView);
mTvLabel = itemView.findViewById(R.id.tv_label);
}
}
public void setOnItemClickListener(OnItemClickListener mListener) {
this.mClickListener = mListener;
}
public interface OnItemClickListener{
void onItemClick(View view, int pos);
}
}

@ -0,0 +1,76 @@
package com.novel.read.adapter;
import android.content.Context;
import android.content.Intent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.novel.read.R;
import com.novel.read.activity.NovelBookDetailActivity;
import com.novel.read.constants.Constant;
import com.novel.read.model.protocol.RecommendListResp;
import com.novel.read.utlis.GlideImageLoader;
import java.util.List;
/**
* create by 赵利君 on 2019/6/19
* describe:
*/
public class HumanAdapter extends RecyclerView.Adapter<HumanAdapter.ViewHolder> {
private List<RecommendListResp.ListBean> mList;
private Context mContext;
public HumanAdapter(List<RecommendListResp.ListBean> mList) {
this.mList = mList;
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
if (mContext==null){
mContext = viewGroup.getContext();
}
View view = LayoutInflater.from(mContext).inflate(R.layout.rlv_human_item, viewGroup, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull ViewHolder viewHolder, int i) {
viewHolder.mTvBookName.setText(mList.get(i).getBook_title());
viewHolder.mTvAuthor.setText(mList.get(i).getAuthor());
GlideImageLoader.displayCornerImage(mContext,mList.get(i).getBook_cover(),viewHolder.mIvBook);
viewHolder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent=new Intent(mContext, NovelBookDetailActivity.class);
intent.putExtra(Constant.Bundle.BookId, mList.get(i).getBook_id());
mContext.startActivity(intent);
}
});
}
@Override
public int getItemCount() {
return mList.size();
}
static class ViewHolder extends RecyclerView.ViewHolder{
ImageView mIvBook;
TextView mTvBookName;
TextView mTvAuthor;
public ViewHolder(@NonNull View itemView) {
super(itemView);
mIvBook = itemView.findViewById(R.id.iv_book);
mTvBookName = itemView.findViewById(R.id.tv_book_name);
mTvAuthor = itemView.findViewById(R.id.tv_book_author);
}
}
}

@ -0,0 +1,15 @@
package com.novel.read.adapter;
import android.view.View;
import android.view.ViewGroup;
/**
* Created by newbiechen on 17-5-17.
*/
public interface IViewHolder<T> {
View createItemView(ViewGroup parent);
void initView();
void onBind(T data, int pos);
void onClick();
}

@ -0,0 +1,81 @@
package com.novel.read.adapter;
import android.content.Context;
import android.content.Intent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.novel.read.R;
import com.novel.read.activity.NovelBookDetailActivity;
import com.novel.read.constants.Constant;
import com.novel.read.model.protocol.RecommendBookResp;
import com.novel.read.utlis.GlideImageLoader;
import java.util.List;
/**
* 猜你喜欢adapter
*/
public class LoveLyAdapter extends RecyclerView.Adapter {
private List<RecommendBookResp.BookBean> mList;
private Context mContext;
public LoveLyAdapter(List<RecommendBookResp.BookBean> mList) {
this.mList = mList;
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
if (mContext==null){
mContext = viewGroup.getContext();
}
View view;
view = LayoutInflater.from(mContext).inflate(R.layout.rlv_item_lovely, viewGroup, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int i) {
if (viewHolder instanceof ViewHolder) {
RecommendBookResp.BookBean bookBean = mList.get(i);
GlideImageLoader.displayCornerImage(mContext, bookBean.getCover(), ((ViewHolder) viewHolder).mIvBook);
((ViewHolder) viewHolder).mTvBookName.setText(bookBean.getTitle());
((ViewHolder) viewHolder).mTvBookAuthor.setText(mContext.getString(R.string.author_zhu,bookBean.getAuthor()));
((ViewHolder) viewHolder).mTvDescription.setText(bookBean.getDescription());
viewHolder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent=new Intent(mContext, NovelBookDetailActivity.class);
intent.putExtra(Constant.Bundle.BookId, bookBean.getId());
mContext.startActivity(intent);
}
});
}
}
@Override
public int getItemCount() {
return mList.size();
}
static class ViewHolder extends RecyclerView.ViewHolder{
ImageView mIvBook;
TextView mTvBookName;
TextView mTvBookAuthor;
TextView mTvDescription;
public ViewHolder(@NonNull View itemView) {
super(itemView);
mIvBook = itemView.findViewById(R.id.iv_book);
mTvBookName = itemView.findViewById(R.id.tv_book_name);
mTvBookAuthor = itemView.findViewById(R.id.tv_book_author);
mTvDescription = itemView.findViewById(R.id.tv_book_description);
}
}
}

@ -0,0 +1,97 @@
package com.novel.read.adapter;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.novel.read.R;
import com.novel.read.model.protocol.MarkResp;
import java.util.List;
public class MarkAdapter extends RecyclerView.Adapter{
private Context mContext;
private List<MarkResp.SignBean> mList;
private boolean edit;
public MarkAdapter(List<MarkResp.SignBean> mList) {
this.mList = mList;
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
if (mContext==null){
mContext = viewGroup.getContext();
}
View view;
view = LayoutInflater.from(mContext).inflate(R.layout.rlv_item_mark, viewGroup, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int i) {
if (viewHolder instanceof ViewHolder){
if (edit){
((ViewHolder) viewHolder).mCheck.setVisibility(View.VISIBLE);
((ViewHolder) viewHolder).mCheck.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
mList.get(i).setEdit(b);
}
});
}else {
((ViewHolder) viewHolder).mCheck.setVisibility(View.GONE);
}
((ViewHolder) viewHolder).mTvMark.setText(mList.get(i).getContent());
((ViewHolder) viewHolder).mCheck.setChecked(mList.get(i).isEdit());
}
}
@Override
public int getItemCount() {
return mList.size();
}
static class ViewHolder extends RecyclerView.ViewHolder{
TextView mTvMark;
CheckBox mCheck;
public ViewHolder(@NonNull View itemView) {
super(itemView);
mTvMark = itemView.findViewById(R.id.tvMarkItem);
mCheck = itemView.findViewById(R.id.checkbox);
}
}
public void setEdit(boolean edit){
this.edit = edit;
notifyDataSetChanged();
}
public boolean getEdit(){
return edit;
}
public String getSelectList() {
StringBuilder signs = new StringBuilder();
for (int i = 0; i < mList.size(); i++) {
if (mList.get(i).isEdit()) {
if (signs.equals("")){
signs.append(mList.get(i).getId());
}else {
signs.append(",").append(mList.get(i).getId());
}
}
}
return String.valueOf(signs);
}
}

@ -0,0 +1,74 @@
package com.novel.read.adapter;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.mango.mangolib.event.EventManager;
import com.novel.read.R;
import com.novel.read.event.SetAdsBgEvent;
import com.novel.read.widget.page.PageLoader;
import com.novel.read.widget.page.PageStyle;
import java.util.List;
public class PageStyleAdapter extends RecyclerView.Adapter<PageStyleAdapter.PageHolder> {
private List<Drawable> mList;
private Context mContext;
private int currentChecked;
private PageLoader mPageLoader;
public PageStyleAdapter(List<Drawable> mList, PageLoader mPageLoader) {
this.mList = mList;
this.mPageLoader = mPageLoader;
}
@NonNull
@Override
public PageHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
if (mContext==null){
mContext = viewGroup.getContext();
}
View view = LayoutInflater.from(mContext).inflate(R.layout.item_read_bg, viewGroup, false);
return new PageHolder(view);
}
@Override
public void onBindViewHolder(@NonNull PageHolder pageHolder, int i) {
pageHolder.mReadBg.setBackground(mList.get(i));
pageHolder.mIvChecked.setVisibility(View.GONE);
if (currentChecked == i){
pageHolder.mIvChecked.setVisibility(View.VISIBLE);
}
pageHolder.itemView.setOnClickListener(view -> {
currentChecked = i;
notifyDataSetChanged();
mPageLoader.setPageStyle(PageStyle.values()[i]);
EventManager.Companion.getInstance().postEvent(new SetAdsBgEvent());
});
}
public void setPageStyleChecked(PageStyle pageStyle){
currentChecked = pageStyle.ordinal();
}
@Override
public int getItemCount() {
return mList.size();
}
static class PageHolder extends RecyclerView.ViewHolder{
private View mReadBg;
private ImageView mIvChecked;
public PageHolder(@NonNull View itemView) {
super(itemView);
mReadBg = itemView.findViewById(R.id.read_bg_view);
mIvChecked = itemView.findViewById(R.id.read_bg_iv_checked);
}
}
}

@ -0,0 +1,77 @@
package com.novel.read.adapter;
import android.content.Context;
import android.content.Intent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.novel.read.R;
import com.novel.read.activity.NovelBookDetailActivity;
import com.novel.read.constants.Constant;
import com.novel.read.model.protocol.RecommendListResp;
import com.novel.read.utlis.GlideImageLoader;
import java.util.List;
/**
* create by 赵利君 on 2019/6/20
* describe:
*/
public class RankAdapter extends RecyclerView.Adapter<RankAdapter.ViewHolder>{
private List<RecommendListResp.ListBean> mList;
private Context mContext;
public RankAdapter(List<RecommendListResp.ListBean> mList) {
this.mList = mList;
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
if (mContext==null){
mContext = viewGroup.getContext();
}
View view = LayoutInflater.from(mContext).inflate(R.layout.rlv_human_item, viewGroup, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull ViewHolder viewHolder, int i) {
viewHolder.mTvBookName.setText(mList.get(i).getBook_title());
viewHolder.mTvAuthor.setText(mList.get(i).getAuthor());
GlideImageLoader.displayCornerImage(mContext,mList.get(i).getBook_cover(),viewHolder.mIvBook);
viewHolder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent=new Intent(mContext, NovelBookDetailActivity.class);
intent.putExtra(Constant.Bundle.BookId, mList.get(i).getBook_id());
mContext.startActivity(intent);
}
});
}
@Override
public int getItemCount() {
return mList.size();
}
static class ViewHolder extends RecyclerView.ViewHolder{
ImageView mIvBook;
TextView mTvBookName;
TextView mTvAuthor;
public ViewHolder(@NonNull View itemView) {
super(itemView);
mIvBook = itemView.findViewById(R.id.iv_book);
mTvBookName = itemView.findViewById(R.id.tv_book_name);
mTvAuthor = itemView.findViewById(R.id.tv_book_author);
}
}
}

@ -0,0 +1,146 @@
package com.novel.read.adapter;
import android.content.Context;
import android.content.Intent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.novel.read.R;
import com.novel.read.activity.NovelBookDetailActivity;
import com.novel.read.adapter.holder.EmptyHolder;
import com.novel.read.adapter.holder.MoreHolder;
import com.novel.read.constants.Constant;
import com.novel.read.inter.OnLoadMoreListener;
import com.novel.read.model.protocol.RankByUpadateResp;
import com.novel.read.utlis.GlideImageLoader;
import java.util.List;
import static com.novel.read.constants.Constant.COMMENT_SIZE;
public class RankListAdapter extends RecyclerView.Adapter {
private List<RankByUpadateResp.BookBean> mList;
private Context mContext;
private final int VALUE_ITEM = 100; //正常item
private final int EMPTY_ITEM = 101; //空白item
private final int PROCESS_ITEM = 102;
private boolean loadingMore;
private int lastVisibleItem, totalItemCount;
private int visibleThreshold = 1;
private OnLoadMoreListener mOnLoadMoreListener;
public RankListAdapter(List<RankByUpadateResp.BookBean> mList,RecyclerView recyclerView) {
this.mList = mList;
if (recyclerView.getLayoutManager() instanceof LinearLayoutManager) {
final LinearLayoutManager llMangager = (LinearLayoutManager) recyclerView.getLayoutManager();
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
totalItemCount = llMangager.getItemCount();
lastVisibleItem = llMangager.findLastVisibleItemPosition();
if (!loadingMore && totalItemCount == (lastVisibleItem + visibleThreshold) && totalItemCount >= (COMMENT_SIZE)) {
if (mOnLoadMoreListener != null) {
mOnLoadMoreListener.onLoadMore();
}
}
}
});
}
}
public void setLoadingMore(boolean loadingMore) {
this.loadingMore = loadingMore;
}
public boolean isLoadingMore() {
return loadingMore;
}
public void setOnLoadMoreListener(OnLoadMoreListener listener) {
this.mOnLoadMoreListener = listener;
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int viewType) {
if (mContext == null) {
mContext = viewGroup.getContext();
}
View view;
if (viewType == VALUE_ITEM) {
view = LayoutInflater.from(mContext).inflate(R.layout.rlv_item_book_list, viewGroup, false);
return new ViewHolder(view);
} else if (viewType == EMPTY_ITEM) {
view = LayoutInflater.from(mContext).inflate(R.layout.rlv_empty_view, viewGroup, false);
return new EmptyHolder(view);
}else if (viewType==PROCESS_ITEM){
view = LayoutInflater.from(mContext).inflate(R.layout.load_more_layout, viewGroup, false);
return new MoreHolder(view);
}
return null;
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, final int i) {
if (viewHolder instanceof ViewHolder){
RankByUpadateResp.BookBean bookBean = mList.get(i);
((ViewHolder) viewHolder).tvBookName.setText(bookBean.getTitle());
((ViewHolder) viewHolder).tvBookAuthor.setText(bookBean.getAuthor());
((ViewHolder) viewHolder).tvBookDescription.setText(bookBean.getDescription());
GlideImageLoader.displayCornerImage(mContext,bookBean.getCover(),((ViewHolder) viewHolder).ivBook);
viewHolder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent=new Intent(mContext, NovelBookDetailActivity.class);
intent.putExtra(Constant.Bundle.BookId, bookBean.getId());
mContext.startActivity(intent);
}
});
}
}
@Override
public int getItemCount() {
if (mList.size() == 0) {
return 1;
}
return mList.size();
}
@Override
public int getItemViewType(int position) {
if (mList == null || mList.size() == 0) {
return EMPTY_ITEM;
} else if (mList.get(position) == null) {
return PROCESS_ITEM;
} else {
return VALUE_ITEM;
}
}
static class ViewHolder extends RecyclerView.ViewHolder {
ImageView ivBook;
TextView tvBookName;
TextView tvBookAuthor;
TextView tvBookDescription;
public ViewHolder(@NonNull View itemView) {
super(itemView);
ivBook = itemView.findViewById(R.id.iv_book);
tvBookName = itemView.findViewById(R.id.tv_book_name);
tvBookAuthor = itemView.findViewById(R.id.tv_book_author);
tvBookDescription = itemView.findViewById(R.id.tv_book_description);
}
}
}

@ -0,0 +1,183 @@
package com.novel.read.adapter;
import android.content.Context;
import android.content.Intent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.novel.read.R;
import com.novel.read.activity.NovelBookDetailActivity;
import com.novel.read.adapter.holder.EmptyHolder;
import com.novel.read.adapter.holder.MoreHolder;
import com.novel.read.constants.Constant;
import com.novel.read.inter.OnLoadMoreListener;
import com.novel.read.model.protocol.SearchResp;
import com.novel.read.utlis.GlideImageLoader;
import java.util.List;
import static com.novel.read.constants.Constant.COMMENT_SIZE;
public class SearchAdapter extends RecyclerView.Adapter {
private List<SearchResp.BookBean> mList;
private Context mContext;
private final int VALUE_ITEM = 100; //正常item
private final int BOOK_ITEM = 102; //书本item
private final int EMPTY_ITEM = 101; //空白item
private boolean book = false;
protected OnItemClickListener mClickListener;
private final int PROCESS_ITEM = 103; //加载更多
private boolean loadingMore;
private int lastVisibleItem, totalItemCount;
private int visibleThreshold = 1;
private OnLoadMoreListener mOnLoadMoreListener;
public SearchAdapter(List<SearchResp.BookBean> mList, RecyclerView recyclerView) {
this.mList = mList;
if (recyclerView.getLayoutManager() instanceof LinearLayoutManager) {
final LinearLayoutManager llMangager = (LinearLayoutManager) recyclerView.getLayoutManager();
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
totalItemCount = llMangager.getItemCount();
lastVisibleItem = llMangager.findLastVisibleItemPosition();
if (!loadingMore && totalItemCount == (lastVisibleItem + visibleThreshold) && totalItemCount >= (COMMENT_SIZE)) {
if (mOnLoadMoreListener != null) {
mOnLoadMoreListener.onLoadMore();
}
}
}
});
}
}
public void setLoadingMore(boolean loadingMore) {
this.loadingMore = loadingMore;
}
public boolean isLoadingMore() {
return loadingMore;
}
public void setOnLoadMoreListener(OnLoadMoreListener listener) {
this.mOnLoadMoreListener = listener;
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
if (mContext == null) {
mContext = viewGroup.getContext();
}
View view;
if (i == VALUE_ITEM) {
view = LayoutInflater.from(mContext).inflate(R.layout.rlv_item_search, viewGroup, false);
return new ViewHolder(view);
} else if (i == BOOK_ITEM) {
view = LayoutInflater.from(mContext).inflate(R.layout.rlv_item_book_list_search, viewGroup, false);
return new BookHolder(view);
} else if (i == EMPTY_ITEM) {
view = LayoutInflater.from(mContext).inflate(R.layout.rlv_empty_view, viewGroup, false);
return new EmptyHolder(view);
} else if (i == PROCESS_ITEM) {
view = LayoutInflater.from(mContext).inflate(R.layout.load_more_layout, viewGroup, false);
return new MoreHolder(view);
}
return null;
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int i) {
if (viewHolder instanceof ViewHolder) {
SearchResp.BookBean bookBean = mList.get(i);
((ViewHolder) viewHolder).mTvBookName.setText(bookBean.getTitle());
viewHolder.itemView.setOnClickListener(view -> mClickListener.onItemClick(view, i));
} else if (viewHolder instanceof BookHolder) {
SearchResp.BookBean bookBean = mList.get(i);
((BookHolder) viewHolder).tvBookName.setText(bookBean.getTitle());
((BookHolder) viewHolder).tvBookAuthor.setText(bookBean.getAuthor());
((BookHolder) viewHolder).tvBookDescription.setText(bookBean.getDescription());
GlideImageLoader.displayCornerImage(mContext, bookBean.getCover(), ((BookHolder) viewHolder).ivBook);
viewHolder.itemView.setOnClickListener(view -> {
Intent intent = new Intent(mContext, NovelBookDetailActivity.class);
intent.putExtra(Constant.Bundle.BookId, bookBean.getId());
mContext.startActivity(intent);
});
}
}
@Override
public int getItemCount() {
if (mList.size() == 0) {
return 1;
}
return mList.size();
}
@Override
public int getItemViewType(int position) {
if (mList == null || mList.size() == 0) {
return EMPTY_ITEM;
} else {
if (mList.get(position) == null) {
return PROCESS_ITEM;
}
if (book) {
return BOOK_ITEM;
} else {
return VALUE_ITEM;
}
}
}
public void setHolderType(boolean book) {
this.book = book;
notifyDataSetChanged();
}
static class ViewHolder extends RecyclerView.ViewHolder {
TextView mTvBookName;
public ViewHolder(@NonNull View itemView) {
super(itemView);
mTvBookName = itemView.findViewById(R.id.tv_book_name);
}
}
static class BookHolder extends RecyclerView.ViewHolder {
ImageView ivBook;
TextView tvBookName;
TextView tvBookAuthor;
TextView tvBookDescription;
public BookHolder(@NonNull View itemView) {
super(itemView);
ivBook = itemView.findViewById(R.id.iv_book);
tvBookName = itemView.findViewById(R.id.tv_book_name);
tvBookAuthor = itemView.findViewById(R.id.tv_book_author);
tvBookDescription = itemView.findViewById(R.id.tv_book_description);
}
}
public void setOnItemClickListener(OnItemClickListener mListener) {
this.mClickListener = mListener;
}
public interface OnItemClickListener {
void onItemClick(View view, int pos);
}
}

@ -0,0 +1,76 @@
package com.novel.read.adapter;
import android.content.Context;
import android.content.Intent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.novel.read.R;
import com.novel.read.activity.NovelBookTypeListActivity;
import com.novel.read.constants.Constant;
import com.novel.read.model.protocol.CategoryTypeResp;
import com.novel.read.utlis.GlideImageLoader;
import java.util.List;
public class StackAdapter extends RecyclerView.Adapter {
private List<CategoryTypeResp.CategoryBean> mList;
private Context mContext;
public StackAdapter(List<CategoryTypeResp.CategoryBean> mList) {
this.mList = mList;
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
if (mContext == null) {
mContext = viewGroup.getContext();
}
View view;
view = LayoutInflater.from(mContext).inflate(R.layout.rlv_item_book_type, viewGroup, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, final int i) {
if (viewHolder instanceof ViewHolder) {
String input = mList.get(i).getTitle();
String regex = "(.{2})";
input = input.replaceAll(regex, "$1\n");
((ViewHolder) viewHolder).mTvType.setText(input);
viewHolder.itemView.setOnClickListener(view -> {
Intent intent = new Intent(mContext, NovelBookTypeListActivity.class);
intent.putExtra(Constant.Bundle.CategoryId, String.valueOf(mList.get(i).getId()));
intent.putExtra(Constant.Bundle.mTitle, mList.get(i).getTitle());
mContext.startActivity(intent);
});
GlideImageLoader.displayCornerImage(mContext, mList.get(i).getCover(), ((ViewHolder) viewHolder).mIvType, R.drawable.ic_type_default);
}
}
@Override
public int getItemCount() {
return mList.size();
}
static class ViewHolder extends RecyclerView.ViewHolder {
ImageView mIvType;
TextView mTvType;
public ViewHolder(@NonNull View itemView) {
super(itemView);
mIvType = itemView.findViewById(R.id.iv_book);
mTvType = itemView.findViewById(R.id.tv_book_name);
}
}
}

@ -0,0 +1,38 @@
package com.novel.read.adapter;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public abstract class ViewHolderImpl<T> implements IViewHolder<T> {
private View view;
private Context context;
/****************************************************/
protected abstract int getItemLayoutId();
@Override
public View createItemView(ViewGroup parent) {
view = LayoutInflater.from(parent.getContext())
.inflate(getItemLayoutId(), parent, false);
context = parent.getContext();
return view;
}
protected <V extends View> V findById(int id){
return (V) view.findViewById(id);
}
protected Context getContext(){
return context;
}
protected View getItemView(){
return view;
}
@Override
public void onClick() {
}
}

@ -0,0 +1,31 @@
package com.novel.read.adapter;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentPagerAdapter;
import java.util.List;
/**
* Created by Administrator on 2017/2/24.
*/
public class ViewPageAdapter extends FragmentPagerAdapter {
private List<Fragment> fragmentList;
public ViewPageAdapter(FragmentManager fm, List<Fragment> fragmentList) {
super(fm);
this.fragmentList = fragmentList;
}
@Override
public Fragment getItem(int position) {
return fragmentList.get(position);
}
@Override
public int getCount() {
return fragmentList.size();
}
}

@ -0,0 +1,53 @@
package com.novel.read.adapter.holder;
import android.graphics.drawable.Drawable;
import android.widget.TextView;
import androidx.core.content.ContextCompat;
import com.novel.read.R;
import com.novel.read.adapter.ViewHolderImpl;
import com.novel.read.model.db.dbManage.BookManager;
import com.novel.read.utlis.StringUtils;
import com.novel.read.widget.page.TxtChapter;
import static com.novel.read.base.MyApp.getContext;
public class CategoryHolder extends ViewHolderImpl<TxtChapter> {
private TextView mTvChapter;
@Override
public void initView() {
mTvChapter = findById(R.id.category_tv_chapter);
}
@Override
public void onBind(TxtChapter value, int pos){
//首先判断是否该章已下载
Drawable drawable = null;
if (value.getBookId() != null && BookManager.isChapterCached(value.getBookId(),value.getTitle())){
drawable = ContextCompat.getDrawable(getContext(),R.drawable.selector_category_load);
}
else {
drawable = ContextCompat.getDrawable(getContext(), R.drawable.selector_category_unload);
}
mTvChapter.setSelected(false);
mTvChapter.setTextColor(ContextCompat.getColor(getContext(),R.color.colorTitle));
mTvChapter.setCompoundDrawablesWithIntrinsicBounds(drawable,null,null,null);
mTvChapter.setText(StringUtils.convertCC(value.getTitle(),getContext()));
}
@Override
protected int getItemLayoutId() {
return R.layout.rlv_item_category;
}
public void setSelectedChapter(){
mTvChapter.setTextColor(ContextCompat.getColor(getContext(),R.color.light_red));
mTvChapter.setSelected(true);
}
}

@ -0,0 +1,13 @@
package com.novel.read.adapter.holder;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
public class EmptyHolder extends RecyclerView.ViewHolder {
public EmptyHolder(@NonNull View itemView) {
super(itemView);
}
}

@ -0,0 +1,23 @@
package com.novel.read.adapter.holder;
import android.view.View;
import androidx.recyclerview.widget.RecyclerView;
/**
* @author: LiJun 390057892@qq.com
* @date: 2018/4/4 9:28
*/
public class MoreHolder extends RecyclerView.ViewHolder{
public MoreHolder(View itemView) {
super(itemView);
}
public void bindModule(){
}
}

@ -0,0 +1,26 @@
package com.novel.read.base;
import android.app.Service;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.disposables.Disposable;
public abstract class BaseService extends Service {
private CompositeDisposable mDisposable;
protected void addDisposable(Disposable disposable){
if (mDisposable == null){
mDisposable = new CompositeDisposable();
}
mDisposable.add(disposable);
}
@Override
public void onDestroy() {
super.onDestroy();
if (mDisposable != null){
mDisposable.dispose();
}
}
}

@ -0,0 +1,71 @@
package com.novel.read.base;
import android.app.Application;
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
import android.util.Log;
import androidx.appcompat.app.AppCompatDelegate;
import com.novel.read.constants.Constant;
import com.novel.read.service.DownloadService;
import com.novel.read.utlis.LocalManageUtil;
import com.novel.read.utlis.SpUtil;
import com.tencent.bugly.crashreport.CrashReport;
import org.litepal.LitePal;
/**
* create by 赵利君 on 2019/6/10
* describe:
*/
public class MyApp extends Application {
private static Context sInstance;
@Override
public void onCreate() {
super.onCreate();
sInstance = this;
LitePal.initialize(this);
setNight();
LocalManageUtil.setApplicationLanguage(this);
startService(new Intent(getContext(), DownloadService.class));
CrashReport.initCrashReport(getApplicationContext(), Constant.buglyId, false);
}
private void setNight() {
if (SpUtil.getBooleanValue(Constant.NIGHT, false)) {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
} else {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
}
}
public static Context getContext() {
return sInstance;
}
@Override
protected void attachBaseContext(Context base) {
SpUtil.init(base);
//保存系统选择语言
LocalManageUtil.saveSystemCurrentLanguage(base);
super.attachBaseContext(LocalManageUtil.setLocal(base));
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
//保存系统选择语言
LocalManageUtil.onConfigurationChanged(getApplicationContext());
}
}

@ -0,0 +1,139 @@
package com.novel.read.base;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.app.AppCompatDelegate;
import com.novel.read.R;
import com.novel.read.constants.Constant;
import com.novel.read.utlis.LocalManageUtil;
import com.novel.read.utlis.SpUtil;
import com.novel.read.utlis.StatusBarUtil;
import butterknife.ButterKnife;
import butterknife.Unbinder;
/**
* create by 赵利君 on 2019/6/10
* describe:
*/
public abstract class NovelBaseActivity extends AppCompatActivity {
Unbinder mBind;
private boolean mCheckNet = true;//是否检查网络连接
public boolean mNetworkChange = false;//获取网络是否连接
private boolean mNowMode;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
StatusBarUtil.setBarsStyle(this, R.color.colorPrimary, true);
mNowMode = SpUtil.getBooleanValue(Constant.NIGHT);
setContentView(getLayoutId());
mBind = ButterKnife.bind(this);
initView();
initData();
}
protected void setTheme() {
if (SpUtil.getBooleanValue(Constant.NIGHT) != mNowMode) {
if (SpUtil.getBooleanValue(Constant.NIGHT)) {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
} else {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
}
recreate();
}
}
protected abstract int getLayoutId();
protected abstract void initView();
protected abstract void initData();
@Override
protected void onDestroy() {
super.onDestroy();
mBind.unbind();
}
public void toActivity(Class<?> cls) {
Intent intent = new Intent(this, cls);
startActivity(intent);
}
public void toActivity(Class<?> toClsActivity, Bundle bundle) {
Intent intent = new Intent(this, toClsActivity);
if (bundle != null) {
intent.putExtras(bundle);
}
startActivity(intent);
}
public boolean isNetworkChange() {
return mNetworkChange;
}
public void setNetworkChange(boolean mNetworkChange) {
this.mNetworkChange = mNetworkChange;
}
public boolean getIsCheckNet() {
return mCheckNet;
}
public void setIsCheckNet(boolean checkNet) {
this.mCheckNet = checkNet;
}
@Override
protected void onResume() {
super.onResume();
setTheme();
}
@Override
protected void onPause() {
super.onPause();
}
protected void gone(final View... views) {
if (views != null && views.length > 0) {
for (View view : views) {
if (view != null) {
view.setVisibility(View.GONE);
}
}
}
}
protected void visible(final View... views) {
if (views != null && views.length > 0) {
for (View view : views) {
if (view != null) {
view.setVisibility(View.VISIBLE);
}
}
}
}
protected boolean isVisible(View view) {
return view.getVisibility() == View.VISIBLE;
}
@Override
protected void attachBaseContext(Context newBase) {
super.attachBaseContext(LocalManageUtil.setLocal(newBase));
}
}

@ -0,0 +1,59 @@
package com.novel.read.base;
import android.content.Intent;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import butterknife.ButterKnife;
import butterknife.Unbinder;
public abstract class NovelBaseFragment extends Fragment {
private Unbinder bind;
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View mContextView = inflater.inflate(getLayoutId(), container, false);
bind = ButterKnife.bind(this, mContextView);
initView();
initData();
return mContextView;
}
protected abstract int getLayoutId();
protected abstract void initView();
protected abstract void initData();
public void toActivity(Class<?> cls) {
Intent intent = new Intent(getActivity(), cls);
startActivity(intent);
}
public void toActivity(Class<?> toClsActivity, Bundle bundle) {
Intent intent = new Intent(getActivity(), toClsActivity);
if (bundle != null) {
intent.putExtras(bundle);
}
startActivity(intent);
}
@Override
public void onDestroyView() {
super.onDestroyView();
bind.unbind();
}
}

@ -0,0 +1,110 @@
/**
* Copyright 2016 JustWayward Team
* <p>
* 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.novel.read.constants;
import android.graphics.Color;
import com.novel.read.utlis.FileUtils;
import java.io.File;
public class Constant {
public static final String NIGHT = "NIGHT";
public static final String Language = "Language";
public static final String BookSort = "BookSort";
public static final String Uid = "Uid";
public static final String Sex = "Sex";
public static final String Type = "Type";
public static final String DateType = "DateType";
public static final String InstallTime = "InstallTime"; //apk的安装时间
public static final String InstallCount = "InstallCount"; //apk的打开次数
public static final String AppraiseShow = "AppraiseShow"; //评价弹框是否提示过
public static final String BookGuide = "BookGuide"; //图书引导是否提示过
public static final String FORMAT_BOOK_DATE = "yyyy-MM-dd HH:mm:ss";
public static final String FORMAT_TIME = "HH:mm";
public static final int COMMENT_SIZE = 10;
public static final String FeedBackEmail = "qdxs01@gmail.com";
/**
* 百度语音合成
*/
//壳001 免费小说
public static final String appId = "16826023";
public static final String appKey = "vEuU5gIWGwq5hivdTAaKz0P9";
public static final String secretKey = "FcWRYUIrOPyE7dy51qfYZmg8Y1ZyP1c4 ";
/**
* 腾讯bugly
*/
public static final String buglyId = "aec152f916";//壳包001
//BookCachePath (因为getCachePath引用了Context,所以必须是静态变量,不能够是静态常量)
public static String BOOK_CACHE_PATH = FileUtils.getCachePath() + File.separator
+ "book_cache" + File.separator;
public static final int[] tagColors = new int[]{
Color.parseColor("#90C5F0"),
Color.parseColor("#91CED5"),
Color.parseColor("#F88F55"),
Color.parseColor("#C0AFD0"),
Color.parseColor("#E78F8F"),
Color.parseColor("#67CCB7"),
Color.parseColor("#F6BC7E"),
Color.parseColor("#90C5F0"),
Color.parseColor("#91CED5"),
};
//榜单类型
public interface ListType {
String Human = "1";
String EditRecommend = "2";
String HotSearch = "3";
}
public interface GenderType {
String Man = "1";
String Woman = "2";
}
public interface DateTyp {
String General = "3";
String Month = "2";
String Week = "1";
}
public interface Bundle {
String CategoryId = "category_id";
String mTitle = "mTitle";
String BookId = "BookId";
}
public interface HasImage {
int has = 1;
}
public interface RequestCode {
int REQUEST_READ = 1;
}
public interface ResultCode {
String RESULT_IS_COLLECTED = "result_is_collected";
}
}

@ -0,0 +1,17 @@
package com.novel.read.event;
import com.mango.mangolib.event.BaseEvent;
import com.mango.mangolib.http.ErrorResponse;
/**
* create by 赵利君 on 2019/6/25
* describe:
*/
public class AddBookSignEvent extends BaseEvent<ErrorResponse> {
public AddBookSignEvent(ErrorResponse result) {
super(result);
}
public AddBookSignEvent() {
}
}

@ -0,0 +1,15 @@
package com.novel.read.event
import com.mango.mangolib.event.BaseEvent
import com.novel.read.model.protocol.BookArticleResp
/**
* create by 赵利君 on 2019/6/18
* describe:
*/
class BookArticleEvent : BaseEvent<BookArticleResp> {
constructor(result: BookArticleResp) : super(result) {}
constructor() {}
}

@ -0,0 +1,13 @@
package com.novel.read.event;
import com.mango.mangolib.event.BaseEvent;
import com.mango.mangolib.http.ErrorResponse;
public class DeleteBookSignEvent extends BaseEvent<ErrorResponse> {
public DeleteBookSignEvent(ErrorResponse result) {
super(result);
}
public DeleteBookSignEvent() {
}
}

@ -0,0 +1,17 @@
package com.novel.read.event;
import com.mango.mangolib.event.BaseEvent;
import com.novel.read.model.db.CollBookBean;
/**
* Created by newbiechen on 17-5-27.
*/
public class DeleteResponseEvent extends BaseEvent {
public boolean isDelete;
public CollBookBean collBook;
public DeleteResponseEvent(boolean isDelete, CollBookBean collBook){
this.isDelete = isDelete;
this.collBook = collBook;
}
}

@ -0,0 +1,16 @@
package com.novel.read.event;
import com.mango.mangolib.event.BaseEvent;
import com.novel.read.model.db.CollBookBean;
/**
* Created by newbiechen on 17-5-27.
*/
public class DeleteTaskEvent extends BaseEvent {
public CollBookBean collBook;
public DeleteTaskEvent(CollBookBean collBook){
this.collBook = collBook;
}
}

@ -0,0 +1,15 @@
package com.novel.read.event
import com.mango.mangolib.event.BaseEvent
import com.novel.read.model.protocol.RecommendListResp
/**
* create by 赵利君 on 2019/6/18
* describe:
*/
class EditEvent : BaseEvent<RecommendListResp> {
constructor(result: RecommendListResp) : super(result) {}
constructor() {}
}

@ -0,0 +1,12 @@
package com.novel.read.event;
import com.mango.mangolib.event.BaseEvent;
public class ErrorChapterEvent extends BaseEvent {
public ErrorChapterEvent(Object result) {
super(result);
}
public ErrorChapterEvent() {
}
}

@ -0,0 +1,12 @@
package com.novel.read.event;
import com.mango.mangolib.event.BaseEvent;
public class FinishChapterEvent extends BaseEvent {
public FinishChapterEvent(Object result) {
super(result);
}
public FinishChapterEvent() {
}
}

@ -0,0 +1,15 @@
package com.novel.read.event
import com.mango.mangolib.event.BaseEvent
import com.novel.read.model.protocol.BookDetailResp
/**
* create by 赵利君 on 2019/6/18
* describe:
*/
class GetBookDetailEvent : BaseEvent<BookDetailResp> {
constructor(result: BookDetailResp) : super(result) {}
constructor() {}
}

@ -0,0 +1,14 @@
package com.novel.read.event
import com.mango.mangolib.event.BaseEvent
import com.novel.read.model.protocol.MarkResp
/**
* create by 赵利君 on 2019/6/25
* describe:
*/
class GetBookSignEvent : BaseEvent<MarkResp> {
constructor(result: MarkResp) : super(result) {}
constructor() {}
}

@ -0,0 +1,18 @@
package com.novel.read.event;
import com.mango.mangolib.event.BaseEvent;
import com.novel.read.model.protocol.CategoryTypeResp;
/**
* create by 赵利君 on 2019/6/18
* describe:
*/
public class GetCategoryTypeEvent extends BaseEvent<CategoryTypeResp> {
public GetCategoryTypeEvent(CategoryTypeResp result) {
super(result);
}
public GetCategoryTypeEvent() {
}
}

@ -0,0 +1,15 @@
package com.novel.read.event
import com.mango.mangolib.event.BaseEvent
import com.novel.read.model.protocol.RecommendBookResp
/**
* create by 赵利君 on 2019/6/18
* describe:
*/
class GetRecommendBookEvent : BaseEvent<RecommendBookResp> {
constructor(result: RecommendBookResp) : super(result) {}
constructor() {}
}

@ -0,0 +1,12 @@
package com.novel.read.event;
import com.mango.mangolib.event.BaseEvent;
public class HideBottomBarEvent extends BaseEvent<Boolean> {
public HideBottomBarEvent(Boolean result) {
super(result);
}
public HideBottomBarEvent() {
}
}

@ -0,0 +1,18 @@
package com.novel.read.event;
import com.mango.mangolib.event.BaseEvent;
import com.novel.read.model.protocol.HotSearchResp;
/**
* create by 赵利君 on 2019/6/18
* describe:
*/
public class HotSearchEvent extends BaseEvent<HotSearchResp> {
public HotSearchEvent(HotSearchResp result) {
super(result);
}
public HotSearchEvent() {
}
}

@ -0,0 +1,16 @@
package com.novel.read.event
import com.mango.mangolib.event.BaseEvent
import com.novel.read.model.protocol.RecommendListResp
/**
* create by 赵利君 on 2019/6/18
* describe:
*/
class HumanEvent : BaseEvent<RecommendListResp> {
constructor(result: RecommendListResp) : super(result) {}
constructor() {}
}

@ -0,0 +1,10 @@
package com.novel.read.event
import com.mango.mangolib.event.BaseEvent
import com.novel.read.model.protocol.UidResp
class LoginEvent : BaseEvent<UidResp> {
constructor(result: UidResp) : super(result) {}
constructor() {}
}

@ -0,0 +1,18 @@
package com.novel.read.event;
import com.mango.mangolib.event.BaseEvent;
import com.novel.read.model.protocol.RankByUpadateResp;
/**
* create by 赵利君 on 2019/6/18
* describe:
*/
public class RankByUpdateEvent extends BaseEvent<RankByUpadateResp> {
public RankByUpdateEvent(RankByUpadateResp result) {
super(result);
}
public RankByUpdateEvent() {
}
}

@ -0,0 +1,6 @@
package com.novel.read.event;
import com.mango.mangolib.event.BaseEvent;
public class ReStartEvent extends BaseEvent {
}

@ -0,0 +1,15 @@
package com.novel.read.event
import com.mango.mangolib.event.BaseEvent
import com.novel.read.model.protocol.RecommendListResp
/**
* create by 赵利君 on 2019/6/18
* describe:
*/
class RecommendListEvent : BaseEvent<RecommendListResp> {
constructor(result: RecommendListResp) : super(result) {}
constructor() {}
}

@ -0,0 +1,79 @@
package com.novel.read.event;
import io.reactivex.Observable;
import io.reactivex.subjects.PublishSubject;
/**
* Created by newbiechen on 17-4-18.
* 原理:PublishSubject本身作为观察者和被观察者
*/
public class RxBus {
private static volatile RxBus sInstance;
private final PublishSubject<Object> mEventBus = PublishSubject.create();
public static RxBus getInstance(){
if (sInstance == null){
synchronized (RxBus.class){
if (sInstance == null){
sInstance = new RxBus();
}
}
}
return sInstance;
}
/**
* 发送事件(post event)
* @param event : event object(事件的内容)
*/
public void post(Object event){
mEventBus.onNext(event);
}
/**
*
* @param code
* @param event
*/
public void post(int code,Object event){
Message msg = new Message(code,event);
mEventBus.onNext(msg);
}
/**
* 返回Event的管理者,进行对事件的接受
* @return
*/
public Observable toObservable(){
return mEventBus;
}
/**
*
* @param cls :保证接受到制定的类型
* @param <T>
* @return
*/
public <T> Observable<T> toObservable(Class<T> cls){
//ofType起到过滤的作用,确定接受的类型
return mEventBus.ofType(cls);
}
public <T> Observable<T> toObservable(int code,Class<T> cls){
return mEventBus.ofType(Message.class)
.filter(msg -> msg.code == code && cls.isInstance(msg.event))
.map( msg -> (T)msg.event);
}
class Message{
int code;
Object event;
public Message(int code,Object event){
this.code = code;
this.event = event;
}
}
}

@ -0,0 +1,15 @@
package com.novel.read.event
import com.mango.mangolib.event.BaseEvent
import com.novel.read.model.protocol.SearchResp
/**
* create by 赵利君 on 2019/6/18
* describe:
*/
class SearchListEvent : BaseEvent<SearchResp> {
constructor(result: SearchResp) : super(result) {}
constructor() {}
}

@ -0,0 +1,8 @@
package com.novel.read.event;
import com.mango.mangolib.event.BaseEvent;
public class SetAdsBgEvent extends BaseEvent {
}

@ -0,0 +1,13 @@
package com.novel.read.event;
import com.mango.mangolib.event.BaseEvent;
public class SwitchFragmentEvent extends BaseEvent {
public SwitchFragmentEvent(Object result) {
super(result);
}
public SwitchFragmentEvent() {
}
}

@ -0,0 +1,13 @@
package com.novel.read.event;
import com.mango.mangolib.event.BaseEvent;
public class UpdateBookEvent extends BaseEvent<String> {
public UpdateBookEvent(String result) {
super(result);
}
public UpdateBookEvent() {
}
}

@ -0,0 +1,14 @@
package com.novel.read.event
import com.mango.mangolib.event.BaseEvent
import com.novel.read.model.protocol.VersionResp
/**
* create by 赵利君 on 2019/6/25
* describe:
*/
class VersionEvent : BaseEvent<VersionResp> {
constructor(result: VersionResp) : super(result) {}
constructor() {}
}

@ -0,0 +1,302 @@
package com.novel.read.fragment;
import android.app.AlertDialog;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatDelegate;
import androidx.appcompat.widget.Toolbar;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.mango.mangolib.event.EventManager;
import com.novel.read.R;
import com.novel.read.activity.NovelMainActivity;
import com.novel.read.activity.NovelSearchActivity;
import com.novel.read.adapter.BookAdapter;
import com.novel.read.base.NovelBaseFragment;
import com.novel.read.constants.Constant;
import com.novel.read.event.HideBottomBarEvent;
import com.novel.read.event.SwitchFragmentEvent;
import com.novel.read.event.UpdateBookEvent;
import com.novel.read.http.AccountManager;
import com.novel.read.model.db.BookRecordBean;
import com.novel.read.model.db.CollBookBean;
import com.novel.read.model.db.dbManage.BookRepository;
import com.novel.read.model.protocol.BookDetailResp;
import com.novel.read.utlis.LocalManageUtil;
import com.novel.read.utlis.RxUtils;
import com.novel.read.utlis.SpUtil;
import com.novel.read.utlis.ToastUtil;
import com.squareup.otto.Subscribe;
import org.litepal.LitePal;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import butterknife.BindView;
import io.reactivex.Single;
import io.reactivex.SingleObserver;
import io.reactivex.disposables.Disposable;
/**
* create by 赵利君 on 2019/10/14
* describe:
*/
public class BookFragment extends NovelBaseFragment {
@BindView(R.id.title)
Toolbar title;
@BindView(R.id.title_edit)
Toolbar titleEdit;
@BindView(R.id.rlv_book)
RecyclerView mRlvBook;
@BindView(R.id.tv_cancel)
TextView mTvCancel;
@BindView(R.id.tv_delete)
TextView mTvDelete;
private BookAdapter mAdapter;
private List<CollBookBean> mList = new ArrayList<>();
private boolean isInit = true;
public static BookFragment newInstance() {
Bundle args = new Bundle();
BookFragment fragment = new BookFragment();
fragment.setArguments(args);
return fragment;
}
@Override
protected int getLayoutId() {
return R.layout.fragment_book;
}
@Override
protected void initView() {
EventManager.Companion.getInstance().registerSubscriber(this);
mList.addAll(BookRepository.getInstance().getCollBooks());
GridLayoutManager gridLayoutManager = new GridLayoutManager(getActivity(), 3);
gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
@Override
public int getSpanSize(int i) {
if (mList == null || mList.size() == 0) {
return 3;
} else {
return 1;
}
}
});
mRlvBook.setLayoutManager(gridLayoutManager);
mAdapter = new BookAdapter(mList);
mRlvBook.setAdapter(mAdapter);
if (isInit) {
isInit = false;
update(mList);
}
}
@Override
protected void initData() {
title.inflateMenu(R.menu.title_book);
titleEdit.inflateMenu(R.menu.title_edit);
setOnClick();
}
private void setOnClick() {
title.setOnMenuItemClickListener(menuItem -> {
switch (menuItem.getItemId()) {
case R.id.action_search:
toActivity(NovelSearchActivity.class);
getActivity().overridePendingTransition(R.anim.message_fade_in, R.anim.message_fade_out);
break;
case R.id.edit_book:
if (mList == null || mList.size() == 0) { //没书的时候提醒用户不能编辑
ToastUtil.show(getActivity(), getString(R.string.please_add_book));
} else {
mAdapter.setEdit(true);
mTvCancel.setVisibility(View.VISIBLE);
mTvDelete.setVisibility(View.VISIBLE);
titleEdit.setVisibility(View.VISIBLE);
title.setVisibility(View.GONE);
EventManager.Companion.getInstance().postEvent(new HideBottomBarEvent(true));
}
break;
case R.id.book_sort:
showBookSortDialog();
break;
case R.id.menu2:
showLanguageDialog();
break;
case R.id.menu3:
if (SpUtil.getBooleanValue(Constant.NIGHT)) {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
SpUtil.setBooleanValue(Constant.NIGHT, false);
} else {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
SpUtil.setBooleanValue(Constant.NIGHT, true);
}
getActivity().recreate();
break;
}
return true;
});
titleEdit.setOnMenuItemClickListener(menuItem -> {
if (menuItem.getItemId() == R.id.action_edit) {
for (int i = 0; i < mList.size(); i++) {
mList.get(i).setSelect(true);
}
mAdapter.notifyDataSetChanged();
}
return true;
});
mTvCancel.setOnClickListener(view -> {
EventManager.Companion.getInstance().postEvent(new HideBottomBarEvent(false));
updateBook(new UpdateBookEvent());
});
mTvDelete.setOnClickListener(view -> {
List<CollBookBean> deleteList = mAdapter.getSelectList();
for (int i = 0; i < deleteList.size(); i++) {
if (deleteList.get(i).isSaved()) {
int count = deleteList.get(i).delete();
LitePal.deleteAll(BookRecordBean.class, "bookId=?", mList.get(i).getId());
Log.e("count", "setOnClick: " + count);
}
}
ToastUtil.show(getActivity(), getString(R.string.delete_success));
EventManager.Companion.getInstance().postEvent(new HideBottomBarEvent(false));
updateBook(new UpdateBookEvent());
});
mAdapter.setOnItemClickListener((view, pos) -> {
EventManager.Companion.getInstance().postEvent(new SwitchFragmentEvent());
});
}
private void showLanguageDialog() {
Log.e("showLanguageDialog", "showLanguageDialog: " + SpUtil.getIntValue(Constant.Language, 0));
new AlertDialog.Builder(getActivity())
.setTitle(getString(R.string.choose_language))
.setSingleChoiceItems(getResources().getStringArray(R.array.setting_dialog_language_choice), SpUtil.getIntValue(Constant.Language, 1),
(dialog, which) -> {
String language = getResources().getStringArray(R.array.setting_dialog_language_choice)[which];
SpUtil.setIntValue(Constant.Language, which);
dialog.dismiss();
if (which == 0) {
selectLanguage(0);
} else {
selectLanguage(1);
}
})
.create().show();
}
private void selectLanguage(int select) {
LocalManageUtil.saveSelectLanguage(getActivity(), select);
NovelMainActivity.reStart(getActivity());
}
private void showBookSortDialog() {
new AlertDialog.Builder(getActivity())
.setTitle(getString(R.string.choose_language))
.setSingleChoiceItems(getResources().getStringArray(R.array.setting_dialog_sort_choice),
SpUtil.getBooleanValue(Constant.BookSort, false) ? 0 : 1,
(dialog, which) -> {
if (which == 0) {
SpUtil.setBooleanValue(Constant.BookSort, true);
} else {
SpUtil.setBooleanValue(Constant.BookSort, false);
}
updateBook(new UpdateBookEvent());
dialog.dismiss();
})
.create().show();
}
@Override
public void onResume() {
super.onResume();
updateBook(new UpdateBookEvent());
}
@Subscribe
public void updateBook(UpdateBookEvent event) {
mTvCancel.setVisibility(View.GONE);
mTvDelete.setVisibility(View.GONE);
title.setVisibility(View.VISIBLE);
titleEdit.setVisibility(View.GONE);
mList.clear();
mList.addAll(BookRepository.getInstance().getCollBooks());
mAdapter.setEdit(false);
}
private void update(List<CollBookBean> collBookBeans) { //检测书籍更新
if (collBookBeans == null || collBookBeans.isEmpty()) return;
List<CollBookBean> collBooks = new ArrayList<>(collBookBeans);
List<Single<BookDetailResp>> observables = new ArrayList<>(collBooks.size());
Iterator<CollBookBean> it = collBooks.iterator();
while (it.hasNext()) {
CollBookBean collBook = it.next();
//删除本地文件
if (collBook.isLocal()) {
it.remove();
} else {
observables.add(AccountManager.getInstance().getBookDetails(collBook.getId()));
}
}
//zip可能不是一个好方法。
Single.zip(observables, objects -> {
List<CollBookBean> newCollBooks = new ArrayList<>(objects.length);
for (int i = 0; i < collBooks.size(); ++i) {
CollBookBean oldCollBook = collBooks.get(i);
CollBookBean newCollBook = ((BookDetailResp) objects[i]).getCollBookBean();
//如果是oldBook是update状态,或者newCollBook与oldBook章节数不同
if (oldCollBook.isUpdate() || !oldCollBook.getLastChapter().equals(newCollBook.getLastChapter())) {
newCollBook.setIsUpdate(true);
} else {
newCollBook.setIsUpdate(false);
}
newCollBook.setLastRead(oldCollBook.getLastRead());
newCollBooks.add(newCollBook);
//存储到数据库中
BookRepository.getInstance().saveCollBooks(newCollBooks);
}
return newCollBooks;
})
.compose(RxUtils::toSimpleSingle)
.subscribe(new SingleObserver<List<CollBookBean>>() {
@Override
public void onSubscribe(Disposable d) {
// addDisposable(d);
}
@Override
public void onSuccess(List<CollBookBean> value) {
//跟原先比较
mList.clear();
mList.addAll(BookRepository.getInstance().getCollBooks());
mAdapter.notifyDataSetChanged();
}
@Override
public void onError(Throwable e) {
}
});
}
@Override
public void onDestroy() {
super.onDestroy();
EventManager.Companion.getInstance().unregisterSubscriber(this);
}
}

@ -0,0 +1,119 @@
package com.novel.read.fragment;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.novel.read.R;
import com.novel.read.adapter.RankListAdapter;
import com.novel.read.base.NovelBaseFragment;
import com.novel.read.constants.Constant;
import com.novel.read.http.AccountManager;
import com.novel.read.model.protocol.RankByUpadateResp;
import java.util.ArrayList;
import java.util.List;
import butterknife.BindView;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import static com.novel.read.constants.Constant.COMMENT_SIZE;
public class BookListFragment extends NovelBaseFragment {
@BindView(R.id.rlv_book_list)
RecyclerView mRlvBookList;
private RankListAdapter mAdapter;
private List<RankByUpadateResp.BookBean> mList;
String sex;
String dateType;
String type;
private int page = 1;
private int loadSize;
public static BookListFragment newInstance(String type, String dateType, String sex) {
Bundle args = new Bundle();
args.putString(Constant.Sex, sex);
args.putString(Constant.DateType, dateType);
args.putString(Constant.Type, type);
BookListFragment fragment = new BookListFragment();
fragment.setArguments(args);
return fragment;
}
@Override
protected int getLayoutId() {
return R.layout.fragment_book_list;
}
@Override
protected void initView() {
mList = new ArrayList<>();
mRlvBookList.setLayoutManager(new LinearLayoutManager(getActivity()));
mAdapter = new RankListAdapter(mList,mRlvBookList);
mRlvBookList.setAdapter(mAdapter);
if (getArguments() != null) {
sex = getArguments().getString(Constant.Sex);
dateType = getArguments().getString(Constant.DateType);
type = getArguments().getString(Constant.Type);
}
}
@Override
protected void initData() {
getData();
mAdapter.setOnLoadMoreListener(() -> {
if (mAdapter.isLoadingMore()) {
} else {
if (loadSize >= COMMENT_SIZE) {
mAdapter.setLoadingMore(true);
mList.add(null);
mAdapter.notifyDataSetChanged();
page++;
getData();
}
}
});
}
private void getData() {
AccountManager.getInstance().getRankList(type, sex, dateType, String.valueOf(page), new RankCallBack());
}
private class RankCallBack implements Callback<RankByUpadateResp> {
@Override
public void onResponse(@NonNull Call<RankByUpadateResp> call, @NonNull Response<RankByUpadateResp> response) {
if (response.isSuccessful()) {
if (response.body() != null) {
loadSize = response.body().getBook().size();
if (mAdapter.isLoadingMore()) {
mList.remove(mList.size() - 1);
mList.addAll(response.body().getBook());
mAdapter.notifyDataSetChanged();
mAdapter.setLoadingMore(false);
}else {
mList.clear();
mList.addAll(response.body().getBook());
mAdapter.notifyDataSetChanged();
}
}
}
}
@Override
public void onFailure(@NonNull Call<RankByUpadateResp> call, @NonNull Throwable t) {
}
}
}

@ -0,0 +1,173 @@
package com.novel.read.fragment;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.mango.mangolib.event.EventManager;
import com.novel.read.R;
import com.novel.read.adapter.EditRecommendAdapter;
import com.novel.read.adapter.HumanAdapter;
import com.novel.read.adapter.RankAdapter;
import com.novel.read.base.NovelBaseFragment;
import com.novel.read.constants.Constant;
import com.novel.read.http.AccountManager;
import com.novel.read.model.protocol.RecommendListResp;
import com.novel.read.widget.HeadLayout;
import com.novel.read.widget.RefreshLayout;
import java.util.ArrayList;
import java.util.List;
import butterknife.BindView;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
public class ManFragment extends NovelBaseFragment {
@BindView(R.id.head_pop)
HeadLayout mHeadPop;
@BindView(R.id.rlv_pop)
RecyclerView mRlvPop;
@BindView(R.id.head_recommend)
HeadLayout mHeadRecommend;
@BindView(R.id.rlv_recommend)
RecyclerView mRlvRecommend;
@BindView(R.id.head_update)
HeadLayout headUpdate;
@BindView(R.id.rlv_update)
RecyclerView mRlvUpdate;
@BindView(R.id.swipe)
RefreshLayout refreshLayout;
private HumanAdapter mHumanAdapter;
private List<RecommendListResp.ListBean> mHumanList = new ArrayList<>();
private EditRecommendAdapter mEditAdapter;
private List<RecommendListResp.ListBean> mEditList = new ArrayList<>();
private RankAdapter mRankAdapter;
private List<RecommendListResp.ListBean> mRankList = new ArrayList<>();
public static ManFragment newInstance(String sex) {
Bundle args = new Bundle();
args.putString(Constant.Sex, sex);
ManFragment fragment = new ManFragment();
fragment.setArguments(args);
return fragment;
}
@Override
protected int getLayoutId() {
return R.layout.fragment_man;
}
@Override
protected void initView() {
EventManager.Companion.getInstance().registerSubscriber(this);
mRlvPop.setLayoutManager(new GridLayoutManager(getActivity(), 3));
mHumanAdapter = new HumanAdapter(mHumanList);
mRlvPop.setAdapter(mHumanAdapter);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getActivity());
linearLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
mRlvRecommend.setLayoutManager(linearLayoutManager);
mEditAdapter = new EditRecommendAdapter(mEditList);
mRlvRecommend.setAdapter(mEditAdapter);
mRlvUpdate.setLayoutManager(new GridLayoutManager(getActivity(), 3));
mRankAdapter = new RankAdapter(mRankList);
mRlvUpdate.setAdapter(mRankAdapter);
}
@Override
protected void initData() {
refreshLayout.showLoading();
getData();
refreshLayout.setOnReloadingListener(new RefreshLayout.OnReloadingListener() {
@Override
public void onReload() {
getData();
}
});
}
private void getData() {
AccountManager.getInstance().getRecommendList(Constant.ListType.Human, new HumanCallBack());
AccountManager.getInstance().getRecommendList(Constant.ListType.EditRecommend, new EditCallBack());
AccountManager.getInstance().getRecommendList(Constant.ListType.HotSearch, new HotSearchCallBack());
}
private class HumanCallBack implements Callback<RecommendListResp> {
@Override
public void onResponse(@NonNull Call<RecommendListResp> call, @NonNull Response<RecommendListResp> response) {
if (response.isSuccessful() && response.body() != null) {
mHumanList.clear();
mHumanList.addAll(response.body().getList());
mHumanAdapter.notifyDataSetChanged();
} else {
refreshLayout.showError();
}
}
@Override
public void onFailure(Call<RecommendListResp> call, Throwable t) {
}
}
private class EditCallBack implements Callback<RecommendListResp> {
@Override
public void onResponse(@NonNull Call<RecommendListResp> call, @NonNull Response<RecommendListResp> response) {
if (response.isSuccessful() && response.body() != null) {
mEditList.clear();
mEditList.addAll(response.body().getList());
mEditAdapter.notifyDataSetChanged();
} else {
refreshLayout.showError();
}
}
@Override
public void onFailure(Call<RecommendListResp> call, Throwable t) {
}
}
private class HotSearchCallBack implements Callback<RecommendListResp> {
@Override
public void onResponse(@NonNull Call<RecommendListResp> call, @NonNull Response<RecommendListResp> response) {
refreshLayout.showFinish();
if (response.isSuccessful() && response.body() != null) {
mRankList.clear();
mRankList.addAll(response.body().getList());
mRankAdapter.notifyDataSetChanged();
} else {
refreshLayout.showError();
}
}
@Override
public void onFailure(Call<RecommendListResp> call, Throwable t) {
}
}
@Override
public void onDestroy() {
super.onDestroy();
EventManager.Companion.getInstance().unregisterSubscriber(this);
}
}

@ -0,0 +1,152 @@
package com.novel.read.fragment;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
import androidx.appcompat.widget.Toolbar;
import com.mango.mangolib.event.EventManager;
import com.novel.read.R;
import com.novel.read.activity.NovelSearchActivity;
import com.novel.read.activity.NovelSettingActivity;
import com.novel.read.base.NovelBaseFragment;
import com.novel.read.constants.Constant;
import com.novel.read.event.ReStartEvent;
import com.novel.read.utlis.ToastUtil;
import com.novel.read.utlis.VersionUtil;
import com.novel.read.widget.dialog.AppraiseDialog;
import com.squareup.otto.Subscribe;
import butterknife.BindView;
import butterknife.OnClick;
/**
* create by 赵利君 on 2019/6/10
* describe:
*/
public class MoreFragment extends NovelBaseFragment {
@BindView(R.id.toolbar)
Toolbar title;
@BindView(R.id.tv_options)
TextView tvOptions;
@BindView(R.id.tv_appraise)
TextView tvAppraise;
@BindView(R.id.tv_setting)
TextView tvSetting;
public static MoreFragment newInstance() {
Bundle args = new Bundle();
MoreFragment fragment = new MoreFragment();
fragment.setArguments(args);
return fragment;
}
@Override
protected int getLayoutId() {
return R.layout.fragment_more;
}
@Override
protected void initView() {
EventManager.Companion.getInstance().registerSubscriber(this);
title.inflateMenu(R.menu.title_more);
}
@Override
protected void initData() {
title.setOnMenuItemClickListener(menuItem -> {
if (menuItem.getItemId() == R.id.action_search) {
toActivity(NovelSearchActivity.class);
getActivity().overridePendingTransition(R.anim.message_fade_in, R.anim.message_fade_out);
}
return true;
});
}
@OnClick({R.id.tv_options, R.id.tv_appraise, R.id.tv_setting})
public void onViewClicked(View view) {
switch (view.getId()) {
case R.id.tv_options:
feedback();
break;
case R.id.tv_appraise:
final AppraiseDialog dialog = new AppraiseDialog(getActivity());
dialog.AppraiseDialog(new View.OnClickListener() {
@Override
public void onClick(View view) {
goToMarket(getActivity(), VersionUtil.getPackage(getActivity()));
dialog.dismiss();
}
});
dialog.show();
break;
case R.id.tv_setting:
toActivity(NovelSettingActivity.class);
break;
}
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
}
public static void goToMarket(Context context, String packageName) {
Uri uri = Uri.parse("market://details?id=" + packageName);
Intent goToMarket = new Intent(Intent.ACTION_VIEW, uri);
final String GOOGLE_PLAY = "com.android.vending";//这里对应的是谷歌商店,跳转别的商店改成对应的即可
goToMarket.setPackage(GOOGLE_PLAY);//这里对应的是谷歌商店,跳转别的商店改成对应的即可
try {
context.startActivity(goToMarket);
} catch (ActivityNotFoundException e) {
if (goToMarket.resolveActivity(context.getPackageManager()) != null) { //有浏览器
context.startActivity(goToMarket);
}else {
ToastUtil.show(context,"未检测到Google应用商店");
}
e.printStackTrace();
}
}
public void feedback() {
Intent email = new Intent(Intent.ACTION_SEND);
//邮件发送类型:无附件,纯文本
email.setType("plain/text");
//邮件接收者(数组,可以是多位接收者)
String[] emailReceiver = new String[]{Constant.FeedBackEmail};
String emailTitle = getString(R.string.opinions);
String emailContent = "";
//设置邮件地址
email.putExtra(Intent.EXTRA_EMAIL, emailReceiver);
//设置邮件标题
email.putExtra(Intent.EXTRA_SUBJECT, emailTitle);
//设置发送的内容
email.putExtra(Intent.EXTRA_TEXT, emailContent);
//调用系统的邮件系统
startActivity(Intent.createChooser(email, "请选择邮件发送软件"));
}
@Override
public void onDestroy() {
super.onDestroy();
EventManager.Companion.getInstance().unregisterSubscriber(this);
}
@Subscribe
public void restart(ReStartEvent event) {
getActivity().recreate();
}
}

@ -0,0 +1,67 @@
package com.novel.read.fragment;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
import com.mango.mangolib.event.EventManager;
import com.novel.read.R;
import com.novel.read.activity.NovelSearchActivity;
import com.novel.read.base.NovelBaseFragment;
import butterknife.BindView;
import butterknife.OnClick;
/**
* create by 赵利君 on 2019/6/10
* describe:
*/
public class RecommendFragment extends NovelBaseFragment {
@BindView(R.id.tv_search)
TextView mTvSearch;
public static RecommendFragment newInstance() {
Bundle args = new Bundle();
RecommendFragment fragment = new RecommendFragment();
fragment.setArguments(args);
return fragment;
}
@Override
protected int getLayoutId() {
return R.layout.fragment_recommend;
}
@Override
protected void initView() {
EventManager.Companion.getInstance().registerSubscriber(this);
// List<Fragment> fragmentList = new ArrayList<>();
// ManFragment manFragment = ManFragment.newInstance(Constant.GenderType.Man);
// WomanFragment womanFragment = WomanFragment.newInstance(Constant.GenderType.Woman);
// fragmentList.add(manFragment);
// fragmentList.add(womanFragment);
}
@Override
protected void initData() {
}
@OnClick({ R.id.tv_search})
public void onViewClicked(View view) {
switch (view.getId()) {
case R.id.tv_search:
toActivity(NovelSearchActivity.class);
getActivity().overridePendingTransition(R.anim.message_fade_in, R.anim.message_fade_out);
break;
}
}
@Override
public void onDestroy() {
super.onDestroy();
EventManager.Companion.getInstance().unregisterSubscriber(this);
}
}

@ -0,0 +1,104 @@
package com.novel.read.fragment;
import android.os.Bundle;
import android.widget.TextView;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.mango.mangolib.event.EventManager;
import com.novel.read.R;
import com.novel.read.activity.NovelSearchActivity;
import com.novel.read.adapter.StackAdapter;
import com.novel.read.base.NovelBaseFragment;
import com.novel.read.event.GetCategoryTypeEvent;
import com.novel.read.http.AccountManager;
import com.novel.read.model.protocol.CategoryTypeResp;
import com.novel.read.widget.RefreshLayout;
import com.squareup.otto.Subscribe;
import java.util.ArrayList;
import java.util.List;
import butterknife.BindView;
import butterknife.OnClick;
/**
* create by 赵利君 on 2019/6/10
* describe:
*/
public class StackFragment extends NovelBaseFragment {
@BindView(R.id.tv_search)
TextView tvSearch;
@BindView(R.id.rlv_book_type)
RecyclerView mRlBookType;
private StackAdapter mAdapter;
@BindView(R.id.refresh)
RefreshLayout refreshLayout;
private List<CategoryTypeResp.CategoryBean> mList;
public static StackFragment newInstance() {
Bundle args = new Bundle();
StackFragment fragment = new StackFragment();
fragment.setArguments(args);
return fragment;
}
@Override
protected int getLayoutId() {
return R.layout.fragment_stack;
}
@Override
protected void initView() {
EventManager.Companion.getInstance().registerSubscriber(this);
mList = new ArrayList<>();
mRlBookType.setLayoutManager(new GridLayoutManager(getActivity(),2));
mAdapter = new StackAdapter(mList);
mRlBookType.setAdapter(mAdapter);
}
@Override
protected void initData() {
refreshLayout.showLoading();
getData();
refreshLayout.setOnReloadingListener(new RefreshLayout.OnReloadingListener() {
@Override
public void onReload() {
getData();
}
});
}
private void getData(){
AccountManager.getInstance().getCategoryType();
}
@OnClick(R.id.tv_search)
public void onViewClicked() {
toActivity(NovelSearchActivity.class);
getActivity().overridePendingTransition(R.anim.message_fade_in, R.anim.message_fade_out);
}
@Subscribe
public void getCategoryType(GetCategoryTypeEvent event){
refreshLayout.showFinish();
if (event.isFail()){
refreshLayout.showError();
}else {
mList.clear();
mList.addAll(event.getResult().getCategory());
mAdapter.notifyDataSetChanged();
}
}
@Override
public void onDestroy() {
super.onDestroy();
EventManager.Companion.getInstance().unregisterSubscriber(this);
}
}

@ -0,0 +1,209 @@
package com.novel.read.fragment;
import android.os.Bundle;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.mango.mangolib.event.EventManager;
import com.novel.read.R;
import com.novel.read.activity.NovelRankListActivity;
import com.novel.read.activity.NovelRecommendBookListActivity;
import com.novel.read.adapter.EditRecommendAdapter;
import com.novel.read.adapter.HumanAdapter;
import com.novel.read.adapter.RankAdapter;
import com.novel.read.base.NovelBaseFragment;
import com.novel.read.constants.Constant;
import com.novel.read.http.AccountManager;
import com.novel.read.model.protocol.RecommendListResp;
import com.novel.read.widget.HeadLayout;
import com.novel.read.widget.RefreshLayout;
import java.util.ArrayList;
import java.util.List;
import butterknife.BindView;
import butterknife.OnClick;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
public class WomanFragment extends NovelBaseFragment {
@BindView(R.id.head_pop)
HeadLayout mHeadPop;
@BindView(R.id.rlv_pop)
RecyclerView mRlvPop;
@BindView(R.id.head_recommend)
HeadLayout headRecommend;
@BindView(R.id.rlv_recommend)
RecyclerView mRlvRecommend;
@BindView(R.id.head_update)
HeadLayout headUpdate;
@BindView(R.id.rlv_update)
RecyclerView mRlvUpdate;
@BindView(R.id.swipe)
RefreshLayout refreshLayout;
private HumanAdapter mHumanAdapter;
private List<RecommendListResp.ListBean> mHumanList = new ArrayList<>();
private EditRecommendAdapter mEditAdapter;
private List<RecommendListResp.ListBean> mEditList = new ArrayList<>();
private RankAdapter mRankAdapter;
private List<RecommendListResp.ListBean> mRankList = new ArrayList<>();
public static WomanFragment newInstance(String sex) {
Bundle args = new Bundle();
args.putString(Constant.Sex, sex);
WomanFragment fragment = new WomanFragment();
fragment.setArguments(args);
return fragment;
}
@Override
protected int getLayoutId() {
return R.layout.fragment_man;
}
@Override
protected void initView() {
EventManager.Companion.getInstance().registerSubscriber(this);
mRlvPop.setLayoutManager(new GridLayoutManager(getActivity(), 3));
mHumanAdapter = new HumanAdapter(mHumanList);
mRlvPop.setAdapter(mHumanAdapter);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getActivity());
linearLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
mRlvRecommend.setLayoutManager(linearLayoutManager);
mEditAdapter = new EditRecommendAdapter(mEditList);
mRlvRecommend.setAdapter(mEditAdapter);
mRlvUpdate.setLayoutManager(new GridLayoutManager(getActivity(),3));
mRankAdapter = new RankAdapter(mRankList);
mRlvUpdate.setAdapter(mRankAdapter);
}
@Override
protected void initData() {
if (getArguments() != null) {
String sex = getArguments().getString(Constant.Sex);
refreshLayout.showLoading();
getData(sex);
refreshLayout.setOnReloadingListener(new RefreshLayout.OnReloadingListener() {
@Override
public void onReload() {
getData(sex);
}
});
}
mHeadPop.setRightTextClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
}
});
}
private void getData(String sex){
AccountManager.getInstance().getRecommendList(Constant.ListType.Human,new HumanCallBack());
AccountManager.getInstance().getRecommendList(Constant.ListType.EditRecommend,new EditCallBack());
AccountManager.getInstance().getRecommendList(Constant.ListType.HotSearch,new HotSearchCallBack());
// AccountManager.getInstance().getRankByUpdate(1,9,new HotSearchCallBack());
}
@OnClick({R.id.head_pop, R.id.head_recommend, R.id.head_update})
public void onViewClicked(View view) {
Bundle bundle = new Bundle();
bundle.putString(Constant.Sex,Constant.GenderType.Woman);
switch (view.getId()) {
case R.id.head_pop:
bundle.putString(Constant.Type,Constant.ListType.Human);
toActivity(NovelRecommendBookListActivity.class,bundle);
break;
case R.id.head_recommend:
bundle.putString(Constant.Type,Constant.ListType.EditRecommend);
toActivity(NovelRankListActivity.class,bundle);
break;
case R.id.head_update:
bundle.putString(Constant.Type,Constant.ListType.HotSearch);
toActivity(NovelRankListActivity.class,bundle);
break;
}
}
private class HumanCallBack implements Callback<RecommendListResp> {
@Override
public void onResponse(@NonNull Call<RecommendListResp> call, @NonNull Response<RecommendListResp> response) {
if (response.isSuccessful()&& response.body() != null){
mHumanList.clear();
mHumanList.addAll(response.body().getList());
mHumanAdapter.notifyDataSetChanged();
}else {
refreshLayout.showError();
}
}
@Override
public void onFailure(Call<RecommendListResp> call, Throwable t) {
}
}
private class EditCallBack implements Callback<RecommendListResp> {
@Override
public void onResponse(@NonNull Call<RecommendListResp> call, @NonNull Response<RecommendListResp> response) {
if (response.isSuccessful()&& response.body() != null){
mEditList.clear();
mEditList.addAll(response.body().getList());
mEditAdapter.notifyDataSetChanged();
}else {
refreshLayout.showError();
}
}
@Override
public void onFailure(Call<RecommendListResp> call, Throwable t) {
}
}
private class HotSearchCallBack implements Callback<RecommendListResp> {
@Override
public void onResponse(@NonNull Call<RecommendListResp> call, @NonNull Response<RecommendListResp> response) {
refreshLayout.showFinish();
if (response.isSuccessful()&&response.body()!=null){
mRankList.clear();
mRankList.addAll(response.body().getList());
mRankAdapter.notifyDataSetChanged();
}else {
refreshLayout.showError();
}
}
@Override
public void onFailure(Call<RecommendListResp> call, Throwable t) {
}
}
@Override
public void onDestroy() {
super.onDestroy();
EventManager.Companion.getInstance().unregisterSubscriber(this);
}
}

@ -0,0 +1,315 @@
package com.novel.read.http;
import android.content.Context;
import android.text.TextUtils;
import android.util.Log;
import com.mango.mangolib.event.EventManager;
import com.mango.mangolib.http.ErrorResponse;
import com.mango.mangolib.http.MyRequestType;
import com.mango.mangolib.http.ServiceCallback;
import com.novel.read.constants.Constant;
import com.novel.read.event.AddBookSignEvent;
import com.novel.read.event.BookArticleEvent;
import com.novel.read.event.DeleteBookSignEvent;
import com.novel.read.event.ErrorChapterEvent;
import com.novel.read.event.FinishChapterEvent;
import com.novel.read.event.GetBookDetailEvent;
import com.novel.read.event.GetBookSignEvent;
import com.novel.read.event.GetCategoryTypeEvent;
import com.novel.read.event.GetRecommendBookEvent;
import com.novel.read.event.HotSearchEvent;
import com.novel.read.event.LoginEvent;
import com.novel.read.event.SearchListEvent;
import com.novel.read.event.VersionEvent;
import com.novel.read.http.service.AccountService;
import com.novel.read.model.db.ChapterInfoBean;
import com.novel.read.model.db.dbManage.BookRepository;
import com.novel.read.model.protocol.BookArticleResp;
import com.novel.read.model.protocol.BookDetailResp;
import com.novel.read.model.protocol.CategoryTypeResp;
import com.novel.read.model.protocol.HotSearchResp;
import com.novel.read.model.protocol.MarkResp;
import com.novel.read.model.protocol.RankByUpadateResp;
import com.novel.read.model.protocol.RecommendBookResp;
import com.novel.read.model.protocol.RecommendListResp;
import com.novel.read.model.protocol.SearchResp;
import com.novel.read.model.protocol.UidResp;
import com.novel.read.model.protocol.VersionResp;
import com.novel.read.utlis.LogUtils;
import com.novel.read.utlis.PhoneUtils;
import com.novel.read.widget.page.TxtChapter;
import org.reactivestreams.Subscriber;
import org.reactivestreams.Subscription;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import io.reactivex.Single;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
import okhttp3.MediaType;
import okhttp3.RequestBody;
import retrofit2.Call;
import retrofit2.Callback;
/**
* Created by JillFung on 2017/2/14.
*/
public class AccountManager {
private AccountService accountService;
private AccountManager() {
accountService = ServiceGenerator.createService(AccountService.class, MyRequestType.URL_TEXT);
}
private static AccountManager instance = null;
public static synchronized AccountManager getInstance() {
if (instance == null) {
instance = new AccountManager();
}
return instance;
}
public void getRecommendBook(String bookId,String limit) {
HashMap<String, String> map = new HashMap<>();
map.put("book_id", bookId);
Call<RecommendBookResp> call = accountService.getRecommendBook(getUrlString(Urls.getRecommend,map));
call.enqueue(new ServiceCallback<>(GetRecommendBookEvent.class));
}
public void getBookDetail(String bookId) {
HashMap<String, String> map = new HashMap<>();
map.put("book_id", bookId);
Call<BookDetailResp> call = accountService.getBookDetail(getUrlString(Urls.getBookDetail,map));
call.enqueue(new ServiceCallback<>(GetBookDetailEvent.class));
}
public Single<BookDetailResp> getBookDetails(String bookId){ //rxjava 获取多书籍详情 合并请求调用
HashMap<String, String> map = new HashMap<>();
map.put("book_id", bookId);
return accountService.getBookDetails(getUrlString(Urls.getBookDetail,map));
}
public void getCategoryType() {
HashMap<String, String> map = new HashMap<>();
Call<CategoryTypeResp> call = accountService.getCategoryType(getUrlString(Urls.getCategoryType,map));
call.enqueue(new ServiceCallback<>(GetCategoryTypeEvent.class));
}
public void getHotSearch() {
HashMap<String, String> map = new HashMap<>();
Call<HotSearchResp> call = accountService.getHotSearch(getUrlString(Urls.getHotSearch,map));
call.enqueue(new ServiceCallback<>(HotSearchEvent.class));
}
public void getBookArticle(String bookId,String hasContent,String page,String limit) {
HashMap<String, String> map = new HashMap<>();
map.put("book_id", bookId);
map.put("has_content", hasContent);
map.put("page", page);
map.put("limit", limit);
Call<BookArticleResp> call = accountService.getBookArticle(getUrlString(Urls.getBookArticle,map));
call.enqueue(new ServiceCallback<>(BookArticleEvent.class));
}
public void getSearchBookList(String category_id,String key,int page) {
HashMap<String, String> map = new HashMap<>();
if (!TextUtils.isEmpty(category_id)) {
map.put("category_id", category_id);
}else {
map.put("category_id", "0");
}
if (!TextUtils.isEmpty(key)){
map.put("key", key);
}
map.put("page", String.valueOf(page));
Call<SearchResp> call = accountService.getSearchList(getUrlString(Urls.getBookList,map));
call.enqueue(new ServiceCallback<>(SearchListEvent.class));
}
public void getRecommendList(String listType, Callback<RecommendListResp> callback) {
HashMap<String, String> map = new HashMap<>();
map.put("type", listType);
Call<RecommendListResp> call = accountService.getRecommendList(getUrlString(Urls.getRecommendList,map));
call.enqueue(callback);
}
public void getRankByUpdate(int page, int limit, Callback<RankByUpadateResp> callback) {
HashMap<String, String> map = new HashMap<>();
if (!TextUtils.isEmpty(String.valueOf(page))) {
map.put("page", String.valueOf(page));
}
if (limit!=0){
map.put("limit", String.valueOf(limit));
}
Call<RankByUpadateResp> call = accountService.getRankByUpdate(getUrlString(Urls.getRankByUpdate,map));
call.enqueue(callback);
}
public void getRankList(String type, String sex, String dateType, String page, Callback<RankByUpadateResp> callback){
HashMap<String, String> map = new HashMap<>();
map.put("type", type);
map.put("gender", sex);
map.put("date_type", dateType);
map.put("page", page);
Call<RankByUpadateResp> call = accountService.getRankList(getUrlString(Urls.getRankList, map));
call.enqueue(callback);
}
public void checkVersion(int versionCode){
HashMap<String, String> map = new HashMap<>();
map.put("version", String.valueOf(versionCode));
// map.put("shell", Constant.shell);
Call<VersionResp> call = accountService.checkVersion(getUrlString(Urls.checkVersion, map));
call.enqueue(new ServiceCallback<>(VersionEvent.class));
}
public void addSign(String bookId,String articleId,String content){
HashMap<String, String> map = new HashMap<>();
map.put("book_id", bookId);
map.put("article_id", articleId);
map.put("content", content);
Call<ErrorResponse> call = accountService.addSign(Urls.addBookSign, mapToBody(map));
call.enqueue(new ServiceCallback<>(AddBookSignEvent.class));
}
public void deleteSign(String signIds){
HashMap<String, String> map = new HashMap<>();
map.put("sign_ids", signIds);
Call<ErrorResponse> call = accountService.deleteSign(Urls.deleteSign, mapToBody(map));
call.enqueue(new ServiceCallback<>(DeleteBookSignEvent.class));
}
public void getSignList(String bookId){
HashMap<String, String> map = new HashMap<>();
map.put("book_id", bookId);
Call<MarkResp> call = accountService.getSignList(getUrlString(Urls.getBookSign, map));
call.enqueue(new ServiceCallback<>(GetBookSignEvent.class));
}
public void login(Context mContext){
HashMap<String, String> map = new HashMap<>();
Log.e("getUniquePsuedoID", "login: "+ PhoneUtils.getUniquePsuedoID());
map.put("code", PhoneUtils.getUniquePsuedoID());
Call<UidResp> call = accountService.login(Urls.login, mapToBody(map));
call.enqueue(new ServiceCallback<>(LoginEvent.class));
}
private Subscription mChapterSub;
public void getBookArticleDetail(String bookId,List<TxtChapter> bookChapters){
int size = bookChapters.size();
//取消上次的任务,防止多次加载
if (mChapterSub != null) {
mChapterSub.cancel();
}
List<Single<ChapterInfoBean>> chapterInfos = new ArrayList<>(bookChapters.size());
ArrayDeque<String> titles = new ArrayDeque<>(bookChapters.size());
// 将要下载章节,转换成网络请求。
for (int i = 0; i < size; ++i) {
TxtChapter bookChapter = bookChapters.get(i);
// 网络中获取数据
Single<ChapterInfoBean> chapterInfoSingle = getChapterInfo(bookChapter.getChapterId());
chapterInfos.add(chapterInfoSingle);
titles.add(bookChapter.getTitle());
}
Single.concat(chapterInfos)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<ChapterInfoBean>() {
String title = titles.poll();
@Override
public void onSubscribe(Subscription s) {
s.request(Integer.MAX_VALUE);
mChapterSub = s;
}
@Override
public void onNext(ChapterInfoBean chapterInfoBean) {
//存储数据
BookRepository.getInstance().saveChapterInfo(
bookId, title, chapterInfoBean.getBody()
);
EventManager.Companion.getInstance().postEvent(new FinishChapterEvent());
//将获取到的数据进行存储
title = titles.poll();
}
@Override
public void onError(Throwable t) {
//只有第一个加载失败才会调用errorChapter
if (bookChapters.get(0).getTitle().equals(title)) {
EventManager.Companion.getInstance().postEvent(new ErrorChapterEvent());
}
LogUtils.e(t);
}
@Override
public void onComplete() {
}
}
);
}
/**
* 注意这里用的是同步请求
*/
public Single<ChapterInfoBean> getChapterInfo(String id){
HashMap<String,String> map = new HashMap<>();
map.put("article_id", id);
return accountService.getBookArticleDetail(getUrlString(Urls.getDetail, map))
.map(bean -> bean.getArticle().get(0));
}
/**
* get方法拼接字符串
*/
private String getUrlString(String path, HashMap<String, String> query) {
String mypath = path;
if (query != null && query.size() > 0) {
StringBuilder pathWithQuery = new StringBuilder(path);
if (!path.contains("?")) {
pathWithQuery.append("?");
} else {
pathWithQuery.append("&");
}
for (Map.Entry<String, String> stringStringEntry : query.entrySet()) {
String key = (String) ((Map.Entry) stringStringEntry).getKey();
String val = (String) ((Map.Entry) stringStringEntry).getValue();
pathWithQuery.append(key);
pathWithQuery.append("=");
pathWithQuery.append(val);
pathWithQuery.append("&");
}
pathWithQuery.deleteCharAt(pathWithQuery.length() - 1);
mypath = pathWithQuery.toString();
}
return mypath;
}
/**
* 减少请求info类的数量,直接用map替代实体类返回body
*/
private RequestBody mapToBody(HashMap<String,String> map){
return RequestBody.create(MediaType.parse("application/json; charset=utf-8"), ServiceGenerator.formatResponse(map));
}
}

@ -0,0 +1,37 @@
package com.novel.read.http;
import androidx.annotation.NonNull;
import com.common_lib.base.utils.SecurityUtils;
import com.novel.read.constants.Constant;
import com.novel.read.utlis.SpUtil;
import java.io.IOException;
import okhttp3.Interceptor;
import okhttp3.Request;
import okhttp3.Response;
/**
* Created by alex on 2019/3/1.
*/
public class CommonHeadersInterceptor implements Interceptor {
@Override
public Response intercept(@NonNull Interceptor.Chain chain) throws IOException {
Request request = chain.request();
Request.Builder builder = request.newBuilder();
String authKey = "Android";
String timeStamp = String.valueOf(System.currentTimeMillis() / 1000);
String uid = SpUtil.getStringValue(Constant.Uid, "1");
builder.addHeader("Content-Type", "application/json");
builder.addHeader("UID", uid);
builder.addHeader("AUTHKEY", authKey);
builder.addHeader("TIMESTAMP", timeStamp);
builder.addHeader("SIGN", SecurityUtils.getInstance().MD5Decode(authKey + timeStamp).toUpperCase());
return chain.proceed(builder.build());
}
}

@ -0,0 +1,59 @@
package com.novel.read.http;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.mango.mangolib.http.GsonUTCdateAdapter;
import com.mango.mangolib.http.MyRequestType;
import com.mango.mangolib.http.ResponseConverterFactory;
import java.util.Date;
import java.util.concurrent.TimeUnit;
import okhttp3.OkHttpClient;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;
public class ServiceGenerator {
private static final String API_BASE_URL_TEXT = "http://novel.duoduvip.com/";
private static Gson gson = new GsonBuilder()
.setPrettyPrinting()
.registerTypeAdapter(Date.class, new GsonUTCdateAdapter()).create();
private static Retrofit.Builder builderTEXT = new Retrofit.Builder()
.baseUrl(API_BASE_URL_TEXT)
.client(getOkHttp())
.addConverterFactory(ResponseConverterFactory.Companion.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create(gson));
private static OkHttpClient getOkHttp(){
return new OkHttpClient()
.newBuilder()
.addInterceptor(new CommonHeadersInterceptor())
.connectTimeout(30, TimeUnit.SECONDS)
.writeTimeout(30, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.build();
}
private ServiceGenerator() {
}
public static <S> S createService(Class<S> serviceClass) {
return createService(serviceClass);
}
public static <S> S createService(Class<S> serviceClass, final MyRequestType type) {
Retrofit retrofit = builderTEXT.build();
return retrofit.create(serviceClass);
}
public static String formatResponse(Object obj) {
return gson.toJson(obj);
}
}

@ -0,0 +1,29 @@
package com.novel.read.http
/**
* create by 赵利君 on 2019/10/14
* describe:
*/
object Urls {
internal const val getRecommend = "api/book/getRecommendByBook/" //获取推荐书籍
internal const val getBookDetail = "api/book/getBookDetail/" //获取书籍详情
internal const val getCategoryType = "api/category/getCategoryList/" //获取小说分类
internal const val getHotSearch = "api/search/getHotSearch/" //获取热搜墙
internal const val getBookArticle = "api/book/getBookArticle/" //获取书籍章节
internal const val getBookList = "api/book/getBookList/" //获取和搜索书籍列表
internal const val getRecommendList = "api/rank/getRecommendList/" //获取推荐列表
internal const val getRankByUpdate = "api/rank/getRankByUpdate/" //最新更新
internal const val getRankList = "api/rank/getRankList/" //获取排行榜
internal const val checkVersion = " api/version/checkVersion/" //检测新版本
internal const val addBookSign = " api/sign/addBookSign/" //添加书签
internal const val getBookSign = " api/sign/getBookSignList/" //获取书签
internal const val deleteSign = " api/sign/deleteSign/" //获取书签
internal const val login = "api/login/checkLogin"//登录
internal const val getDetail = "api/book/getArticleDetail"//获取章节详情
}

@ -0,0 +1,94 @@
package com.novel.read.http.service;
import com.mango.mangolib.http.ErrorResponse;
import com.novel.read.model.protocol.BookArticleResp;
import com.novel.read.model.protocol.BookDetailResp;
import com.novel.read.model.protocol.CategoryTypeResp;
import com.novel.read.model.protocol.ChapterInfoPackage;
import com.novel.read.model.protocol.HotSearchResp;
import com.novel.read.model.protocol.MarkResp;
import com.novel.read.model.protocol.RankByUpadateResp;
import com.novel.read.model.protocol.RecommendBookResp;
import com.novel.read.model.protocol.RecommendListResp;
import com.novel.read.model.protocol.SearchResp;
import com.novel.read.model.protocol.UidResp;
import com.novel.read.model.protocol.VersionResp;
import io.reactivex.Single;
import okhttp3.RequestBody;
import retrofit2.Call;
import retrofit2.http.Body;
import retrofit2.http.GET;
import retrofit2.http.POST;
import retrofit2.http.Url;
/**
* Created by Administrator on 2017/2/14.
*/
public interface AccountService {
//获取推荐书籍
@GET
Call<RecommendBookResp> getRecommendBook(@Url String url);
//获取书籍详情
@GET
Call<BookDetailResp> getBookDetail(@Url String url);
//获取书籍详情
@GET
Single<BookDetailResp> getBookDetails(@Url String url);
//小说类型
@GET
Call<CategoryTypeResp> getCategoryType(@Url String url);
//热搜
@GET
Call<HotSearchResp> getHotSearch(@Url String url);
//书籍章节
@GET
Call<BookArticleResp> getBookArticle(@Url String url);
//搜索
@GET
Call<SearchResp> getSearchList(@Url String url);
//获取推荐
@GET
Call<RecommendListResp> getRecommendList(@Url String url);
//获取最新排行
@GET
Call<RankByUpadateResp> getRankByUpdate(@Url String url);
//获取排行
@GET
Call<RankByUpadateResp> getRankList(@Url String url);
//获取新版本
@GET
Call<VersionResp> checkVersion(@Url String url);
//添加标签
@POST
Call<ErrorResponse> addSign(@Url String url, @Body RequestBody body);
//删除标签
@POST
Call<ErrorResponse> deleteSign(@Url String url, @Body RequestBody body);
//获取标签
@GET
Call<MarkResp> getSignList(@Url String url);
//登录
@POST
Call<UidResp> login(@Url String url, @Body RequestBody body);
//获取书籍章节详情
@GET
Single<ChapterInfoPackage> getBookArticleDetail(@Url String url);
}

@ -0,0 +1,9 @@
package com.novel.read.inter
/**
* create by zlj on 2019/10/14
* describe:
*/
interface OnLoadMoreListener {
fun onLoadMore()
}

@ -0,0 +1,161 @@
package com.novel.read.model.db;
import org.litepal.crud.LitePalSupport;
import java.io.Serializable;
/**
* Created by newbiechen on 17-5-10.
* 书的章节链接(作为下载的进度数据)
* 同时作为网络章节和本地章节 (没有找到更好分离两者的办法)
*/
public class BookChapterBean extends LitePalSupport implements Serializable {
/**
* title : 第一章 他叫白小纯
* link : http://read.qidian.com/chapter/rJgN8tJ_cVdRGoWu-UQg7Q2/6jr-buLIUJSaGfXRMrUjdw2
* unreadble : false
*/
private String chapterId;
private String link;
private String title;
//所属的下载任务
private String taskName;
private boolean unreadble;
//所属的书籍
private String bookId;
//本地书籍参数
private CollBookBean collBookBean;
//本地下载参数
private DownloadTaskBean downloadTaskBean;
//在书籍文件中的起始位置
private long start;
//在书籍文件中的终止位置
private long end;
public BookChapterBean(String id, String link, String title, String taskName,
boolean unreadble, String bookId, long start, long end) {
this.chapterId = id;
this.link = link;
this.title = title;
this.taskName = taskName;
this.unreadble = unreadble;
this.bookId = bookId;
this.start = start;
this.end = end;
}
public BookChapterBean(String id,String title) {
this.chapterId = id;
this.title = title;
}
public BookChapterBean() {
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getLink() {
return link;
}
public void setLink(String link) {
this.link = link;
}
public boolean isUnreadble() {
return unreadble;
}
public void setUnreadble(boolean unreadble) {
this.unreadble = unreadble;
}
public String getTaskName() {
return taskName;
}
public void setTaskName(String taskName) {
this.taskName = taskName;
}
public boolean getUnreadble() {
return this.unreadble;
}
public String getBookId() {
return bookId;
}
public void setBookId(String bookId) {
this.bookId = bookId;
}
public String getId() {
return chapterId;
}
public void setId(String id) {
this.chapterId = id;
}
public long getStart() {
return start;
}
public void setStart(long start) {
this.start = start;
}
public long getEnd() {
return end;
}
public void setEnd(long end) {
this.end = end;
}
public CollBookBean getCollBookBean() {
return collBookBean;
}
public void setCollBookBean(CollBookBean collBookBean) {
this.collBookBean = collBookBean;
}
public DownloadTaskBean getDownloadTaskBean() {
return downloadTaskBean;
}
public void setDownloadTaskBean(DownloadTaskBean downloadTaskBean) {
this.downloadTaskBean = downloadTaskBean;
}
@Override
public String toString() {
return "BookChapterBean{" +
"chapterId='" + chapterId + '\'' +
", link='" + link + '\'' +
", title='" + title + '\'' +
", taskName='" + taskName + '\'' +
", unreadble=" + unreadble +
", bookId='" + bookId + '\'' +
", start=" + start +
", end=" + end +
'}';
}
}

@ -0,0 +1,43 @@
package com.novel.read.model.db;
import org.litepal.crud.LitePalSupport;
import java.io.Serializable;
/**
* Created by newbiechen on 17-5-20.
*/
public class BookRecordBean extends LitePalSupport implements Serializable {
//所属的书的id
private String bookId;
//阅读到了第几章
private int chapter;
//当前的页码
private int pagePos;
public String getBookId() {
return bookId;
}
public void setBookId(String bookId) {
this.bookId = bookId;
}
public int getChapter() {
return chapter;
}
public void setChapter(int chapter) {
this.chapter = chapter;
}
public int getPagePos() {
return pagePos;
}
public void setPagePos(int pagePos) {
this.pagePos = pagePos;
}
}

@ -0,0 +1,98 @@
package com.novel.read.model.db;
/**
* Created by newbiechen on 17-5-10.
*/
public class ChapterInfoBean {
/**
* title : 第一章 他叫白小纯
* content : 帽儿山位于东林山脉中山下有一个村子民风淳朴以耕田为生与世隔绝
清晨村庄的大门前整个村子里的乡亲正为一个十五六岁少年送别这少年瘦弱但却白白净净看起来很是乖巧衣着尽管是寻常的青衫可却洗的泛白穿在这少年的身上与他目中的纯净搭配在一起透出一股子灵动
他叫白小纯
父老乡亲们我要去修仙了可我舍不得你们啊少年满脸不舍原本就乖巧的样子此刻看起来更为纯朴
四周的乡亲面面相觑顿时摆出难舍之色
小纯你爹娘走的早你是个好孩子难道你不想长生了么成为仙人就可以长生能活的很久很久走吧雏鹰长大总有飞出去的那一天人群内走出一个头发花白的老者说道好孩子三个字时他顿了一下
在外面遇到任何事情都要坚持下去走出村子就不要回来因为你的路在前方老人神色慈祥拍了拍少年的肩膀
长生白小纯身体一震目中慢慢坚定起来在老者以及四周乡亲鼓励的目光下他重重的点了点头深深的看了一眼四周的乡亲转身迈着大步渐渐走出了村子
眼看少年的身影远去村中的众人一个个都激动起来目中的难舍刹那就被喜悦代替那之前满脸慈祥的老者此刻也在颤抖眼中流下泪水
苍天有眼这白鼠狼他终于终于走了是谁告诉他在附近看到仙人的你为村子立下了大功
这白鼠狼终于肯离开了可怜我家的几只鸡就因为这白鼠狼怕鸡打鸣不知用了什么方法唆使一群孩子吃鸡肉把全村的鸡都给吃的干干净净
今天过年了欢呼之声立刻在这不大的村子里沸腾而起甚至有人拿出了锣鼓高兴的敲打起来
村子外白小纯还没等走远他就听到了身后村子内传出了敲锣打鼓的声音还夹着欢呼
白小纯脚步一顿神色有些古怪干咳一声伴随着耳边传来的锣鼓白小纯顺着山路走上了帽儿山
这帽儿山虽不高却灌木杂多虽是清晨可看起来也是黑压压一片很是安静
听二狗说他前几天在这里被一头野猪追赶时看到天上有仙人飞过白小纯走在山路上心脏怦怦跳动时忽然一旁的灌林中传来阵阵哗哗声似野猪一样这声音来的突然让本就紧张的白小纯顿时背后发凉
谁在那里白小纯右手快速从行囊中拿出四把斧头六把柴刀还觉得不放心又从怀里取出了一小根黑色的香死死的抓住
别出来千万别出来我有斧头有柴刀手里的香还可以召唤天雷能引仙人降临你敢出来就劈死你白小纯哆嗦的大喊连滚带爬的夹着那些武器赶紧顺着山路跑去沿途叮当乱响斧头柴刀掉了一地
或许是真的被他给吓住了很快的哗哗声就消失没有什么野兽跑出来白小纯面色苍白擦了擦冷汗有心放弃继续上山可一想到手中这根香是他爹娘去世前留给他的据说是祖上曾偶然的救下一个落魄的仙人那仙人离去时留下这根香作为报答曾言会收下白家血脉一人为弟子只要点燃仙人就会到来
可至今为止这根香他点过十多次始终不见仙人到来让白小纯开始怀疑仙人是不是真的会来这一次之所以下定决心一方面是香所剩不多另一方面是他听村子里人说头几天在这看到有仙人从天上飞过
所以他这才到来想着距离仙人近一些或许仙人就察觉到了也说不定
踌躇一番白小纯咬牙继续好在此山不高不久他气喘吁吁的到了山顶站在那里他遥望山下的村庄神色颇为感慨又低头看着手中的只有指甲盖大小的黑香此香似乎被燃烧了好多次所剩不多
三年了爹娘保佑我这次一定要成功白小纯深吸口气小心的将香点燃立刻四周狂风顿起天空更是眨眼间乌云密布一道道闪电划过还有震耳欲聋的雷鸣在白小纯耳边直接炸开
声音之大气势之强让白小纯身体哆嗦有种随时会被雷劈死的感觉下意识的就想要吐口唾沫将那根香灭掉但却挣扎忍住
三年了我点这根香点了十二次这是第十三次这次一定要忍住小纯不怕应该不会被劈死白小纯想起了这三年的经历不算这次点了十二次每次都是这样的雷鸣闪电仙人也没有到来吓的本就怕死的他每次都吐口唾沫将其熄灭说来也怪这根香看似不凡可实际上一样是浇水就灭
在白小纯这里心惊肉跳艰难的于那雷声中等待时距离这里不远处的天空上有一道长虹正急速的呼啸而来
长虹内是一个中年男子这男子衣着华丽仙风道骨可偏偏风尘仆仆甚至仔细去看可以看到他神色内深深的疲惫
我倒要看看到底是个什么样的人竟然点根香点了三年
一想到自己这三年的经历中年男子就气恼三年前他察觉有人点燃自己还是凝气时送出的香药想起了当年在凡俗中的一段人情
这才飞出寻来原本按照他的打算很快就会回来可没成想刚寻着香气过去还没等多远那气息就瞬间消失断了联系若是一次也就罢了这三年气息出现了十多次
使得他这里多次在寻找时中断就这样来来回回折腾了三年
此刻他遥遥的看到了帽儿山看到了山顶上白小纯气不打一处来一瞬飞出直接就站在了山顶大手一挥那根所剩不多的香直接熄灭
雷声刹那消失白小纯愣了一下抬头一看看到了自己的身边多了一个中年男子
仙人白小纯小心翼翼的开口有些拿不准背后偷偷捡起一把斧头
本座李青候你是白家后人中年修士目光如电无视白小纯身后的斧子打量了白小纯一番觉得眼前此子眉清目秀依稀与当年的故人相似资质也不错心底的恼意也不由缓了一些
晚辈正是白家后人白小纯白小纯眨了眨眼小声说道虽然心中有些畏惧但还是挺了挺腰板
我问你点一根香为什么点了三年中年修士淡淡开口问出了他这三年里最想要知道的问题
白小纯听到这个问题脑筋飞速转动然后脸上摆出惆怅遥望山下的村庄
晚辈是一个重情重义的人舍不得那些乡亲们每一次我点燃香他们也都不舍得我离去如今山下的他们还在因为我的离去而悲伤呢
中年修士一愣这个缘由是他之前没想到的目中的恼色又少了一些单单从话语上看此子的本性还是不错的
可当他的目光落在山下的村子时他的神识随之扫过听到了村子里的敲锣打鼓以及那一句句欢呼白鼠狼离去的话语面色立刻难看起来有些头疼看着眼前这个外表乖巧纯朴人畜无害的白小纯已心底明朗对方实际上一肚子坏水
说实话中年修士一瞪眼声音如同雷声一样白小纯吓得一个哆嗦
这不怨我啊你那什么破香啊每次点燃都会打雷好几次都差点劈死我我躲过了十三次已经很不容易了白小纯可怜兮兮的说道
中年修士看着白小纯半晌无语
既然你这么害怕为什么还要强行去点香十多次中年修士缓缓开口
我怕死啊修仙不是能长生么我想长生啊白小纯委屈的说道
中年修士再次无语不过觉得此子总算执念可嘉扔到门派里磨炼一番或可在性子上改变一二
于是略一思索大袖一甩卷着白小纯化作一道长虹直奔天边而去
跟我走吧
去哪这也太高了吧白小纯看到自己在天上飞下面是万丈深渊立刻脸色苍白斧头一扔死死的抱住仙人的大腿
中年修士看了眼自己的腿无奈开口
灵溪宗
兄弟姐妹们阔别2个月你们想不想我啊我非常想你们
这本书我做了详细的大纲每次回顾大纲里的情节都很兴奋有种燃烧的感觉我非常满意明天正式更新依旧是中午一章晚上一章
很兴奋我们已沉寂了数月如今归来再战起点
新书期兄弟姐妹别忘了收藏与推荐啊收藏与推荐至关重要
求收藏求推荐
让众人知晓我们归来了
我们的目标依旧是点击榜推荐榜第一
*/
private String title;
private String content;
private int words;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getBody() {
return content;
}
public void setBody(String body) {
this.content = body;
}
public int getWords() {
return words;
}
public void setWords(int words) {
this.words = words;
}
}

@ -0,0 +1,198 @@
package com.novel.read.model.db;
import com.novel.read.base.MyApp;
import com.novel.read.utlis.StringUtils;
import org.litepal.crud.LitePalSupport;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
/**
* Created by newbiechen on 17-5-8.
* 收藏的书籍
*/
public class CollBookBean extends LitePalSupport implements Serializable {
public static final int STATUS_UNCACHE = 0; //未缓存
public static final int STATUS_CACHING = 1; //正在缓存
public static final int STATUS_CACHED = 2; //已经缓存
/**
* _id : 53663ae356bdc93e49004474
* title : 逍遥派
* author : 白马出淤泥
* shortIntro : 金庸武侠中有不少的神秘高手书中或提起名字或不曾提起总之他们要么留下了绝世秘笈要么就名震武林 独孤九剑的创始者独孤求败他真的只创出九剑吗 残本葵花...
* cover : /cover/149273897447137
* hasCp : true
* latelyFollower : 60213
* retentionRatio : 22.87
* updated : 2017-05-07T18:24:34.720Z
* <p>
* chaptersCount : 1660
* lastChapter : 第1659章 朱长老
*/
private String bookId; // 本地书籍中,path 的 md5 值作为本地书籍的 id
private String title;
private String author;
private String shortIntro;
private String cover; // 在本地书籍中,该字段作为本地文件的路径
private boolean hasCp;
private int latelyFollower;
private double retentionRatio;
//最新更新日期
private String updated;
//最新阅读日期
private String lastRead;
private int chaptersCount;
private String lastChapter;
//是否更新或未阅读
private boolean isUpdate = true;
//是否是本地文件
private boolean isLocal = false;
private boolean isSelect = false;
private int include_image;
public boolean isSelect() {
return isSelect;
}
public void setSelect(boolean select) {
isSelect = select;
}
private List<BookChapterBean> bookChapterList = new ArrayList<BookChapterBean>();
public String getId() {
return bookId == null ? "" : bookId;
}
public void setId(String id) {
this.bookId = id;
}
public String getTitle() {
return title == null ? "" : StringUtils.convertCC(title, MyApp.getContext());
}
public void setTitle(String title) {
this.title = title;
}
public String getAuthor() {
return author == null ? "" :StringUtils.convertCC(author, MyApp.getContext());
}
public void setAuthor(String author) {
this.author = author;
}
public String getShortIntro() {
return shortIntro == null ? "" :StringUtils.convertCC(shortIntro, MyApp.getContext());
}
public void setShortIntro(String shortIntro) {
this.shortIntro = shortIntro;
}
public String getCover() {
return cover == null ? "" : cover;
}
public void setCover(String cover) {
this.cover = cover;
}
public boolean isHasCp() {
return hasCp;
}
public void setHasCp(boolean hasCp) {
this.hasCp = hasCp;
}
public int getLatelyFollower() {
return latelyFollower;
}
public void setLatelyFollower(int latelyFollower) {
this.latelyFollower = latelyFollower;
}
public double getRetentionRatio() {
return retentionRatio;
}
public void setRetentionRatio(double retentionRatio) {
this.retentionRatio = retentionRatio;
}
public String getUpdated() {
return updated == null ? "" : updated;
}
public void setUpdated(String updated) {
this.updated = updated;
}
public String getLastRead() {
return lastRead == null ? "" : lastRead;
}
public void setLastRead(String lastRead) {
this.lastRead = lastRead;
}
public int getChaptersCount() {
return chaptersCount;
}
public void setChaptersCount(int chaptersCount) {
this.chaptersCount = chaptersCount;
}
public String getLastChapter() {
return lastChapter == null ? "" : StringUtils.convertCC(lastChapter, MyApp.getContext());
}
public void setLastChapter(String lastChapter) {
this.lastChapter = lastChapter;
}
public boolean isUpdate() {
return isUpdate;
}
public void setIsUpdate(boolean update) {
isUpdate = update;
}
public boolean isLocal() {
return isLocal;
}
public void setLocal(boolean local) {
isLocal = local;
}
public int getInclude_image() {
return include_image;
}
public void setInclude_image(int include_image) {
this.include_image = include_image;
}
public List<BookChapterBean> getBookChapters() {
if (bookChapterList == null) {
return new ArrayList<>();
}
return bookChapterList;
}
public void setBookChapters(List<BookChapterBean> bookChapterList) {
this.bookChapterList = bookChapterList;
}
}

@ -0,0 +1,157 @@
package com.novel.read.model.db;
import org.litepal.LitePal;
import org.litepal.crud.LitePalSupport;
import java.util.ArrayList;
import java.util.List;
/**
* Created by newbiechen on 17-5-11.
*/
public class DownloadTaskBean extends LitePalSupport {
public static final int STATUS_LOADING = 1;
public static final int STATUS_WAIT = 2;
public static final int STATUS_PAUSE = 3;
public static final int STATUS_ERROR = 4;
public static final int STATUS_FINISH = 5;
//任务名称 -> 名称唯一不重复
private String taskName;
//所属的bookId(外健)
private String bookId;
private List<BookChapterBean> bookChapterList = new ArrayList<>();
//章节的下载进度,默认为初始状态
private int currentChapter = 0;
//最后的章节
private int lastChapter = 0;
//状态:正在下载、下载完成、暂停、等待、下载错误。
private volatile int status = STATUS_WAIT;
//总大小 -> (完成之后才会赋值)
private long size = 0;
private CollBookBean collBookBean;
public DownloadTaskBean(String taskName, String bookId, int currentChapter, int lastChapter,
int status, long size) {
this.taskName = taskName;
this.bookId = bookId;
this.currentChapter = currentChapter;
this.lastChapter = lastChapter;
this.status = status;
this.size = size;
}
public DownloadTaskBean() {
}
public String getBookId() {
return bookId;
}
public void setBookId(String bookId) {
this.bookId = bookId;
}
public String getTaskName() {
return taskName;
}
public void setTaskName(String taskName) {
this.taskName = taskName;
if (bookChapterList!=null){
for (BookChapterBean bean : bookChapterList){
bean.setTaskName(getTaskName());
}
}
}
public List<BookChapterBean> getBookChapterList() {
if (bookChapterList == null) {
// BookChapterBeanDao targetDao = daoSession.getBookChapterBeanDao();
// List<BookChapterBean> bookChapterListNew = targetDao
// ._queryDownloadTaskBean_BookChapterList(taskName);
List<BookChapterBean> bookChapterListNew = LitePal
.where("taskName=?", taskName).find(BookChapterBean.class);
synchronized (this) {
if (bookChapterList == null) {
bookChapterList = bookChapterListNew;
}
}
}
return bookChapterList;
}
/**
* 这才是真正的列表使用类
*
*/
public void setBookChapters(List<BookChapterBean> beans){
bookChapterList = beans;
for (BookChapterBean bean : bookChapterList){
bean.setTaskName(getTaskName());
}
}
public List<BookChapterBean> getBookChapters(){
return bookChapterList;
}
public int getCurrentChapter() {
return currentChapter;
}
public void setCurrentChapter(int current) {
this.currentChapter = current;
}
public int getLastChapter() {
return lastChapter;
}
public void setLastChapter(int lastChapter) {
this.lastChapter = lastChapter;
}
//多线程访问的问题,所以需要同步机制
public int getStatus() {
return status;
}
public void setStatus(int status){
this.status = status;
}
public long getSize() {
return size;
}
public void setSize(long size) {
this.size = size;
}
public synchronized void resetBookChapterList() {
bookChapterList = null;
}
public CollBookBean getCollBookBean() {
List<CollBookBean> list = LitePal.where("bookId=?", bookId).find(CollBookBean.class);
if (list!=null&&list.size()>0){
return list.get(0);
}else {
return collBookBean;
}
}
public void setCollBookBean(CollBookBean collBookBean) {
this.collBookBean = collBookBean;
}
}

@ -0,0 +1,42 @@
package com.novel.read.model.db;
import androidx.annotation.Nullable;
import org.litepal.crud.LitePalSupport;
import java.io.Serializable;
/**
* create by 赵利君 on 2019/6/19
* describe:
*/
public class SearchListTable extends LitePalSupport implements Serializable {
private String key;
private long saveTime;
public String getKey() {
return key == null ? "" : key;
}
public void setKey(String key) {
this.key = key;
}
public long getSaveTime() {
return saveTime;
}
public void setSaveTime(long saveTime) {
this.saveTime = saveTime;
}
@Override
public boolean equals(@Nullable Object obj) {
if (obj != null && obj.toString().equals(key)) {
return true;
}
return super.equals(obj);
}
}

@ -0,0 +1,223 @@
package com.novel.read.model.db.dbManage;
import com.novel.read.constants.Constant;
import com.novel.read.utlis.FileUtils;
import java.io.File;
import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.Map;
/**
* Created by newbiechen on 17-5-20.
* 处理书籍的工具类配合PageFactory使用
* 已弃用
*/
public class BookManager {
private static final String TAG = "BookManager";
private String chapterName;
private String bookId;
private long chapterLen;
private long position;
private Map<String, Cache> cacheMap = new HashMap<>();
private static volatile BookManager sInstance;
public static BookManager getInstance(){
if (sInstance == null){
synchronized (BookManager.class){
if (sInstance == null){
sInstance = new BookManager();
}
}
}
return sInstance;
}
public boolean openChapter(String bookId, String chapterName){
return openChapter(bookId,chapterName,0);
}
public boolean openChapter(String bookId, String chapterName, long position){
//如果文件不存在,则打开失败
File file = new File(Constant.BOOK_CACHE_PATH + bookId
+ File.separator + chapterName + FileUtils.SUFFIX_NB);
if (!file.exists()){
return false;
}
this.bookId = bookId;
this.chapterName = chapterName;
this.position = position;
createCache();
return true;
}
private void createCache(){
//创建Cache
if (!cacheMap.containsKey(chapterName)){
Cache cache = new Cache();
File file = getBookFile(bookId, chapterName);
//TODO:数据加载默认utf-8(以后会增加判断),FileUtils采用Reader获取数据的,可能用byte会更好一点
char[] array = FileUtils.getFileContent(file).toCharArray();
WeakReference<char[]> charReference = new WeakReference<char[]>(array);
cache.size = array.length;
cache.data = charReference;
cacheMap.put(chapterName, cache);
chapterLen = cache.size;
}
else {
chapterLen = cacheMap.get(chapterName).getSize();
}
}
public void setPosition(long position){
this.position = position;
}
public long getPosition(){
return position;
}
//获取上一段
public String getPrevPara(){
//首先判断是否Position已经达到起始位置,已经越界
if (position < 0){
return null;
}
//初始化从后向前获取的起始点,终止点,文本
int end = (int)position;
int begin = end;
char[] array = getContent();
while (begin >= 0) { //判断指针是否达到章节的起始位置
char character = array[begin]; //获取当前指针下的字符
//判断当前字符是否为换行,如果为换行,就代表获取到了一个段落,并退出。
//有可能发生初始指针指的就是换行符的情况。
if ((character+"").equals("\n") && begin != end) {
position = begin;
//当当前指针指向换行符的时候向后退一步
begin++;
break;
}
//向前进一步
begin--;
}
//最后end获取到段落的起始点,begin是段落的终止点。
//当越界的时候,保证begin在章节内
if (begin < 0){
begin = 0;//在章节内
position = -1; //越界
}
int size = end+1 - begin;
return new String(array,begin,size);
}
//获取下一段
public String getNextPara(){
//首先判断是否Position已经达到终点位置
if (position >= chapterLen){
return null;
}
//初始化起始点,终止点。
int begin = (int)position;
int end = begin;
char[] array = getContent();
while (end < chapterLen) { //判断指针是否在章节的末尾位置
char character = array[end]; //获取当前指针下的字符
//判断当前字符是否为换行,如果为换行,就代表获取到了一个段落,并退出。
//有可能发生初始指针指的就是换行符的情况。
//这里当遇到\n的时候,不需要回退
if ((character+"").equals("\n") && begin != end){
++end;//指向下一字段
position = end;
break;
}
//指向下一字段
end++;
}
//所要获取的字段的长度
int size = end - begin;
return new String(array,begin,size);
}
//获取章节的内容
public char[] getContent() {
if (cacheMap.size() == 0){
return new char[1];
}
char[] block = cacheMap.get(chapterName).getData().get();
if (block == null) {
File file = getBookFile(bookId, chapterName);
block = FileUtils.getFileContent(file).toCharArray();
Cache cache = cacheMap.get(chapterName);
cache.data = new WeakReference<char[]>(block);
}
return block;
}
public long getChapterLen(){
return chapterLen;
}
public void clear(){
cacheMap.clear();
position = 0;
chapterLen = 0;
}
/**
* 创建或获取存储文件
* @param folderName
* @param fileName
* @return
*/
public static File getBookFile(String folderName, String fileName){
return FileUtils.getFile(Constant.BOOK_CACHE_PATH + folderName
+ File.separator + fileName + FileUtils.SUFFIX_NB);
}
public static long getBookSize(String folderName){
return FileUtils.getDirSize(FileUtils
.getFolder(Constant.BOOK_CACHE_PATH + folderName));
}
/**
* 根据文件名判断是否被缓存过 (因为可能数据库显示被缓存过但是文件中却没有的情况所以需要根据文件判断是否被缓存
* )
* @param folderName : bookId
* @param fileName: chapterName
* @return
*/
public static boolean isChapterCached(String folderName, String fileName){
File file = new File(Constant.BOOK_CACHE_PATH + folderName
+ File.separator + fileName + FileUtils.SUFFIX_NB);
return file.exists();
}
public class Cache {
private long size;
private WeakReference<char[]> data;
public WeakReference<char[]> getData() {
return data;
}
public void setData(WeakReference<char[]> data) {
this.data = data;
}
public long getSize() {
return size;
}
public void setSize(long size) {
this.size = size;
}
}
}

@ -0,0 +1,371 @@
package com.novel.read.model.db.dbManage;
import android.content.ContentValues;
import android.util.Log;
import com.novel.read.constants.Constant;
import com.novel.read.model.db.BookChapterBean;
import com.novel.read.model.db.BookRecordBean;
import com.novel.read.model.db.ChapterInfoBean;
import com.novel.read.model.db.CollBookBean;
import com.novel.read.model.db.DownloadTaskBean;
import com.novel.read.utlis.FileUtils;
import com.novel.read.utlis.IOUtils;
import com.novel.read.utlis.SpUtil;
import com.novel.read.widget.page.Void;
import org.litepal.LitePal;
import org.litepal.crud.callback.SaveCallback;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Reader;
import java.io.Writer;
import java.util.ArrayList;
import java.util.List;
import io.reactivex.Single;
import io.reactivex.SingleEmitter;
import io.reactivex.SingleOnSubscribe;
/**
* Created by newbiechen on 17-5-8.
* 存储关于书籍内容的信息(CollBook(收藏书籍),BookChapter(书籍列表),ChapterInfo(书籍章节),BookRecord(记录))
*/
public class BookRepository {
private static final String TAG = "CollBookManager";
private static volatile BookRepository sInstance;
private BookRepository() {
}
public static BookRepository getInstance() {
if (sInstance == null) {
synchronized (BookRepository.class) {
if (sInstance == null) {
sInstance = new BookRepository();
}
}
}
return sInstance;
}
//存储已收藏书籍
public void saveCollBookWithAsync(CollBookBean bean) {
// bean.saveAsync().listen(new SaveCallback() {
// @Override
// public void onFinish(boolean success) {
// System.out.println(success);
// }
// });
// LitePal.saveAll(bean.getBookChapters());
// bean.saveOrUpdate("bookId=?", bean.getId());
// bean.saveOrUpdateAsync("bookId=?", bean.getId());
bean.saveOrUpdate("bookId=?", bean.getId());
for (int i = 0; i < bean.getBookChapters().size(); i++) {
bean.getBookChapters().get(i).setCollBookBean(bean);
}
LitePal.saveAllAsync(bean.getBookChapters()).listen(new SaveCallback() {
@Override
public void onFinish(boolean success) {
Log.e(TAG, "saveCollBookWithAsync: " + success);
}
});
// LitePal.saveAll(bean.getBookChapters());
}
/**
* 异步存储
* 同时保存BookChapter
*
* @param beans
*/
public void saveCollBooksWithAsync(List<CollBookBean> beans) {
// mSession.startAsyncSession()
// .runInTx(
// () -> {
// for (CollBookBean bean : beans){
// if (bean.getBookChapters() != null){
// //存储BookChapterBean(需要修改,如果存在id相同的则无视)
// mSession.getBookChapterBeanDao()
// .insertOrReplaceInTx(bean.getBookChapters());
// }
// }
// //存储CollBook (确保先后顺序,否则出错)
// mCollBookDao.insertOrReplaceInTx(beans);
// }
// );
}
public void saveCollBook(CollBookBean bean) {
// mCollBookDao.insertOrReplace(bean);
ContentValues values = new ContentValues();
values.put("isUpdate", bean.isUpdate());
values.put("lastRead", bean.getLastRead());
values.put("lastChapter", bean.getLastChapter());
LitePal.updateAll(CollBookBean.class, values, "bookId=?", bean.getId());
// bean.setBookChapters(new ArrayList<>());
// bean.saveOrUpdate("bookId=?", bean.getId());
// for (int i = 0; i < bean.getBookChapters().size(); i++) {
// bean.getBookChapters().get(i).setCollBookBean(bean);
// }
// LitePal.saveAllAsync(bean.getBookChapters()).listen(new SaveCallback() {
// @Override
// public void onFinish(boolean success) {
// Log.e(TAG, "saveCollBookWithAsync: " + success);
// }
// });
}
public void saveCollBooks(List<CollBookBean> beans) {
for (int i = 0; i <beans.size() ; i++) {
ContentValues values = new ContentValues();
values.put("isUpdate", beans.get(i).isUpdate());
values.put("lastRead", beans.get(i).getLastRead());
values.put("lastChapter", beans.get(i).getLastChapter());
values.put("updated",beans.get(i).getUpdated());
LitePal.updateAll(CollBookBean.class, values, "bookId=?", beans.get(i).getId());
}
}
/**
* 异步存储BookChapter
*
* @param beans
*/
public void saveBookChaptersWithAsync(List<BookChapterBean> beans, CollBookBean collBookBean) {
// //先删除旧的章节,再异步储存新的章节
// LitePal.deleteAll(BookChapterBean.class, "bookId=?", collBookBean.getId());
collBookBean.saveOrUpdate("bookId=?", collBookBean.getId());
for (int i = 0; i <collBookBean.getBookChapters().size() ; i++) {
collBookBean.getBookChapters().get(i).setCollBookBean(collBookBean);
collBookBean.getBookChapters().get(i).saveOrUpdateAsync("bookId=?", collBookBean.getId());
}
// LitePal.saveAllAsync(beans).listen(new SaveCallback() {
// @Override
// public void onFinish(boolean success) {
// if (success) {
//
// }
// Log.d(TAG, "saveBookChaptersWithAsync: " + "进行存储" + success);
// }
// });
}
/**
* 存储章节
*
* @param folderName
* @param fileName
* @param content
*/
public void saveChapterInfo(String folderName, String fileName, String content) {
String str = content.replaceAll("\\\\n\\\\n", "\n");
File file = BookManager.getBookFile(folderName, fileName);
//获取流并存储
Writer writer = null;
try {
writer = new BufferedWriter(new FileWriter(file));
writer.write(str);
writer.flush();
} catch (IOException e) {
e.printStackTrace();
IOUtils.close(writer);
}
}
public void saveBookRecord(BookRecordBean bean) {
// mSession.getBookRecordBeanDao()
// .insertOrReplace(bean);
bean.saveOrUpdateAsync("bookId=?", bean.getBookId()).listen(new SaveCallback() {
@Override
public void onFinish(boolean success) {
Log.e("saveBookRecord", "onFinish: " + success);
}
});
}
/*****************************get************************************************/
public CollBookBean getCollBook(String bookId) {
List<CollBookBean> bean = LitePal.where("bookId =?", bookId).find(CollBookBean.class);
if (bean != null && bean.size() > 0) {
return bean.get(0);
} else {
return null;
}
}
public List<CollBookBean> getCollBooks() {
// return mCollBookDao
// .queryBuilder()
// .orderDesc(CollBookBeanDao.Properties.LastRead)
// .list();
List<CollBookBean> collBookBeans;
if (SpUtil.getBooleanValue(Constant.BookSort, false)) { //默认根据阅读时间排序
collBookBeans = LitePal.order("updated desc").find(CollBookBean.class);
} else {
collBookBeans = LitePal.order("lastRead desc").find(CollBookBean.class);
}
return collBookBeans;
}
//获取书籍列表
public List<BookChapterBean> getBookChaptersInRx(String bookId) {
// return Single.create(new SingleOnSubscribe<List<BookChapterBean>>() {
// @Override
// public void subscribe(SingleEmitter<List<BookChapterBean>> e) throws Exception {
// List<BookChapterBean> beans = mSession
// .getBookChapterBeanDao()
// .queryBuilder()
// .where(BookChapterBeanDao.Properties.BookId.eq(bookId))
// .list();
// e.onSuccess(beans);
// }
// });
List<CollBookBean> bookBeans = LitePal.where("bookId=?", bookId).find(CollBookBean.class, true);
if (bookBeans != null && bookBeans.size() > 0) {
return bookBeans.get(0).getBookChapters();
} else {
return new ArrayList<>();
}
}
//获取阅读记录
public BookRecordBean getBookRecord(String bookId) {
// return mSession.getBookRecordBeanDao()
// .queryBuilder()
// .where(BookRecordBeanDao.Properties.BookId.eq(bookId))
// .unique();
List<BookRecordBean> beans = LitePal.where("bookId=?", bookId).find(BookRecordBean.class);
if (beans != null && beans.size() > 0) {
return beans.get(0);
} else {
return null;
}
}
//TODO:需要进行获取编码并转换的问题
public ChapterInfoBean getChapterInfoBean(String folderName, String fileName) {
File file = new File(Constant.BOOK_CACHE_PATH + folderName
+ File.separator + fileName + FileUtils.SUFFIX_NB);
if (!file.exists()) return null;
Reader reader = null;
String str = null;
StringBuilder sb = new StringBuilder();
try {
reader = new FileReader(file);
BufferedReader br = new BufferedReader(reader);
while ((str = br.readLine()) != null) {
sb.append(str);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
IOUtils.close(reader);
}
ChapterInfoBean bean = new ChapterInfoBean();
bean.setTitle(fileName);
bean.setBody(sb.toString());
return bean;
}
/************************************************************/
/************************************************************/
public Single<Void> deleteCollBookInRx(CollBookBean bean) {
return Single.create(new SingleOnSubscribe<Void>() {
@Override
public void subscribe(SingleEmitter<Void> e) throws Exception {
//查看文本中是否存在删除的数据
deleteBook(bean.getId());
//删除任务
deleteDownloadTask(bean.getId());
//删除目录
deleteBookChapter(bean.getId());
//删除CollBook
LitePal.deleteAll(CollBookBean.class, "bookId=?", bean.getId());
e.onSuccess(new Void());
}
});
}
//这个需要用rx,进行删除
public void deleteBookChapter(String bookId) {
// mSession.getBookChapterBeanDao()
// .queryBuilder()
// .where(BookChapterBeanDao.Properties.BookId.eq(bookId))
// .buildDelete()
// .executeDeleteWithoutDetachingEntities();
}
public void deleteCollBook(CollBookBean collBook) {
// mCollBookDao.delete(collBook);
}
//删除书籍
public void deleteBook(String bookId) {
FileUtils.deleteFile(Constant.BOOK_CACHE_PATH + bookId);
}
public void deleteBookRecord(String id) {
// mSession.getBookRecordBeanDao()
// .queryBuilder()
// .where(BookRecordBeanDao.Properties.BookId.eq(id))
// .buildDelete()
// .executeDeleteWithoutDetachingEntities();
}
//删除任务
public void deleteDownloadTask(String bookId) {
// mSession.getDownloadTaskBeanDao()
// .queryBuilder()
// .where(DownloadTaskBeanDao.Properties.BookId.eq(bookId))
// .buildDelete()
// .executeDeleteWithoutDetachingEntities();
}
public List<DownloadTaskBean> getDownloadTaskList() {
return LitePal.findAll(DownloadTaskBean.class);
}
public void saveDownloadTask(DownloadTaskBean bean) {
bean.saveOrUpdate("bookId=?",bean.getBookId());
CollBookBean collBookBean = bean.getCollBookBean();
for (int i = 0; i <bean.getBookChapters().size() ; i++) {
bean.getBookChapters().get(i).setDownloadTaskBean(bean);
bean.getBookChapters().get(i).setCollBookBean(collBookBean);
bean.getBookChapters().get(i).saveOrUpdate("chapterId=?", bean.getBookChapters().get(i).getId());
}
// //先删除旧的章节,再异步储存新的章节
// LitePal.deleteAll(BookChapterBean.class, "taskName=?",bean.getTaskName());
//
// LitePal.saveAllAsync(bean.getBookChapters()).listen(new SaveCallback() {
// @Override
// public void onFinish(boolean success) {
// if (success) {
// bean.setBookChapters(bean.getBookChapters());
// bean.saveOrUpdate("taskName=?",bean.getTaskName());
// }
// Log.d(TAG, "saveBookChaptersWithAsync: " + "进行存储" + success);
// }
// });
}
}

@ -0,0 +1,92 @@
package com.novel.read.model.protocol;
import com.novel.read.model.db.BookChapterBean;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
public class BookArticleResp implements Serializable {
private List<ArticleBean> article;
private List<BookChapterBean> bookChapterBean;
public List<ArticleBean> getArticle() {
return article;
}
public void setArticle(List<ArticleBean> article) {
this.article = article;
}
public static class ArticleBean {
/**
* id : 1
* title : 第一章 我为帝辛求支持
* words : 4272
* create_time : 1560048488
*/
private int id;
private String title;
private int words;
private int create_time;
private String volume;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getTitle() {
return getVolume()+title;
}
public void setTitle(String title) {
this.title = title;
}
public int getWords() {
return words;
}
public void setWords(int words) {
this.words = words;
}
public int getCreate_time() {
return create_time;
}
public void setCreate_time(int create_time) {
this.create_time = create_time;
}
public String getVolume() {
return volume == null ? "" : volume;
}
public void setVolume(String volume) {
this.volume = volume;
}
}
public List<BookChapterBean> getChapterBean() {
if (bookChapterBean == null) {
bookChapterBean = createChapterBean();
}
return bookChapterBean;
}
public List<BookChapterBean> createChapterBean() {
List<BookChapterBean> mList = new ArrayList<>();
for (ArticleBean articleBean:getArticle()){
mList.add(new BookChapterBean(String.valueOf(articleBean.getId()),articleBean.getTitle()));
}
return mList;
}
}

@ -0,0 +1,203 @@
package com.novel.read.model.protocol;
import com.novel.read.model.db.CollBookBean;
import com.novel.read.utlis.StringUtils;
/**
* create by 赵利君 on 2019/6/18
* describe:
*/
public class BookDetailResp {
/**
* book : {"id":1,"title":"帝逆洪荒","cover":"http://dev.duoduvip.com/uploads/20190609/408f516e930518df187acc911208f004.png","description":" 【群号536o626o6】人族至宝崆峒印逆天回到未来,带来周天附身殷商人皇纣王之身!帝辛怒吼:人族要自强,人族要自立,人族要自主!但随即帝辛现了洪荒并不是那么简单,洪荒在亘古居然被打碎了,有蛮荒,莽荒,大荒三荒并存,四荒合并成就洪荒大世界!兽皇神逆,魔祖罗T,阴阳老祖,乾坤老祖,扬眉大仙,洪荒大能纷纷出世!真龙老祖,凤凰老母,瑞麒麟三族老祖出世,镇压三族!东皇太一,妖皇帝俊设计假死,瞒过众圣,如今万妖齐聚!且看帝辛如何在万族夹击之中求生存,成就一代人族大帝,庇佑人族!<br> 各位书友要是觉得《帝逆洪荒》还不错的话请不要忘记向您QQ群和微博里的朋友推荐哦!帝逆洪荒最新章节,帝逆洪荒无弹窗,帝逆洪荒全文阅读.","hot":100,"like":20,"author":"天子辉","create_time":1560048488,"words":4637684}
* last_article : {"id":1,"title":"第一章 我为帝辛!【求支持】","create_time":1560048488}
*/
private BookBean book;
private LastArticleBean last_article;
private CollBookBean collBookBean;
public BookBean getBook() {
return book;
}
public void setBook(BookBean book) {
this.book = book;
}
public LastArticleBean getLast_article() {
return last_article;
}
public void setLast_article(LastArticleBean last_article) {
this.last_article = last_article;
}
public static class BookBean {
/**
* id : 1
* title : 帝逆洪荒
* cover : http://dev.duoduvip.com/uploads/20190609/408f516e930518df187acc911208f004.png
* description : 群号536o626o6人族至宝崆峒印逆天回到未来带来周天附身殷商人皇纣王之身帝辛怒吼人族要自强人族要自立人族要自主但随即帝辛现了洪荒并不是那么简单洪荒在亘古居然被打碎了有蛮荒莽荒大荒三荒并存四荒合并成就洪荒大世界兽皇神逆魔祖罗T阴阳老祖乾坤老祖扬眉大仙洪荒大能纷纷出世真龙老祖凤凰老母瑞麒麟三族老祖出世镇压三族东皇太一妖皇帝俊设计假死瞒过众圣如今万妖齐聚且看帝辛如何在万族夹击之中求生存成就一代人族大帝庇佑人族<br> 各位书友要是觉得帝逆洪荒还不错的话请不要忘记向您QQ群和微博里的朋友推荐哦帝逆洪荒最新章节,帝逆洪荒无弹窗,帝逆洪荒全文阅读.
* hot : 100
* like : 20
* author : 天子辉
* create_time : 1560048488
* words : 4637684
*/
private int id;
private String title;
private String cover;
private String description;
private int hot;
private int like;
private String author;
private int create_time;
private int words;
private int include_image;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getCover() {
return cover;
}
public void setCover(String cover) {
this.cover = cover;
}
public String getDescription() {
return description == null ? "" : StringUtils.delete160(description);
}
public void setDescription(String description) {
this.description = description;
}
public int getHot() {
return hot;
}
public void setHot(int hot) {
this.hot = hot;
}
public String getLike() {
return like+"%";
}
public void setLike(int like) {
this.like = like;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public int getCreate_time() {
return create_time;
}
public void setCreate_time(int create_time) {
this.create_time = create_time;
}
public int getWords() {
return words;
}
public void setWords(int words) {
this.words = words;
}
public int getInclude_image() {
return include_image;
}
public void setInclude_image(int include_image) {
this.include_image = include_image;
}
}
public static class LastArticleBean {
/**
* id : 1
* title : 第一章 我为帝辛求支持
* create_time : 1560048488
*/
private int id;
private String title;
private long create_time;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getTitle() {
return title == null ? "" : title;
}
public void setTitle(String title) {
this.title = title;
}
public long getCreate_time() {
return create_time;
}
public void setCreate_time(long create_time) {
this.create_time = create_time;
}
}
public CollBookBean getCollBookBean(){
if (collBookBean == null){
collBookBean = createCollBookBean();
}
return collBookBean;
}
public CollBookBean createCollBookBean(){
CollBookBean bean = new CollBookBean();
bean.setId(String.valueOf(getBook().getId()));
bean.setTitle(getBook().getTitle());
bean.setAuthor(getBook().getAuthor());
bean.setShortIntro(getBook().getDescription());
bean.setCover(getBook().getCover());
bean.setInclude_image(getBook().getInclude_image());
// bean.setHasCp(getBook().isHasCp());
// bean.setLatelyFollower(getBook().getLatelyFollower());
// bean.setRetentionRatio(Double.parseDouble(getBook().getRetentionRatio()));
if (getLast_article()!=null){
bean.setUpdated(String.valueOf(getLast_article().getCreate_time()));
bean.setLastChapter(getLast_article().getTitle());
}
// bean.setChaptersCount(getBook().getChaptersCount());
return bean;
}
}

@ -0,0 +1,57 @@
package com.novel.read.model.protocol;
import com.novel.read.base.MyApp;
import com.novel.read.utlis.StringUtils;
import java.io.Serializable;
import java.util.List;
public class CategoryTypeResp implements Serializable {
private List<CategoryBean> category;
public List<CategoryBean> getCategory() {
return category;
}
public void setCategory(List<CategoryBean> category) {
this.category = category;
}
public static class CategoryBean {
/**
* id : 1
* title : 玄幻奇幻
* cover :
*/
private int id;
private String title;
private String cover;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getTitle() {
return StringUtils.convertCC(title == null ? "" : title, MyApp.getContext());
}
public void setTitle(String title) {
this.title = title;
}
public String getCover() {
return cover;
}
public void setCover(String cover) {
this.cover = cover;
}
}
}

@ -0,0 +1,21 @@
package com.novel.read.model.protocol;
import com.novel.read.model.db.ChapterInfoBean;
import java.io.Serializable;
import java.util.List;
public class ChapterInfoPackage implements Serializable {
private List<ChapterInfoBean> article;
public List<ChapterInfoBean> getArticle() {
return article;
}
public void setArticle(List<ChapterInfoBean> article) {
this.article = article;
}
}

@ -0,0 +1,18 @@
package com.novel.read.model.protocol;
import java.io.Serializable;
import java.util.List;
public class HotSearchResp implements Serializable {
private List<String> key;
public List<String> getKey() {
return key;
}
public void setKey(List<String> key) {
this.key = key;
}
}

@ -0,0 +1,120 @@
package com.novel.read.model.protocol;
import java.util.List;
public class MarkResp {
private List<SignBean> sign;
public List<SignBean> getSign() {
return sign;
}
public void setSign(List<SignBean> sign) {
this.sign = sign;
}
public static class SignBean {
/**
* id : 8
* uid : 1
* book_id : 1
* article_id : 1
* words : 0
* create_time : 1561450031
* update_time : 1561450031
* delete_time : null
*/
private int id;
private int uid;
private int book_id;
private int article_id;
private int words;
private int create_time;
private int update_time;
private Object delete_time;
private String content;
private boolean edit;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getUid() {
return uid;
}
public void setUid(int uid) {
this.uid = uid;
}
public int getBook_id() {
return book_id;
}
public void setBook_id(int book_id) {
this.book_id = book_id;
}
public int getArticle_id() {
return article_id;
}
public void setArticle_id(int article_id) {
this.article_id = article_id;
}
public int getWords() {
return words;
}
public void setWords(int words) {
this.words = words;
}
public int getCreate_time() {
return create_time;
}
public void setCreate_time(int create_time) {
this.create_time = create_time;
}
public int getUpdate_time() {
return update_time;
}
public void setUpdate_time(int update_time) {
this.update_time = update_time;
}
public Object getDelete_time() {
return delete_time;
}
public void setDelete_time(Object delete_time) {
this.delete_time = delete_time;
}
public String getContent() {
return content == null ? "" : content;
}
public void setContent(String content) {
this.content = content;
}
public boolean isEdit() {
return edit;
}
public void setEdit(boolean edit) {
this.edit = edit;
}
}
}

@ -0,0 +1,115 @@
package com.novel.read.model.protocol;
import com.novel.read.base.MyApp;
import com.novel.read.utlis.StringUtils;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
/**
* create by 赵利君 on 2019/6/20
* describe:
*/
public class RankByUpadateResp implements Serializable {
private List<BookBean> book;
public List<BookBean> getBook() {
if (book == null) {
return new ArrayList<>();
}
return book;
}
public void setBook(List<BookBean> book) {
this.book = book;
}
public static class BookBean {
/**
* id : 2446
* title : 吞天记
* cover : http://api.duoduvip.com/uploads/nocover.jpg
* description : &#160;&#160;&#160;&#160;炎黄古域浩瀚无边无尽岁月中诞生诸多太古仙妖撕裂天地脱三界五行更有万物神灵天生神体穿梭虚空逆乱阴阳无所不能<br>&#160;&#160;&#160;&#160;当今乃仙道盛世万法通天众生修道妖孽横行<br>&#160;&#160;&#160;&#160;东吴太子吴煜于绝境中得东方绝世战仙之衣钵自此横空出世逆天崛起<br>&#160;&#160;&#160;&#160;亿万世人心中他是普渡众生的帝仙<br>&#160;&#160;&#160;&#160;漫天仙佛眼中他是吞噬天地的妖魔<br>&#160;&#160;&#160;&#160;<br>&#160;&#160;&#160;&#160;想和作者探讨剧情加入讨论群请加我微信fengqingyang17k或搜风青阳<br>&#160;&#160;&#160;&#160;各位书友要是觉得吞天记还不错的话请不要忘记向您QQ群和微博里的朋友推荐哦吞天记最新章节,吞天记无弹窗,吞天记全文阅读.
* hot : 41926
* like : 65
* author : 风青阳
* create_time : 1561001132
*/
private int id;
private String title;
private String cover;
private String description;
private int hot;
private int like;
private String author;
private int create_time;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getTitle() {
return title == null ? "" : StringUtils.convertCC(title, MyApp.getContext());
}
public void setTitle(String title) {
this.title = title;
}
public String getCover() {
return cover;
}
public void setCover(String cover) {
this.cover = cover;
}
public String getDescription() {
return description == null ? "" : StringUtils.convertCC(StringUtils.delete160(description), MyApp.getContext());
}
public void setDescription(String description) {
this.description = description;
}
public int getHot() {
return hot;
}
public void setHot(int hot) {
this.hot = hot;
}
public int getLike() {
return like;
}
public void setLike(int like) {
this.like = like;
}
public String getAuthor() {
return author == null ? "" :StringUtils.convertCC(author, MyApp.getContext());
}
public void setAuthor(String author) {
this.author = author;
}
public int getCreate_time() {
return create_time;
}
public void setCreate_time(int create_time) {
this.create_time = create_time;
}
}
}

@ -0,0 +1,112 @@
package com.novel.read.model.protocol;
import com.novel.read.base.MyApp;
import com.novel.read.utlis.StringUtils;
import java.io.Serializable;
import java.util.List;
/**
* create by 赵利君 on 2019/6/18
* describe:
*/
public class RecommendBookResp implements Serializable {
private List<BookBean> book;
public List<BookBean> getBook() {
return book;
}
public void setBook(List<BookBean> book) {
this.book = book;
}
public static class BookBean {
/**
* id : 139
* title : 丹师剑宗
* cover : http://dev.duoduvip.com/uploads/20190611/b81d831d3310041846444dacca57cef9.png
* description :
* hot : 83146
* like : 64
* author : 伯爵
* create_time : 1560191131
*/
private int id;
private String title;
private String cover;
private String description;
private int hot;
private int like;
private String author;
private int create_time;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getTitle() {
return title == null ? "" : StringUtils.convertCC(title, MyApp.getContext());
}
public void setTitle(String title) {
this.title = title;
}
public String getCover() {
return cover;
}
public void setCover(String cover) {
this.cover = cover;
}
public String getDescription() {
return description == null ? "" : StringUtils.convertCC(StringUtils.delete160(description), MyApp.getContext());
}
public void setDescription(String description) {
this.description = description;
}
public int getHot() {
return hot;
}
public void setHot(int hot) {
this.hot = hot;
}
public int getLike() {
return like;
}
public void setLike(int like) {
this.like = like;
}
public String getAuthor() {
return author == null ? "" : StringUtils.convertCC(author, MyApp.getContext()) ;
}
public void setAuthor(String author) {
this.author = author;
}
public int getCreate_time() {
return create_time;
}
public void setCreate_time(int create_time) {
this.create_time = create_time;
}
}
}

@ -0,0 +1,167 @@
package com.novel.read.model.protocol;
import com.novel.read.base.MyApp;
import com.novel.read.utlis.StringUtils;
import java.io.Serializable;
import java.util.List;
/**
* create by 赵利君 on 2019/6/19
* describe:
*/
public class RecommendListResp implements Serializable {
private List<ListBean> list;
public List<ListBean> getList() {
return list;
}
public void setList(List<ListBean> list) {
this.list = list;
}
public static class ListBean {
/**
* id : 5
* book_id : 10
* type : 1
* gender : 1
* sort : 10
* create_time : 1560129944
* update_time : 1560129944
* delete_time : null
* book_title : 重生之末世宝典
* book_cover : http://api.duoduvip.com/uploads/nocover.jpg
*/
private int id;
private int book_id;
private int type;
private int gender;
private int sort;
private int create_time;
private int update_time;
private Object delete_time;
private String book_title;
private String book_cover;
private String author;
private String description;
private int hot;
private int like;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getBook_id() {
return book_id;
}
public void setBook_id(int book_id) {
this.book_id = book_id;
}
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
public int getGender() {
return gender;
}
public void setGender(int gender) {
this.gender = gender;
}
public int getSort() {
return sort;
}
public void setSort(int sort) {
this.sort = sort;
}
public int getCreate_time() {
return create_time;
}
public void setCreate_time(int create_time) {
this.create_time = create_time;
}
public int getUpdate_time() {
return update_time;
}
public void setUpdate_time(int update_time) {
this.update_time = update_time;
}
public Object getDelete_time() {
return delete_time;
}
public void setDelete_time(Object delete_time) {
this.delete_time = delete_time;
}
public String getBook_title() {
return book_title == null ? "" : StringUtils.convertCC(book_title, MyApp.getContext());
}
public void setBook_title(String book_title) {
this.book_title = book_title;
}
public String getBook_cover() {
return book_cover == null ? "" : book_cover;
}
public void setBook_cover(String book_cover) {
this.book_cover = book_cover;
}
public String getAuthor() {
return author == null ? "" : StringUtils.convertCC(author, MyApp.getContext());
}
public void setAuthor(String author) {
this.author = author;
}
public String getDescription() {
return description == null ? "" : StringUtils.convertCC(StringUtils.delete160(description), MyApp.getContext());
}
public void setDescription(String description) {
this.description = description;
}
public String getHot() {
return String.valueOf(hot);
}
public void setHot(int hot) {
this.hot = hot;
}
public String getLike() {
return like+"%";
}
public void setLike(int like) {
this.like = like;
}
}
}

@ -0,0 +1,135 @@
package com.novel.read.model.protocol;
import com.novel.read.base.MyApp;
import com.novel.read.utlis.StringUtils;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
public class SearchResp implements Serializable {
/**
* book : [{"id":92,"title":"极品全能狂少","category_id":3,"cover":"http://dev.duoduvip.com/uploads/20190610/64512ebcd7e79923bc59ffc1d3afb597.png","description":"","hot":99437,"like":41,"author":"一支烟的快感","create_time":1560159443},{"id":170,"title":"抬棺匠","category_id":1,"cover":"http://dev.duoduvip.com/uploads/20190611/19cfa1ff96a4bec66b14e16b997ffba9.png","description":"","hot":99184,"like":54,"author":"陈八仙","create_time":1560205316},{"id":47,"title":"都市超级医圣","category_id":3,"cover":"http://dev.duoduvip.com/uploads/20190610/868b69fdf75dc303ca70fef4ccc8bc87.png","description":" 财法侣地,修行其实是一项非常耗钱的奢侈运动。无意中得到传说中道教学家,炼丹家,医药家葛洪的传承,淳朴的山里人葛东旭开始努力赚钱。当大多数人还在读高中时,他为了炼丹修行已经开始一边读书一边赚钱。当大多数人读大学还在为交女朋友的开销愁时,他已经是一名老板。当大多数人大学毕业在为找工作四处投简历,当富二代开着跑车,在美女面前炫耀时,他已经是一名级富一代,当然还是一名大隐隐于市的至尊医圣。<br> 各位书友要是觉得《都市超级医圣》还不错的话请不要忘记向您QQ群和微博里的朋友推荐哦!都市超级医圣最新章节,都市超级医圣无弹窗,都市超级医圣全文阅读.","hot":99056,"like":21,"author":"断桥残雪","create_time":1560129236},{"id":105,"title":"神医高手在都市","category_id":3,"cover":"http://dev.duoduvip.com/uploads/20190610/ccab1913cdaf9aee2cfeaef84910a700.png","description":"","hot":98517,"like":28,"author":"复仇","create_time":1560167691},{"id":21,"title":"夜少的心尖宝贝","category_id":1,"cover":"http://dev.duoduvip.com/uploads/20190609/c0f5c2ff7fa532e4bd399625e5edacf3.png","description":" 简介:<br> 为了能正大光明的睡乔小姐,夜少不惜采用了108种追妻方式结果有两个小萝卜头冒了出来,对他说,\u201c帅叔叔,你想追我妈咪吗我们可以教你哦\u201d夜少掀桌,\u201c叫什么叔叔乖,叫爹地\u201d夜少一生最风光得意的事情就是睡了乔小姐,留下了种,让她给自己生了两个宝贝儿子,在她的身上永恒的打上了自己的烙印夜少漫漫追妻之旅,甜甜甜,超甜宠文,1v1<br> 各位书友要是觉得《夜少的心尖宝贝》还不错的话请不要忘记向您QQ群和微博里的朋友推荐哦!夜少的心尖宝贝最新章节,夜少的心尖宝贝无弹窗,夜少的心尖宝贝全文阅读.","hot":97296,"like":64,"author":"慕欢颜","create_time":1560095819},{"id":102,"title":"万域灵神","category_id":4,"cover":"http://dev.duoduvip.com/uploads/20190610/847703596e2af187311bb9f5ab7c26b4.png","description":"","hot":97157,"like":56,"author":"乾多多","create_time":1560165904},{"id":87,"title":"至尊剑皇","category_id":4,"cover":"http://dev.duoduvip.com/uploads/20190610/711a87b0df3446885739845fba33fce4.png","description":"","hot":96684,"like":23,"author":"半步沧桑","create_time":1560156886},{"id":166,"title":"生活在美利坚的森林游侠","category_id":3,"cover":"http://dev.duoduvip.com/uploads/20190611/d663219f43a8bbba3d0718637fa0724a.png","description":"","hot":96427,"like":77,"author":"酱疙瘩","create_time":1560203771},{"id":171,"title":"三界红包群","category_id":3,"cover":"http://dev.duoduvip.com/uploads/nocover.jpg","description":"","hot":96362,"like":47,"author":"小教主","create_time":1560205922},{"id":131,"title":"命之途","category_id":2,"cover":"http://dev.duoduvip.com/uploads/nocover.jpg","description":"","hot":94835,"like":27,"author":"莫若梦兮","create_time":1560186387}]
* limit : 10
*/
private int limit;
private List<BookBean> book;
public int getLimit() {
return limit;
}
public void setLimit(int limit) {
this.limit = limit;
}
public List<BookBean> getBook() {
if (book == null) {
return new ArrayList<>();
}
return book;
}
public void setBook(List<BookBean> book) {
this.book = book;
}
public static class BookBean {
/**
* id : 92
* title : 极品全能狂少
* category_id : 3
* cover : http://dev.duoduvip.com/uploads/20190610/64512ebcd7e79923bc59ffc1d3afb597.png
* description :
* hot : 99437
* like : 41
* author : 一支烟的快感
* create_time : 1560159443
*/
private int id;
private String title;
private int category_id;
private String cover;
private String description;
private int hot;
private int like;
private String author;
private int create_time;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getTitle() {
return title == null ? "" : StringUtils.convertCC(title, MyApp.getContext());
}
public void setTitle(String title) {
this.title = title;
}
public int getCategory_id() {
return category_id;
}
public void setCategory_id(int category_id) {
this.category_id = category_id;
}
public String getCover() {
return cover;
}
public void setCover(String cover) {
this.cover = cover;
}
public String getDescription() {
return description == null ? "" : StringUtils.convertCC(StringUtils.delete160(description), MyApp.getContext());
}
public void setDescription(String description) {
this.description = description;
}
public int getHot() {
return hot;
}
public void setHot(int hot) {
this.hot = hot;
}
public int getLike() {
return like;
}
public void setLike(int like) {
this.like = like;
}
public String getAuthor() {
return author == null ? "" : StringUtils.convertCC(author, MyApp.getContext());
}
public void setAuthor(String author) {
this.author = author;
}
public int getCreate_time() {
return create_time;
}
public void setCreate_time(int create_time) {
this.create_time = create_time;
}
}
}

@ -0,0 +1,18 @@
package com.novel.read.model.protocol;
public class UidResp {
/**
* uid : 3
*/
private int uid;
public int getUid() {
return uid;
}
public void setUid(int uid) {
this.uid = uid;
}
}

@ -0,0 +1,138 @@
package com.novel.read.model.protocol;
/**
* create by 赵利君 on 2019/6/25
* describe:
*/
public class VersionResp {
/**
* version : {"id":2,"version":"1.0.0","size":"5096","content":"正式上线","download":"https://play.google.com/store/apps/details?id=com.freebook.bookreader","coerce":1,"status":1,"push_time":1560060702,"create_time":1560060772,"update_time":1560752842,"delete_time":null}
*/
private VersionBean version;
public VersionBean getVersion() {
return version;
}
public void setVersion(VersionBean version) {
this.version = version;
}
public static class VersionBean {
/**
* id : 2
* version : 1.0.0
* size : 5096
* content : 正式上线
* download : https://play.google.com/store/apps/details?id=com.freebook.bookreader
* coerce : 1
* status : 1
* push_time : 1560060702
* create_time : 1560060772
* update_time : 1560752842
* delete_time : null
*/
private int id;
private String version;
private String size;
private String content;
private String download;
private int coerce;
private int status;
private int push_time;
private int create_time;
private int update_time;
private Object delete_time;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
public String getSize() {
return size;
}
public void setSize(String size) {
this.size = size;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public String getDownload() {
return download;
}
public void setDownload(String download) {
this.download = download;
}
public int getCoerce() {
return coerce;
}
public void setCoerce(int coerce) {
this.coerce = coerce;
}
public int getStatus() {
return status;
}
public void setStatus(int status) {
this.status = status;
}
public int getPush_time() {
return push_time;
}
public void setPush_time(int push_time) {
this.push_time = push_time;
}
public int getCreate_time() {
return create_time;
}
public void setCreate_time(int create_time) {
this.create_time = create_time;
}
public int getUpdate_time() {
return update_time;
}
public void setUpdate_time(int update_time) {
this.update_time = update_time;
}
public Object getDelete_time() {
return delete_time;
}
public void setDelete_time(Object delete_time) {
this.delete_time = delete_time;
}
}
}

@ -0,0 +1,17 @@
package com.novel.read.service;
import com.mango.mangolib.event.BaseEvent;
/**
* Created by newbiechen on 17-5-10.
* 下载进度事件
*/
public class DownloadMessage extends BaseEvent {
public String message;
public DownloadMessage(String message){
this.message = message;
}
}

@ -0,0 +1,448 @@
package com.novel.read.service;
import android.content.Context;
import android.content.Intent;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.text.TextUtils;
import androidx.annotation.Nullable;
import com.mango.mangolib.event.EventManager;
import com.novel.read.R;
import com.novel.read.base.BaseService;
import com.novel.read.event.DeleteResponseEvent;
import com.novel.read.event.DeleteTaskEvent;
import com.novel.read.event.RxBus;
import com.novel.read.http.AccountManager;
import com.novel.read.model.db.BookChapterBean;
import com.novel.read.model.db.DownloadTaskBean;
import com.novel.read.model.db.dbManage.BookManager;
import com.novel.read.model.db.dbManage.BookRepository;
import com.novel.read.utlis.LocalManageUtil;
import com.novel.read.utlis.LogUtils;
import com.novel.read.utlis.NetworkUtils;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
/**
* Created by newbiechen on 17-5-10.
*/
public class DownloadService extends BaseService {
private static final String TAG = "DownloadService";
//加载状态
private static final int LOAD_ERROR = -1;
private static final int LOAD_NORMAL = 0;
private static final int LOAD_PAUSE = 1;
private static final int LOAD_DELETE = 2; //正在加载时候,用户删除收藏书籍的情况。
//下载状态
public static final int STATUS_CONTINUE = DownloadTaskBean.STATUS_LOADING;
public static final int STATUS_PAUSE = DownloadTaskBean.STATUS_PAUSE;
//线程池
private final ExecutorService mSingleExecutor = Executors.newSingleThreadExecutor();
//加载队列
private final List<DownloadTaskBean> mDownloadTaskQueue = Collections.synchronizedList(new ArrayList<>());
//Handler
private Handler mHandler;
//包含所有的DownloadTask
private List<DownloadTaskBean> mDownloadTaskList;
private OnDownloadListener mDownloadListener;
private boolean isBusy = false;
private boolean isCancel = false;
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(LocalManageUtil.setLocal(base));
}
@Override
public void onCreate() {
super.onCreate();
mHandler = new Handler(getMainLooper());
//从数据库中获取所有的任务
mDownloadTaskList = BookRepository
.getInstance()
.getDownloadTaskList();
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return new TaskBuilder();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
//接受创建的DownloadTask
Disposable disposable = RxBus.getInstance()
.toObservable(DownloadTaskBean.class)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
(event) -> {
//判断任务是否为轮询标志
//判断任务是否存在,并修改任务
if (TextUtils.isEmpty(event.getBookId()) || !checkAndAlterDownloadTask(event)) {
addToExecutor(event);
}
}
);
addDisposable(disposable);
//是否删除数据的问题
Disposable deleteDisp = RxBus.getInstance()
.toObservable(DeleteTaskEvent.class)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
(event) -> {
//判断是否该数据存在加载列表中
boolean isDelete = true;
for (DownloadTaskBean bean : mDownloadTaskQueue) {
if (bean.getBookId().equals(event.collBook.getId())) {
isDelete = false;
break;
}
}
//如果不存在则删除List中的task
if (isDelete) {
//
Iterator<DownloadTaskBean> taskIt = mDownloadTaskList.iterator();
while (taskIt.hasNext()) {
DownloadTaskBean task = taskIt.next();
if (task.getBookId().equals(event.collBook.getId())) {
taskIt.remove();
}
}
}
//返回状态
RxBus.getInstance().post(new DeleteResponseEvent(isDelete, event.collBook));
}
);
addDisposable(deleteDisp);
return super.onStartCommand(intent, flags, startId);
}
/**
* 1. 查看是否任务已存在
* 2. 修改DownloadTask的 taskName list
*
* @return
*/
private boolean checkAndAlterDownloadTask(DownloadTaskBean newTask) {
boolean isExist = false;
for (DownloadTaskBean downloadTask : mDownloadTaskList) {
//如果不相同则不往下执行,往下执行都是存在相同的情况
if (!downloadTask.getTaskName().equals(newTask.getTaskName())) continue;
if (downloadTask.getStatus() == DownloadTaskBean.STATUS_FINISH) {
//判断是否newTask是已完成
if (downloadTask.getLastChapter() == newTask.getLastChapter()) {
isExist = true;
//发送回去已缓存
postMessage(getString(R.string.cached));
}
//判断,是否已完成的章节的起始点比新Task大,如果更大则表示新Task中的该章节已被加载,所以需要剪切
else if (downloadTask.getLastChapter() > (newTask.getLastChapter() - newTask.getBookChapterList().size())) {
if (downloadTask.getLastChapter() > newTask.getLastChapter()) {
isExist = true;
//发送回去已缓存
postMessage(getString(R.string.cached));
} else {
//删除掉已经完成的章节
List<BookChapterBean> remainChapterBeans = newTask.getBookChapterList().subList(downloadTask.getLastChapter(), newTask.getLastChapter());
String taskName = newTask.getTaskName()
+ getString(R.string.nb_download_chapter_scope,
downloadTask.getLastChapter(), newTask.getLastChapter());
//重置任务
newTask.setBookChapters(remainChapterBeans);
newTask.setTaskName(taskName);
//发送添加到任务的提示
postMessage(getString(R.string.cache_success));
}
}
}
//表示该任务已经在 下载、等待、暂停、网络错误中
else {
isExist = true;
//发送回去:已经在加载队列中。
postMessage(getString(R.string.task_exist));
}
}
//重置名字
if (!isExist) {
String taskName = newTask.getTaskName()
+ getString(R.string.nb_download_chapter_scope,
1, newTask.getLastChapter());
newTask.setTaskName(taskName);
postMessage(getString(R.string.cache_success));
}
return isExist;
}
private void addToExecutor(DownloadTaskBean taskEvent) {
//判断是否为轮询请求
if (!TextUtils.isEmpty(taskEvent.getBookId())) {
if (!mDownloadTaskList.contains(taskEvent)) {
//加入总列表中,表示创建,修改CollBean的状态。
mDownloadTaskList.add(taskEvent);
}
// 添加到下载队列
mDownloadTaskQueue.add(taskEvent);
}
// 从队列顺序取出第一条下载
if (mDownloadTaskQueue.size() > 0 && !isBusy) {
isBusy = true;
executeTask(mDownloadTaskQueue.get(0));
}
}
private void executeTask(DownloadTaskBean taskEvent) {
Runnable runnable = () -> {
taskEvent.setStatus(DownloadTaskBean.STATUS_LOADING);
int result = LOAD_NORMAL;
List<BookChapterBean> bookChapterBeans = taskEvent.getBookChapters();
//调用for循环,下载数据 //todo
// for (int i=taskEvent.getCurrentChapter(); i<bookChapterBeans.size();++i) {
for (int i = taskEvent.getCurrentChapter(); i <= taskEvent.getLastChapter() && i < bookChapterBeans.size(); ++i) {
BookChapterBean bookChapterBean = bookChapterBeans.get(i);
//首先判断该章节是否曾经被加载过 (从文件中判断)
if (BookManager.isChapterCached(taskEvent.getBookId(), bookChapterBean.getTitle())) {
//设置任务进度
taskEvent.setCurrentChapter(i);
//章节加载完成
postDownloadChange(taskEvent, DownloadTaskBean.STATUS_LOADING, i + "");
//无需进行下一步
continue;
}
//判断网络是否出问题
if (!NetworkUtils.isAvailable()) {
//章节加载失败
result = LOAD_ERROR;
break;
}
if (isCancel) {
result = LOAD_PAUSE;
isCancel = false;
break;
}
//加载数据
result = loadChapter(taskEvent.getBookId(), bookChapterBean);
//章节加载完成
if (result == LOAD_NORMAL) {
taskEvent.setCurrentChapter(i);
postDownloadChange(taskEvent, DownloadTaskBean.STATUS_LOADING, i + "");
}
//章节加载失败
else {
//遇到错误退出
break;
}
}
if (result == LOAD_NORMAL) {
//存储DownloadTask的状态
taskEvent.setStatus(DownloadTaskBean.STATUS_FINISH);//Task的状态
taskEvent.setCurrentChapter(taskEvent.getBookChapters().size());//当前下载的章节数量
taskEvent.setSize(BookManager.getBookSize(taskEvent.getBookId()));//Task的大小
//发送完成状态
postDownloadChange(taskEvent, DownloadTaskBean.STATUS_FINISH, getString(R.string.download_success));
} else if (result == LOAD_ERROR) {
taskEvent.setStatus(DownloadTaskBean.STATUS_ERROR);//Task的状态
//任务加载失败
postDownloadChange(taskEvent, DownloadTaskBean.STATUS_ERROR, getString(R.string.download_error));
} else if (result == LOAD_PAUSE) {
taskEvent.setStatus(DownloadTaskBean.STATUS_PAUSE);//Task的状态
postDownloadChange(taskEvent, DownloadTaskBean.STATUS_PAUSE, getString(R.string.download_pause));
} else if (result == LOAD_DELETE) {
//没想好怎么做
}
//存储状态
BookRepository.getInstance().saveDownloadTask(taskEvent);
//轮询下一个事件,用RxBus用来保证事件是在主线程
//移除完成的任务
mDownloadTaskQueue.remove(taskEvent);
//设置为空闲
isBusy = false;
//轮询
post(new DownloadTaskBean());
};
mSingleExecutor.execute(runnable);
}
private int loadChapter(String folderName, BookChapterBean bean) {
//加载的结果参数
final int[] result = {LOAD_NORMAL};
//问题:(这里有个问题,就是body其实比较大,如何获取数据流而不是对象,)是不是直接使用OkHttpClient交互会更好一点
Disposable disposable = AccountManager.getInstance()
.getChapterInfo(bean.getId())
//表示在当前环境下执行
.subscribe(
chapterInfo -> {
//TODO:这里文件的名字用的是BookChapter的title,而不是chapter的title。
//原因是Chapter的title可能重复,但是BookChapter的title不会重复
//BookChapter的title = 卷名 + 章节名 chapter 的 title 就是章节名。。
BookRepository.getInstance().saveChapterInfo(folderName, bean.getTitle(), chapterInfo.getBody());
},
e -> {
//当前进度加载错误(这里需要判断是什么问题,根据相应的问题做出相应的回答)
LogUtils.e(e);
//设置加载结果
result[0] = LOAD_ERROR;
}
);
addDisposable(disposable);
return result[0];
}
private void postDownloadChange(DownloadTaskBean task, int status, String msg) {
if (mDownloadListener != null && msg != null) {
int position = mDownloadTaskList.indexOf(task);
//通过handler,切换回主线程
mHandler.post(() -> mDownloadListener.onDownloadChange(
position, status, msg)
);
}
}
private void postMessage(String msg) {
// RxBus.getInstance().post(new DownloadMessage(msg));
EventManager.Companion.getInstance().postEvent(new DownloadMessage(msg));
}
private void post(DownloadTaskBean task) {
RxBus.getInstance().post(task);
}
@Override
public boolean onUnbind(Intent intent) {
mDownloadListener = null;
return super.onUnbind(intent);
}
class TaskBuilder extends Binder implements IDownloadManager {
@Override
public List<DownloadTaskBean> getDownloadTaskList() {
return Collections.unmodifiableList(mDownloadTaskList);
}
@Override
public void setOnDownloadListener(OnDownloadListener listener) {
mDownloadListener = listener;
}
@Override
public void setDownloadStatus(String taskName, int status) {
//修改某个Task的状态
switch (status) {
//加入缓存队列
case DownloadTaskBean.STATUS_WAIT:
for (int i = 0; i < mDownloadTaskList.size(); ++i) {
DownloadTaskBean bean = mDownloadTaskList.get(i);
if (taskName.equals(bean.getTaskName())) {
bean.setStatus(DownloadTaskBean.STATUS_WAIT);
mDownloadListener.onDownloadResponse(i, DownloadTaskBean.STATUS_WAIT);
addToExecutor(bean);
break;
}
}
break;
//从缓存队列中删除
case DownloadTaskBean.STATUS_PAUSE:
Iterator<DownloadTaskBean> it = mDownloadTaskQueue.iterator();
while (it.hasNext()) {
DownloadTaskBean bean = it.next();
if (bean.getTaskName().equals(taskName)) {
if (bean.getStatus() == DownloadTaskBean.STATUS_LOADING
&& bean.getTaskName().equals(taskName)) {
isCancel = true;
break;
} else {
bean.setStatus(DownloadTaskBean.STATUS_PAUSE);
mDownloadTaskQueue.remove(bean);
int position = mDownloadTaskList.indexOf(bean);
mDownloadListener.onDownloadResponse(position, DownloadTaskBean.STATUS_PAUSE);
break;
}
}
}
break;
}
}
@Override
public void setAllDownloadStatus(int status) {
//修改所有Task的状态
}
//首先判断是否在加载队列中。
//如果在加载队列中首先判断是否正在下载,
//然后判断是否在完成队列中。
}
@Override
public void onDestroy() {
super.onDestroy();
}
public interface IDownloadManager {
List<DownloadTaskBean> getDownloadTaskList();
void setOnDownloadListener(OnDownloadListener listener);
void setDownloadStatus(String taskName, int status);
void setAllDownloadStatus(int status);
}
public interface OnDownloadListener {
/**
* @param pos : Task在item中的位置
* @param status : Task的状态
* @param msg: 传送的Msg
*/
void onDownloadChange(int pos, int status, String msg);
/**
* 回复
*/
void onDownloadResponse(int pos, int status);
}
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save