新增书架分组

pull/5/head
fengyuecanzhu 4 years ago
parent 31c16a6004
commit 36a2647ccb
  1. 37
      .idea/assetWizardSettings.xml
  2. BIN
      .idea/caches/build_file_checksums.ser
  3. 4
      .idea/modules.xml
  4. 55
      .idea/navEditor.xml
  5. 7
      app/build.gradle
  6. 13
      app/src/main/AndroidManifest.xml
  7. 10
      app/src/main/assets/_csrfToken.fy
  8. 10
      app/src/main/assets/fonts/_csrfToken.fy
  9. 29
      app/src/main/assets/updatelog.fy
  10. 18
      app/src/main/java/xyz/fycz/myreader/ActivityManage.java
  11. 73
      app/src/main/java/xyz/fycz/myreader/application/MyApplication.java
  12. 5
      app/src/main/java/xyz/fycz/myreader/application/SysManager.java
  13. 6
      app/src/main/java/xyz/fycz/myreader/backup/BackupAndRestore.java
  14. 63
      app/src/main/java/xyz/fycz/myreader/base/BaseActivity2.java
  15. 2
      app/src/main/java/xyz/fycz/myreader/base/BaseFragment.java
  16. 7
      app/src/main/java/xyz/fycz/myreader/common/APPCONST.java
  17. 9
      app/src/main/java/xyz/fycz/myreader/common/URLCONST.java
  18. 8
      app/src/main/java/xyz/fycz/myreader/creator/APPDownloadTip.java
  19. 50
      app/src/main/java/xyz/fycz/myreader/creator/ChangeSourceDialog.java
  20. 49
      app/src/main/java/xyz/fycz/myreader/creator/DialogCreator.java
  21. 10
      app/src/main/java/xyz/fycz/myreader/creator/MultiChoiceDialog.java
  22. 15
      app/src/main/java/xyz/fycz/myreader/creator/MyAlertDialog.java
  23. 10
      app/src/main/java/xyz/fycz/myreader/entity/Setting.java
  24. 80
      app/src/main/java/xyz/fycz/myreader/entity/bookstore/QDBook.java
  25. 38
      app/src/main/java/xyz/fycz/myreader/entity/bookstore/RankBook.java
  26. 27
      app/src/main/java/xyz/fycz/myreader/entity/bookstore/SortBook.java
  27. 10
      app/src/main/java/xyz/fycz/myreader/enums/BookSource.java
  28. 40
      app/src/main/java/xyz/fycz/myreader/enums/FindType.java
  29. 39
      app/src/main/java/xyz/fycz/myreader/greendao/entity/Book.java
  30. 70
      app/src/main/java/xyz/fycz/myreader/greendao/entity/BookGroup.java
  31. 77
      app/src/main/java/xyz/fycz/myreader/greendao/service/BookGroupService.java
  32. 60
      app/src/main/java/xyz/fycz/myreader/greendao/service/BookMarkService.java
  33. 88
      app/src/main/java/xyz/fycz/myreader/greendao/service/BookService.java
  34. 2
      app/src/main/java/xyz/fycz/myreader/greendao/util/MySQLiteOpenHelper.java
  35. 104
      app/src/main/java/xyz/fycz/myreader/ui/activity/AboutActivity.java
  36. 34
      app/src/main/java/xyz/fycz/myreader/ui/activity/BookDetailedActivity.java
  37. 420
      app/src/main/java/xyz/fycz/myreader/ui/activity/BookstoreActivity.java
  38. 138
      app/src/main/java/xyz/fycz/myreader/ui/activity/CatalogActivity.java
  39. 2
      app/src/main/java/xyz/fycz/myreader/ui/activity/FileSystemActivity.java
  40. 154
      app/src/main/java/xyz/fycz/myreader/ui/activity/FontsActivity.java
  41. 197
      app/src/main/java/xyz/fycz/myreader/ui/activity/LoginActivity.java
  42. 319
      app/src/main/java/xyz/fycz/myreader/ui/activity/MainActivity.java
  43. 127
      app/src/main/java/xyz/fycz/myreader/ui/activity/MoreSettingActivity.java
  44. 7
      app/src/main/java/xyz/fycz/myreader/ui/activity/ReadActivity.java
  45. 265
      app/src/main/java/xyz/fycz/myreader/ui/activity/RegisterActivity.java
  46. 405
      app/src/main/java/xyz/fycz/myreader/ui/activity/SearchBookActivity.java
  47. 5
      app/src/main/java/xyz/fycz/myreader/ui/adapter/BookMarkAdapter.java
  48. 151
      app/src/main/java/xyz/fycz/myreader/ui/adapter/BookStoreBookAdapter.java
  49. 10
      app/src/main/java/xyz/fycz/myreader/ui/adapter/BookStoreBookTypeAdapter.java
  50. 128
      app/src/main/java/xyz/fycz/myreader/ui/adapter/BookcaseAdapter.java
  51. 35
      app/src/main/java/xyz/fycz/myreader/ui/adapter/BookcaseDetailedAdapter.java
  52. 29
      app/src/main/java/xyz/fycz/myreader/ui/adapter/BookcaseDragAdapter.java
  53. 5
      app/src/main/java/xyz/fycz/myreader/ui/adapter/ChapterTitleAdapter.java
  54. 4
      app/src/main/java/xyz/fycz/myreader/ui/adapter/FontsAdapter.java
  55. 54
      app/src/main/java/xyz/fycz/myreader/ui/adapter/TabFragmentPageAdapter.java
  56. 82
      app/src/main/java/xyz/fycz/myreader/ui/adapter/holder/BookStoreBookHolder.java
  57. 36
      app/src/main/java/xyz/fycz/myreader/ui/fragment/BookStoreFragment.java
  58. 35
      app/src/main/java/xyz/fycz/myreader/ui/fragment/BookcaseFragment.java
  59. 57
      app/src/main/java/xyz/fycz/myreader/ui/fragment/FindFragment.java
  60. 397
      app/src/main/java/xyz/fycz/myreader/ui/fragment/MineFragment.java
  61. 62
      app/src/main/java/xyz/fycz/myreader/ui/presenter/AboutPresenter.java
  62. 6
      app/src/main/java/xyz/fycz/myreader/ui/presenter/BookMarkPresenter.java
  63. 180
      app/src/main/java/xyz/fycz/myreader/ui/presenter/BookStorePresenter.java
  64. 577
      app/src/main/java/xyz/fycz/myreader/ui/presenter/BookcasePresenter.java
  65. 134
      app/src/main/java/xyz/fycz/myreader/ui/presenter/CatalogActivityPresenter.java
  66. 7
      app/src/main/java/xyz/fycz/myreader/ui/presenter/CatalogPresenter.java
  67. 118
      app/src/main/java/xyz/fycz/myreader/ui/presenter/FontsPresenter.java
  68. 137
      app/src/main/java/xyz/fycz/myreader/ui/presenter/LoginPresenter.java
  69. 134
      app/src/main/java/xyz/fycz/myreader/ui/presenter/MainPresenter.java
  70. 95
      app/src/main/java/xyz/fycz/myreader/ui/presenter/ReadPresenter.java
  71. 244
      app/src/main/java/xyz/fycz/myreader/ui/presenter/RegisterPresenter.java
  72. 354
      app/src/main/java/xyz/fycz/myreader/ui/presenter/SearchBookPrensenter.java
  73. 86
      app/src/main/java/xyz/fycz/myreader/util/HttpUtil.java
  74. 3
      app/src/main/java/xyz/fycz/myreader/util/notification/NotificationUtil.java
  75. 61
      app/src/main/java/xyz/fycz/myreader/util/utils/BlurTransformation.java
  76. 80
      app/src/main/java/xyz/fycz/myreader/util/utils/ColorUtil.java
  77. 2
      app/src/main/java/xyz/fycz/myreader/util/utils/FileUtils.java
  78. 18
      app/src/main/java/xyz/fycz/myreader/webapi/BookStoreApi.java
  79. 2
      app/src/main/java/xyz/fycz/myreader/webapi/CommonApi.java
  80. 6
      app/src/main/java/xyz/fycz/myreader/webapi/crawler/BiQuGe44ReadCrawler.java
  81. 35
      app/src/main/java/xyz/fycz/myreader/webapi/crawler/BiQuGeReadCrawler.java
  82. 6
      app/src/main/java/xyz/fycz/myreader/webapi/crawler/FYReadCrawler.java
  83. 23
      app/src/main/java/xyz/fycz/myreader/webapi/crawler/FindCrawler.java
  84. 6
      app/src/main/java/xyz/fycz/myreader/webapi/crawler/PinShuReadCrawler.java
  85. 6
      app/src/main/java/xyz/fycz/myreader/webapi/crawler/PinShuReadCrawler2.java
  86. 287
      app/src/main/java/xyz/fycz/myreader/webapi/crawler/QB5ReadCrawler.java
  87. 75
      app/src/main/java/xyz/fycz/myreader/webapi/crawler/QiDianRankList.java
  88. 1
      app/src/main/java/xyz/fycz/myreader/webapi/crawler/ReadCrawler.java
  89. 65
      app/src/main/java/xyz/fycz/myreader/webapi/crawler/ReadCrawlerUtil.java
  90. 7
      app/src/main/java/xyz/fycz/myreader/webapi/crawler/TianLaiReadCrawler.java
  91. 117
      app/src/main/java/xyz/fycz/myreader/webapi/crawler/find/ABC.java
  92. 8
      app/src/main/res/anim/fade_in.xml
  93. 8
      app/src/main/res/anim/fade_out.xml
  94. 5
      app/src/main/res/color/selector_bn.xml
  95. 4
      app/src/main/res/color/selector_btn_file_add.xml
  96. 6
      app/src/main/res/drawable-xhdpi/setting_style_blue_deep_circle.xml
  97. 6
      app/src/main/res/drawable-xhdpi/setting_style_breen_circle.xml
  98. 8
      app/src/main/res/drawable-xhdpi/setting_style_common_circle.xml
  99. 2
      app/src/main/res/drawable-xhdpi/setting_style_common_circle_selected.xml
  100. 6
      app/src/main/res/drawable-xhdpi/setting_style_leather_circle.xml
  101. Some files were not shown because too many files have changed in this diff Show More

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="WizardSettings">
<option name="children">
<map>
<entry key="imageWizard">
<value>
<PersistentState />
</value>
</entry>
<entry key="vectorWizard">
<value>
<PersistentState>
<option name="children">
<map>
<entry key="vectorAssetStep">
<value>
<PersistentState>
<option name="values">
<map>
<entry key="assetSourceType" value="FILE" />
<entry key="outputName" value="ic_group" />
<entry key="sourceFile" value="F:\SVG图标\分组.svg" />
</map>
</option>
</PersistentState>
</value>
</entry>
</map>
</option>
</PersistentState>
</value>
</entry>
</map>
</option>
</component>
</project>

@ -2,8 +2,8 @@
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/FYReader-master.iml" filepath="$PROJECT_DIR$/FYReader-master.iml" group="FYReader-master" />
<module fileurl="file://$PROJECT_DIR$/app/app.iml" filepath="$PROJECT_DIR$/app/app.iml" group="FYReader-master/app" />
<module fileurl="file://$PROJECT_DIR$/FYReader-master.iml" filepath="$PROJECT_DIR$/FYReader-master.iml" />
<module fileurl="file://$PROJECT_DIR$/.idea/modules/app/FYReader-master.app.iml" filepath="$PROJECT_DIR$/.idea/modules/app/FYReader-master.app.iml" />
</modules>
</component>
</project>

@ -0,0 +1,55 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="navEditor-manualLayoutAlgorithm2">
<option name="myPositions">
<map>
<entry key="mobile_navigation.xml">
<value>
<LayoutPositions>
<option name="myPositions">
<map>
<entry key="navigation_dashboard">
<value>
<LayoutPositions>
<option name="myPosition">
<Point>
<option name="x" value="256" />
<option name="y" value="12" />
</Point>
</option>
</LayoutPositions>
</value>
</entry>
<entry key="navigation_home">
<value>
<LayoutPositions>
<option name="myPosition">
<Point>
<option name="x" value="12" />
<option name="y" value="12" />
</Point>
</option>
</LayoutPositions>
</value>
</entry>
<entry key="navigation_notifications">
<value>
<LayoutPositions>
<option name="myPosition">
<Point>
<option name="x" value="12" />
<option name="y" value="368" />
</Point>
</option>
</LayoutPositions>
</value>
</entry>
</map>
</option>
</LayoutPositions>
</value>
</entry>
</map>
</option>
</component>
</project>

@ -99,10 +99,11 @@ dependencies {
implementation 'org.jsoup:jsoup:1.11.3'
//SmartRefreshLayout
implementation 'com.scwang.smartrefresh:SmartRefreshLayout:1.1.2'
implementation 'com.scwang.smartrefresh:SmartRefreshHeader:1.1.2'
implementation 'pl.droidsonroids.gif:android-gif-drawable:1.2.3'
implementation 'me.gujun.android.taggroup:library:1.4@aar'
@ -124,10 +125,12 @@ dependencies {
//
implementation 'net.ricecode:string-similarity:1.0.0'
implementation 'com.jayway.jsonpath:json-path:2.4.0'
}
greendao {
schemaVersion 11
schemaVersion 14
daoPackage 'xyz.fycz.myreader.greendao.gen'
// targetGenDir 'src/main/java'
}

@ -63,7 +63,7 @@
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher"
android:supportsRtl="true"
android:theme="@style/AppDayTheme"
android:theme="@style/MAppTheme"
android:requestLegacyExternalStorage="true"
android:networkSecurityConfig="@xml/network_security_config">
@ -72,6 +72,11 @@
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<meta-data
android:name="android.app.shortcuts"
android:resource="@xml/shortcuts" />
</activity>
@ -86,7 +91,8 @@
</provider>
<activity android:name=".ui.activity.MainActivity"
android:launchMode="singleTask"/>
android:launchMode="singleTask"
android:alwaysRetainTaskState="true"/>
<activity
android:name=".ui.activity.SearchBookActivity"
android:windowSoftInputMode="stateVisible"/>
@ -94,6 +100,7 @@
<activity
android:name=".ui.activity.ReadActivity"
android:launchMode="singleTask"
android:windowSoftInputMode="stateAlwaysHidden">
<intent-filter tools:ignore="AppLinkUrlError">
<action android:name="android.intent.action.VIEW" />
@ -101,7 +108,6 @@
<data android:mimeType="text/plain" />
</intent-filter>
</activity>
<activity android:name=".ui.activity.FontsActivity"/>
<activity android:name=".ui.activity.LoginActivity"/>
@ -115,6 +121,7 @@
<activity android:name=".ui.activity.FileSystemActivity"/>
<activity android:name=".ui.activity.MoreSettingActivity"/>
<activity android:name=".ui.activity.BookstoreActivity"/>
<receiver android:name=".util.notification.NotificationClickReceiver"/>
<receiver android:name=".ui.presenter.BookcasePresenter$cancelDownloadReceiver"/>

@ -0,0 +1,10 @@
_csrfToken=AfAoas8MBYmg6LNiXTCqRB4GqdvAIjLhoMhq0dMR; newstatisticUUID=1600428458_1590109905,
_csrfToken=JoeVbiYLyXUa1F1afAe7vopVMTCIAy9gjYjgs3vG; newstatisticUUID=1600428473_81078399,
_csrfToken=HrhdGbLO43Q1sqYB3fE2HFxTOgjA06Qb4tMdk4oP; newstatisticUUID=1600428493_975004371,
_csrfToken=ipGWAeoYVu786drUzlLunN24Z9aujs5nh5n9BRkO; newstatisticUUID=1600428519_644819972,
_csrfToken=XagcA1H7EuyKRlcCnYxBEXh96LdxehdF79bAshVq; newstatisticUUID=1600428535_1734949593,
_csrfToken=b6ZsEBvH8DizXhKHa7XG9s6kPN81vo0FujgQkBss; newstatisticUUID=1600428547_1240575899,
_csrfToken=AN09KVoEyMW1b7A2h0WICDw0iZRh10YJPHrPMyuF; newstatisticUUID=1600428559_1890659047,
_csrfToken=NPv5rB13eOhAw2PM5GKUbMCrpPXMHEozqs6fTIA7; newstatisticUUID=1600428572_110329628,
_csrfToken=it9IyUnSOXK7xC8fQXADlyrem8ZtGNKFSPt65kj1; newstatisticUUID=1600428591_1594511991,
_csrfToken=HJPozY5Rdj0Ij0HcyXT3L3VW3OLqeOQooCayuMLG; newstatisticUUID=1600428602_278088659

@ -0,0 +1,10 @@
_csrfToken=6aY1oV18xaiLFe342vi6RRTJ1CsuZ7PZPqz2Tl9A; newstatisticUUID=1600427331_759036854,
_csrfToken=PnRLboRVY2ag0eGbG3e3dA3X4B96SpihEkCDGle7; newstatisticUUID=1600427449_1941387289,
_csrfToken=Ia5w2vTL03IHyPKiS5PJFgocvzHWbMgi4dBEvrox; newstatisticUUID=1600427497_1599098587,
_csrfToken=GjyWEsVXIta60t4YXkbtO0hsDc2VVBbfKy6GIBRg; newstatisticUUID=1600427528_887702937,
_csrfToken=iPjMCVKGnvL8QrbsdYIxCDNQZkJVSscN1CQFFSdF; newstatisticUUID=1600427557_1213608979,
_csrfToken=Iby8oSKxp767d25frgCGjOAWFWbYwwyRA36nBaxO; newstatisticUUID=1600427589_1737201533,
_csrfToken=IR81KoIAQxXYb6e9Agv8WuXDkAKukMLnlLe9BYha; newstatisticUUID=1600427619_487685580,
_csrfToken=YM1F8lgqaePVMceunc7z7ndjys5ngAx5sYsemg60; newstatisticUUID=1600427643_2022665645,
_csrfToken=8bRnXJseSCajlTcG6lhyWOF0rWwDCiMVpCGvKvQj; newstatisticUUID=1600427644_1615074434,
_csrfToken=AehQ3WVD6wLbFGhFsnSW4DRF6BS1wqVvHU6PbiiX; newstatisticUUID=1600427644_575162687

@ -1,3 +1,32 @@
2020.09.26
风月读书v1.20.092617
1、新增书架自定义分组功能(点击编辑书架即可选择书籍加入指定分组[需要自行添加分组])
2、修复夜间模式下部分界面显示移除的bug
3、修复主题模式切换后菜单栏失效的bug
2020.09.19
风月读书v1.20.091922
1、优化全局UI
2、适配全局夜间模式
3、新增主题模式设置
4、新增发现界面(排行榜、分类、书城)
5、部分菜单移至"我的"界面
6、新增QQ反馈群(1085028304),可在"关于"界面加入QQ群
2020.09.07
风月读书v1.20.090722
1、新增书源"全本小说网(www.qb5.com)"
2、新增简易书城(实验版,默认开启,可在设置关闭)
3、新增换源后历史阅读章节智能匹配机制
4、新增设置界面
(1)阅读设置:音量键翻页、息屏时间
(2)书架设置:自动刷新、禁用更新
(3)搜索设置:禁用书源
(4)换源设置:历史章节智能匹配、智能匹配度
(5)缓存设置:章节缓存间隔、一键缓存、清除缓存
(6)其他设置:开启书城
注:因笔趣阁书源经常宕机,导致无法搜索到书籍,故默认禁用该书源
2020.08.24
风月读书v1.20.082422
1、重做书籍详情界面

@ -1,7 +1,9 @@
package xyz.fycz.myreader;
import android.app.Activity;
import androidx.appcompat.app.AppCompatActivity;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
/**
@ -9,7 +11,7 @@ import java.util.ArrayList;
*/
public class ActivityManage {
private static ArrayList<AppCompatActivity> activities = new ArrayList<AppCompatActivity>();
private static ArrayList<AppCompatActivity> activities = new ArrayList<>();
public static void addActivity(AppCompatActivity activity){
activities.add(activity);
@ -34,6 +36,18 @@ public class ActivityManage {
return activities.get(activities.size() - 1);
}
/**
* 判断指定Activity是否存在
*/
public static Boolean isExist(Class<?> activityClass) {
boolean result = false;
for (AppCompatActivity item : activities) {
if (null != item && item.getClass() == activityClass) {
result = true;
break;
}
}
return result;
}
}

@ -18,8 +18,10 @@ import android.os.Build;
import android.os.Environment;
import android.os.Handler;
import android.util.Log;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.app.AppCompatDelegate;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
@ -43,8 +45,10 @@ import xyz.fycz.myreader.creator.APPDownloadTip;
import xyz.fycz.myreader.creator.DialogCreator;
import xyz.fycz.myreader.entity.Setting;
import xyz.fycz.myreader.entity.UpdateInfo;
import xyz.fycz.myreader.ui.activity.MainActivity;
import xyz.fycz.myreader.ui.fragment.BookcaseFragment;
import xyz.fycz.myreader.util.*;
import xyz.fycz.myreader.util.utils.NetworkUtils;
public class MyApplication extends Application {
@ -66,7 +70,39 @@ public class MyApplication extends Application {
mFixedThreadPool = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());//初始化线程池
BaseActivity.setCloseAntiHijacking(true);
initNightTheme();
}
public void initNightTheme() {
if (isNightFS()){
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM);
}else {
if (isNightTheme()) {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
} else {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
}
}
}
protected boolean isNightTheme() {
return !SysManager.getSetting().isDayStyle();
}
public boolean isNightFS() {
return SharedPreUtils.getInstance().getBoolean("isNightFS", false);
}
/**
* 设置夜间模式
* @param isNightMode
*/
public void setNightTheme(boolean isNightMode) {
SharedPreUtils.getInstance().putBoolean("isNightFS", false);
Setting setting = SysManager.getSetting();
setting.setDayStyle(!isNightMode);
SysManager.saveSetting(setting);
MyApplication.getApplication().initNightTheme();
}
@SuppressLint("TrulyRandom")
@ -109,7 +145,7 @@ public class MyApplication extends Application {
try {
mFixedThreadPool.execute(runnable);
} catch (Exception e) {
e.printStackTrace();
//e.printStackTrace();
mFixedThreadPool = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());//初始化线程池
mFixedThreadPool.execute(runnable);
}
@ -244,7 +280,7 @@ public class MyApplication extends Application {
}
});
}*/
public static void checkVersionByServer(final BaseActivity activity, final boolean isManualCheck,
public static void checkVersionByServer(final AppCompatActivity activity, final boolean isManualCheck,
final BookcaseFragment mBookcaseFragment) {
MyApplication.getApplication().newThread(() -> {
Document doc = null;
@ -256,7 +292,9 @@ public class MyApplication extends Application {
doc = Jsoup.connect(url).get();
String content = doc.getElementsByClass("ql-editor").text();
if (StringHelper.isEmpty(content)) {
if (isManualCheck || NetworkUtils.isNetWorkAvailable()) {
ToastUtils.showError("检查更新失败!");
}
return;
}
String[] contents = content.split(";");
@ -282,6 +320,7 @@ public class MyApplication extends Application {
s.append("\n");
}
int versionCode = getVersionCode();
Log.i("检查更新,最新版本", newestVersion + "");
if (newestVersion > versionCode) {
MyApplication m = new MyApplication();
Setting setting = SysManager.getSetting();
@ -296,8 +335,11 @@ public class MyApplication extends Application {
}
} catch (Exception e) {
e.printStackTrace();
Log.e("检查更新失败!", e.getLocalizedMessage());
if (isManualCheck || NetworkUtils.isNetWorkAvailable()) {
ToastUtils.showError("检查更新失败!");
}
}
});
}
@ -307,7 +349,7 @@ public class MyApplication extends Application {
* @param activity
* @param versionCode
*/
public void updateApp(final BaseActivity activity, final String url, final int versionCode, String message,
public void updateApp(final AppCompatActivity activity, final String url, final int versionCode, String message,
final boolean isForceUpdate, final BookcaseFragment mBookcaseFragment) {
//String version = (versionCode / 100 % 10) + "." + (versionCode / 10 % 10) + "." + (versionCode % 10);
String cancelTitle;
@ -328,6 +370,10 @@ public class MyApplication extends Application {
activity.finish();
}
}, (dialog, which) -> {
if (activity instanceof MainActivity){
MainActivity mainActivity = (MainActivity) activity;
mainActivity.getViewPagerMain().setCurrentItem(0);
}
if (url == null || "".equals(url)) {
ToastUtils.showError("获取链接失败,请前往浏览器下载!");
Intent intent = new Intent();
@ -381,4 +427,25 @@ public class MyApplication extends Application {
return mActivity == null || mActivity.isFinishing() || mActivity.isDestroyed();
}
/****************
*
* 发起添加群流程群号风月读书交流群(1085028304) key 8PIOnHFuH6A38hgxvD_Rp2Bu-Ke1ToBn
* 调用 joinQQGroup(8PIOnHFuH6A38hgxvD_Rp2Bu-Ke1ToBn) 即可发起手Q客户端申请加群 风月读书交流群(1085028304)
*
* @param key 由官网生成的key
* @return 返回true表示呼起手Q成功返回false表示呼起失败
******************/
public static boolean joinQQGroup(Context context, String key) {
Intent intent = new Intent();
intent.setData(Uri.parse("mqqopensdkapi://bizAgent/qm/qr?url=http%3A%2F%2Fqm.qq.com%2Fcgi-bin%2Fqm%2Fqr%3Ffrom%3Dapp%26p%3Dandroid%26jump_from%3Dwebapi%26k%3D" + key));
// 此Flag可根据具体产品需要自定义,如设置,则在加群界面按返回,返回手Q主界面,不设置,按返回会返回到呼起产品界面 //intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
try {
context.startActivity(intent);
return true;
} catch (Exception e) {
// 未安装手Q或安装的版本不支持
return false;
}
}
}

@ -65,7 +65,8 @@ public class SysManager {
setting.setMatchChapter(true);
setting.setMatchChapterSuitability(0.7f);
setting.setCatheGap(150);
setting.setRefreshWhenStart(false);
setting.setRefreshWhenStart(true);
setting.setOpenBookStore(true);
setting.setSettingVersion(APPCONST.SETTING_VERSION);
return setting;
}
@ -79,6 +80,8 @@ public class SysManager {
Setting setting = getSetting();
setting.setVolumeTurnPage(true);
setting.setMatchChapter(true);
setting.setRefreshWhenStart(true);
setting.setOpenBookStore(true);
setting.setResetScreen(3);
setting.setSettingVersion(APPCONST.SETTING_VERSION);
saveSetting(setting);

@ -83,6 +83,7 @@ public class BackupAndRestore {
String source = "null";
boolean isCloseUpdate = false;
boolean isDownloadAll = true;
String group = "allBook";
if(!sBookFields[2].contains("novel.fycz.xyz")){
source = sBookFields[17];
}
@ -95,11 +96,14 @@ public class BackupAndRestore {
if (sBookFields.length >= 20){
isDownloadAll = Boolean.parseBoolean(sBookFields[19]);
}
if (sBookFields.length >= 21){
group = sBookFields[20];
}
Book book = new Book(sBookFields[0], sBookFields[1], sBookFields[2], sBookFields[3], sBookFields[4],
sBookFields[5], sBookFields[6], sBookFields[7], sBookFields[8], sBookFields[9], sBookFields[10],
sBookFields[11], Integer.parseInt(sBookFields[12]), Integer.parseInt(sBookFields[13]),
Integer.parseInt(sBookFields[14]), Integer.parseInt(sBookFields[15]), Integer.parseInt(sBookFields[16])
, source, isCloseUpdate, isDownloadAll);
, source, isCloseUpdate, isDownloadAll, group, 0);
books.add(book);
}
mBookService.deleteAllBooks();

@ -12,6 +12,7 @@ import androidx.annotation.LayoutRes;
import androidx.annotation.Nullable;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.app.AppCompatDelegate;
import androidx.appcompat.widget.Toolbar;
import butterknife.ButterKnife;
import butterknife.Unbinder;
@ -20,6 +21,9 @@ import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.disposables.Disposable;
import xyz.fycz.myreader.ActivityManage;
import xyz.fycz.myreader.R;
import xyz.fycz.myreader.application.MyApplication;
import xyz.fycz.myreader.application.SysManager;
import xyz.fycz.myreader.entity.Setting;
import xyz.fycz.myreader.util.StatusBarUtil;
import java.lang.reflect.Method;
@ -37,6 +41,8 @@ public abstract class BaseActivity2 extends AppCompatActivity {
private Toolbar mToolbar;
private Unbinder unbinder;
private int curNightMode;
/****************************abstract area*************************************/
@LayoutRes
@ -75,12 +81,32 @@ public abstract class BaseActivity2 extends AppCompatActivity {
*/
protected void processLogic(){
}
/**
* @return 是否夜间模式
*/
protected boolean isNightTheme() {
return !SysManager.getSetting().isDayStyle();
}
/**
* 设置夜间模式
* @param isNightMode
*/
protected void setNightTheme(boolean isNightMode) {
Setting setting = SysManager.getSetting();
setting.setDayStyle(!isNightMode);
MyApplication.getApplication().initNightTheme();
}
/*************************lifecycle area*****************************************************/
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initTheme();
ActivityManage.addActivity(this);
setContentView(getContentId());
initData(savedInstanceState);
@ -100,6 +126,13 @@ public abstract class BaseActivity2 extends AppCompatActivity {
}
}
@Override
protected void onResume() {
super.onResume();
if (isThemeChange()){
recreate();
}
}
@Override
protected void onDestroy() {
@ -110,7 +143,22 @@ public abstract class BaseActivity2 extends AppCompatActivity {
mDisposable.dispose();
}
}
/**
* 初始化主题
*/
public void initTheme() {
//if (isNightTheme()) {
//setTheme(R.style.AppNightTheme);
curNightMode = AppCompatDelegate.getDefaultNightMode();
/*} else {
//curNightMode = false;
//setTheme(R.style.AppDayTheme);
}*/
}
protected boolean isThemeChange(){
return curNightMode != AppCompatDelegate.getDefaultNightMode();
}
/**************************used method area*******************************************/
protected void startActivity(Class<? extends AppCompatActivity> activity){
@ -148,6 +196,19 @@ public abstract class BaseActivity2 extends AppCompatActivity {
StatusBarUtil.setStatusBarColor(this, 0x55000000);
}
}
} /**
* 设置MENU图标颜色
*/
@Override
public boolean onCreateOptionsMenu(Menu menu) {
for (int i = 0; i < menu.size(); i++) {
Drawable drawable = menu.getItem(i).getIcon();
if (drawable != null) {
drawable.mutate();
drawable.setColorFilter(getColor(R.color.textPrimary), PorterDuff.Mode.SRC_ATOP);
}
}
return super.onCreateOptionsMenu(menu);
}
@SuppressLint("PrivateApi")
@ -168,7 +229,7 @@ public abstract class BaseActivity2 extends AppCompatActivity {
Drawable drawable = menuItem.getIcon();
if (drawable != null) {
drawable.mutate();
drawable.setColorFilter(getResources().getColor(R.color.black), PorterDuff.Mode.SRC_ATOP);
drawable.setColorFilter(getResources().getColor(R.color.textPrimary), PorterDuff.Mode.SRC_ATOP);
}
}
}

@ -23,7 +23,7 @@ public abstract class BaseFragment extends Fragment {
protected CompositeDisposable mDisposable;
private View root = null;
private Unbinder unbinder;
protected Unbinder unbinder;
@LayoutRes
protected abstract int getContentId();

@ -10,10 +10,10 @@ import java.io.File;
public class APPCONST {
public static String publicKey = "fyds1.0";//服务端公钥
public static String publicKey = "";//服务端公钥
public static String privateKey;//app私钥
public final static String s = "11940364935628058505";
public static final String KEY = "readerByFengyue";
public static final String KEY = "";
public static final String ALARM_SCHEDULE_MSG = "alarm_schedule_msg";
@ -33,6 +33,8 @@ public class APPCONST {
public static final int exitConfirmTime = 2000;
public static final String BOOK = "book";
public static final String TITLE = "title";
public static final String FIND_CRAWLER = "findCrawler";
public static final String CHAPTER_PAGE = "chapter_page";
public static final String SETTING = "setting";
public static final String SEARCH_BOOK_BEAN = "SearchBookBean";
@ -57,6 +59,7 @@ public class APPCONST {
public static final int REQUEST_FONT = 1001;
public static final int REQUEST_CHAPTER_PAGE = 1002;
public static final int REQUEST_RESET_SCREEN_TIME = 1003;
public static final int REQUEST_LOGIN = 1004;
public static final int REQUEST_READ = 1;

@ -1,9 +1,5 @@
package xyz.fycz.myreader.common;
/**
* Created by zhao on 2016/10/20.
*/
public class URLCONST {
// 命名空间
@ -11,12 +7,17 @@ public class URLCONST {
public static String nameSpace_biquge = "https://www.52bqg.com/";
public static String nameSpace_qb5 = "https://www.qb5.tw";
public static String qidian_rank = "https://www.qidian.com/rank";
public static String nameSpace_system = "https://novel.fycz.xyz";
public static boolean isRSA = false;
// 搜索小说
public static String method_fengyue_search = "https://novel.fycz.xyz/search.html";
public static String method_buxiu_search = "https://www.23txt.com/search.php";
// 获取最新版本号

@ -2,14 +2,13 @@ package xyz.fycz.myreader.creator;
import android.annotation.SuppressLint;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import androidx.appcompat.app.AppCompatActivity;
import xyz.fycz.myreader.application.MyApplication;
import xyz.fycz.myreader.base.BaseActivity;
import xyz.fycz.myreader.callback.ResultCallback;
import xyz.fycz.myreader.common.APPCONST;
import xyz.fycz.myreader.ui.activity.MainActivity;
@ -38,7 +37,7 @@ public class APPDownloadTip {
private MainActivity activity;
private boolean isForceUpdate;
public APPDownloadTip(String url, BookcaseFragment mBookcaseFragment, BaseActivity activity, boolean isForceUpdate) {
public APPDownloadTip(String url, BookcaseFragment mBookcaseFragment, AppCompatActivity activity, boolean isForceUpdate) {
this.url = url;
this.mBookcaseFragment = mBookcaseFragment;
this.activity = (MainActivity) activity;
@ -49,6 +48,7 @@ public class APPDownloadTip {
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
if (!MyApplication.isDestroy(activity)) {
switch (msg.what) {
case 1:
mBookcaseFragment.getTvDownloadTip().setText("获取下载链接失败,请前往浏览器下载!");
@ -65,6 +65,7 @@ public class APPDownloadTip {
break;
}
}
}
};
public void downloadApp() {
@ -159,6 +160,7 @@ public class APPDownloadTip {
activity.finish();
}
}
@SuppressLint({"SetTextI18n"})
private void updateDownloadPro(double progress) {
mBookcaseFragment.getPbDownload().setProgress((int) progress);

@ -4,7 +4,9 @@ import android.annotation.SuppressLint;
import android.content.Context;
import android.os.Handler;
import android.os.Message;
import xyz.fycz.myreader.application.MyApplication;
import xyz.fycz.myreader.callback.ResultCallback;
import xyz.fycz.myreader.util.ToastUtils;
import xyz.fycz.myreader.webapi.crawler.*;
import xyz.fycz.myreader.entity.SearchBookBean;
import xyz.fycz.myreader.greendao.entity.Book;
@ -30,22 +32,34 @@ public class ChangeSourceDialog {
private boolean isSearchSuccess;
private int threadCount;
private ResultCallback rc;
private boolean isGetOneBook = false;
private Book oneBook;
@SuppressLint("HandlerLeak")
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case 1:
if (isGetOneBook){
rc.onFinish(oneBook, 0);
}else {
if (threadCount == 0) {
createaBooks();
}
}
break;
case 2:
if (!isSearchSuccess && threadCount == 0) {
if (!isGetOneBook|| oneBook == null) {
rc.onError(new Exception());
}
}else if (threadCount == 0){
if (isGetOneBook){
rc.onFinish(oneBook, 0);
}else {
createaBooks();
}
}
break;
}
}
@ -62,17 +76,32 @@ public class ChangeSourceDialog {
getData();
}
public void initOneBook(ResultCallback rc){
this.rc = rc;
getData();
isGetOneBook = true;
}
/**
* 获取搜索数据
*/
private void getData() {
mBooks.clear();
threadCount = 4;
ArrayList<ReadCrawler> readCrawlers = ReadCrawlerUtil.getReadCrawlers();
threadCount = readCrawlers.size();
if (threadCount == 0){
if (isGetOneBook){
ToastUtils.showWarring("当前书源已全部禁用,无法搜索!");
}else {
ToastUtils.showWarring("当前书源已全部禁用,无法换源!");
}
rc.onError(new Exception());
return;
}
isSearchSuccess = false;
searchBookByCrawler(new BiQuGe44ReadCrawler(), "");
searchBookByCrawler(new TianLaiReadCrawler(), "");
searchBookByCrawler(new BiQuGeReadCrawler(), "gbk");
searchBookByCrawler(new PinShuReadCrawler(), "gbk");
for (ReadCrawler readCrawler : readCrawlers){
searchBookByCrawler(readCrawler, readCrawler.getSearchCharset());
}
}
private void searchBookByCrawler(final ReadCrawler rc, String charset) {
@ -89,6 +118,16 @@ public class ChangeSourceDialog {
public void onFinish(Object o, int code) {
final ConcurrentMultiValueMap<SearchBookBean, Book> cmvm =
(ConcurrentMultiValueMap<SearchBookBean, Book>) o;
if (isGetOneBook){
if (oneBook != null){
return;
}
oneBook = cmvm.getValue(sbb, 0);
threadCount--;
mHandler.sendMessage(mHandler.obtainMessage(1));
MyApplication.getApplication().shutdownThreadPool();
return;
}
if (rc instanceof BookInfoCrawler) {
BookInfoCrawler bic = (BookInfoCrawler) rc;
final List<Book> aBooks = cmvm.getValues(sbb);
@ -140,4 +179,5 @@ public class ChangeSourceDialog {
aBooks = (ArrayList<Book>) mBooks.getValues(sbb);
rc.onFinish(aBooks, 1);
}
}

@ -18,6 +18,7 @@ import android.widget.*;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.AppCompatImageView;
import xyz.fycz.myreader.R;
import xyz.fycz.myreader.application.MyApplication;
import xyz.fycz.myreader.application.SysManager;
@ -115,12 +116,7 @@ public class DialogCreator {
ivLastSelectd = ivBlueDeepStyle;
break;
}
ivCommonStyle.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
selectedStyle(ivCommonStyle, common, onReadStyleChangeListener);
}
});
ivCommonStyle.setOnClickListener(v -> selectedStyle(ivCommonStyle, common, onReadStyleChangeListener));
ivLeatherStyle.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
@ -371,7 +367,7 @@ public class DialogCreator {
Window window = dialog.getWindow();
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
if (Build.VERSION.SDK_INT >= 21) {
window.setStatusBarColor(dialog.getContext().getResources().getColor(R.color.sys_dialog_setting_bg));
window.setStatusBarColor(dialog.getContext().getColor(R.color.sys_dialog_setting_bg));
}
view.setOnTouchListener(new View.OnTouchListener() {
@ -452,7 +448,7 @@ public class DialogCreator {
tvNightAndDay.setText(context.getString(R.string.day));
}
if (onClickNightAndDayListener != null) {
onClickNightAndDayListener.onClick(dialog, view1, isDay);
onClickNightAndDayListener.onClick(dialog, view, isDay);
}
});
@ -486,7 +482,7 @@ public class DialogCreator {
public static AlertDialog createCommonDialog(Context context, String title, String mesage, boolean isCancelable,
DialogInterface.OnClickListener positiveListener, DialogInterface.OnClickListener negativeListener) {
final AlertDialog.Builder normalDialog = new AlertDialog.Builder(context);
final AlertDialog.Builder normalDialog = MyAlertDialog.build(context);
// normalDialog.setIcon(R.drawable.icon_dialog);
normalDialog.setTitle(title);
normalDialog.setCancelable(isCancelable);
@ -518,36 +514,33 @@ public class DialogCreator {
* @param mesage
* @param key1
* @param key2
* @param positiveListener key1按键动作
* @param negativeListener key2按键动作
* @param key1Listener key1按键动作
* @param key2Listener key2按键动作
*/
public static void createCommonDialog(Context context, String title, String mesage, boolean isCancelable,
String key1, String key2,
DialogInterface.OnClickListener positiveListener,
DialogInterface.OnClickListener negativeListener) {
DialogInterface.OnClickListener key1Listener,
DialogInterface.OnClickListener key2Listener) {
try {
final AlertDialog.Builder normalDialog = new AlertDialog.Builder(context);
final AlertDialog.Builder normalDialog = MyAlertDialog.build(context);
// normalDialog.setIcon(R.drawable.icon_dialog);
normalDialog.setTitle(title);
normalDialog.setCancelable(isCancelable);
if (mesage != null) {
normalDialog.setMessage(mesage);
}
normalDialog.setPositiveButton(key1, positiveListener);
normalDialog.setNegativeButton(key2, negativeListener);
normalDialog.setPositiveButton(key1, key1Listener);
normalDialog.setNegativeButton(key2, key2Listener);
// 显示
// final AlertDialog alertDialog = normalDialog.create();
MyApplication.runOnUiThread(new Runnable() {
@Override
public void run() {
// final MyAlertDialog alertDialog = normalDialog.create();
MyApplication.runOnUiThread(() -> {
try {
// final AlertDialog alertDialog = normalDialog.create();
// final MyAlertDialog alertDialog = normalDialog.create();
normalDialog.show();
} catch (Exception e) {
e.printStackTrace();
}
}
});
} catch (Exception e) {
e.printStackTrace();
@ -568,7 +561,7 @@ public class DialogCreator {
String key, DialogInterface.OnClickListener positiveListener
) {
try {
final AlertDialog.Builder normalDialog = new AlertDialog.Builder(context);
final AlertDialog.Builder normalDialog = MyAlertDialog.build(context);
// normalDialog.setIcon(R.drawable.icon_dialog);
normalDialog.setTitle(title);
normalDialog.setCancelable(isCancelable);
@ -578,12 +571,12 @@ public class DialogCreator {
normalDialog.setPositiveButton(key, positiveListener);
// 显示
// final AlertDialog alertDialog = normalDialog.create();
// final MyAlertDialog alertDialog = normalDialog.create();
MyApplication.runOnUiThread(new Runnable() {
@Override
public void run() {
try {
// final AlertDialog alertDialog = normalDialog.create();
// final MyAlertDialog alertDialog = normalDialog.create();
normalDialog.show();
} catch (Exception e) {
e.printStackTrace();
@ -609,7 +602,7 @@ public class DialogCreator {
(Context context, String title, String message/*,
DialogInterface.OnClickListener positiveListener,DialogInterface.OnClickListener negativeListener*/) {
final ProgressDialog progressDialog = new ProgressDialog(context);
final ProgressDialog progressDialog = new ProgressDialog(context, R.style.alertDialogTheme);
// normalDialog.setIcon(R.drawable.icon_dialog);
if (!StringHelper.isEmpty(title)) {
progressDialog.setTitle(title);
@ -654,7 +647,7 @@ public class DialogCreator {
DialogInterface.OnClickListener positiveListener) {
/* final EditText et = new EditText(context);*/
try {
final AlertDialog.Builder dialog = new AlertDialog.Builder(context);
final AlertDialog.Builder dialog = MyAlertDialog.build(context);
dialog.setTitle(title);
if (!StringHelper.isEmpty(msg)) {
dialog.setMessage(msg);
@ -670,7 +663,7 @@ public class DialogCreator {
@Override
public void run() {
try {
// final AlertDialog alertDialog = normalDialog.create();
// final MyAlertDialog alertDialog = normalDialog.create();
dialog.show();
} catch (Exception e) {
e.printStackTrace();

@ -5,6 +5,7 @@ import android.content.DialogInterface;
import android.widget.Button;
import android.widget.ListView;
import androidx.appcompat.app.AlertDialog;
import xyz.fycz.myreader.R;
/**
* @author fengyue
@ -22,10 +23,13 @@ public class MultiChoiceDialog {
DialogCreator.OnMultiDialogListener onMultiDialogListener) {
this.checkedCount = checkedCount;
int itemsCount = checkedItems.length;
AlertDialog multiChoiceDialog = new AlertDialog.Builder(context)
AlertDialog multiChoiceDialog = MyAlertDialog.build(context)
.setTitle(title)
.setCancelable(false)
.setMultiChoiceItems(items, checkedItems, (dialog, which, isChecked) -> {
if (onMultiDialogListener != null) {
onMultiDialogListener.onItemClick(dialog, which, isChecked);
}
if(isChecked){
this.checkedCount++;
}else {
@ -57,7 +61,9 @@ public class MultiChoiceDialog {
checkedItems[i] = false;
itemList.setItemChecked(i, false);
}
if (onMultiDialogListener != null) {
onMultiDialogListener.onSelectAll(false);
}
} else {
this.checkedCount = itemsCount;
selectAll.setText("取消全选");
@ -65,8 +71,10 @@ public class MultiChoiceDialog {
checkedItems[i] = true;
itemList.setItemChecked(i, true);
}
if (onMultiDialogListener != null) {
onMultiDialogListener.onSelectAll(true);
}
}
});
return multiChoiceDialog;

@ -0,0 +1,15 @@
package xyz.fycz.myreader.creator;
import android.content.Context;
import androidx.appcompat.app.AlertDialog;
import xyz.fycz.myreader.R;
/**
* @author fengyue
* @date 2020/9/20 9:48
*/
public class MyAlertDialog {
public static AlertDialog.Builder build(Context context){
return new AlertDialog.Builder(context, R.style.alertDialogTheme);
}
}

@ -51,6 +51,8 @@ public class Setting implements Serializable {
private boolean refreshWhenStart;//打开软件自动更新书籍
private boolean openBookStore;//是否开启书城
private int settingVersion;//设置版本号
public int getAutoScrollSpeed() {
@ -212,4 +214,12 @@ public class Setting implements Serializable {
public void setRefreshWhenStart(boolean refreshWhenStart) {
this.refreshWhenStart = refreshWhenStart;
}
public boolean isOpenBookStore() {
return openBookStore;
}
public void setOpenBookStore(boolean openBookStore) {
this.openBookStore = openBookStore;
}
}

@ -0,0 +1,80 @@
package xyz.fycz.myreader.entity.bookstore;
/**
* @author fengyue
* @date 2020/9/18 20:46
*/
public class QDBook {
protected String bid;
protected String bName;
protected String bAuth;
protected String img;
protected String cat;
protected int catId;
protected String cnt;
protected String desc;
public String getBid() {
return bid;
}
public void setBid(String bid) {
this.bid = bid;
}
public String getbName() {
return bName;
}
public void setbName(String bName) {
this.bName = bName;
}
public String getbAuth() {
return bAuth;
}
public void setbAuth(String bAuth) {
this.bAuth = bAuth;
}
public String getImg() {
return img;
}
public void setImg(String img) {
this.img = img;
}
public String getCat() {
return cat;
}
public void setCat(String cat) {
this.cat = cat;
}
public int getCatId() {
return catId;
}
public void setCatId(int catId) {
this.catId = catId;
}
public String getCnt() {
return cnt;
}
public void setCnt(String cnt) {
this.cnt = cnt;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
}

@ -0,0 +1,38 @@
package xyz.fycz.myreader.entity.bookstore;
/**
* @author fengyue
* @date 2020/9/16 22:56
*/
public class RankBook extends QDBook{
/*bAuth: "净无痕"
bName: "伏天氏"
bid: "1011058239"
cat: "玄幻"
catId: 21
cnt: "636.1万字"
desc: "东方神州,有人皇立道统,有圣贤宗门传道,有诸侯雄踞一方王国,诸强林立,神州动乱千万载,值此之时,一代天骄叶青帝及东凰大帝横空出世,东方神州一统!然,叶青帝忽然暴毙,世间雕像尽皆被毁,于世间除名,沦为禁忌;从此神州唯东凰大帝独尊!十五年后,东海青州城,一名为叶伏天的少年,开启了他的传奇之路…"
rankCnt: "5996月票"
rankNum: 21*/
private String rankCnt;
private int rankNum;
public String getRankCnt() {
return rankCnt;
}
public void setRankCnt(String rankCnt) {
this.rankCnt = rankCnt;
}
public int getRankNum() {
return rankNum;
}
public void setRankNum(int rankNum) {
this.rankNum = rankNum;
}
}

@ -0,0 +1,27 @@
package xyz.fycz.myreader.entity.bookstore;
/**
* @author fengyue
* @date 2020/9/18 20:43
*/
public class SortBook extends QDBook{
/*bAuth: "老鸡吃蘑菇"
bName: "全世界都不知道我多强"
bid: 1021781295
cat: "玄幻"
catId: 21
cid: 406957810
cnt: "72.68万字"
desc: "【日更过万,质量保证!】当梁凡从地底爬出来之后,才发现不是变秃才能变强!我要控制我自己,要是不小心一拳打爆这个星球怎么办?安静的隐藏在世俗,全世界都不知道我有多强,虽然这个世界妖魔鬼怪很变态,但苟着享"
state: "连载"*/
private String state;
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
}

@ -12,6 +12,7 @@ public enum BookSource {
biquge44("笔趣阁44"),
pinshu("品书网"),
biquge("笔趣阁"),
qb5("全本小说"),
local("本地书籍");
public String text;
@ -19,6 +20,15 @@ public enum BookSource {
this.text = text;
}
public static String getFromName(String name){
for (BookSource bookSource : BookSource.values()){
if (bookSource.text.equals(name)){
return bookSource.toString();
}
}
return null;
}
public static BookSource get(int var0) {
return values()[var0];
}

@ -0,0 +1,40 @@
package xyz.fycz.myreader.enums;
import java.io.Serializable;
/**
* 小说源
* Created by zhao on 2020/04/13.
*/
public enum FindType implements Serializable {
qidian("排行榜[起点中文网]", "https://www.qidian.com/rank"),
qidianns("排行榜[起点女生网]", "https://www.qidian.com/mm/rank"),
qb5("书城[全本小说]", "https://www.qb5.tw"),
biquge("书城[笔趣阁]", "https://www.52bqg.com");
private String text;
private String url;
private static final long serialVersionUID = 1L;
FindType(String text, String url) {
this.text = text;
this.url = url;
}
public static FindType get(int var0) {
return values()[var0];
}
public static FindType fromString(String string) {
return valueOf(string);
}
public String getText() {
return text;
}
public String getUrl() {
return url;
}
}

@ -60,14 +60,19 @@ public class Book implements Serializable {
@Nullable
private boolean isDownLoadAll = true;//是否一键缓存
@Generated(hash = 1839780644)
private String groupId;//分组id
private int groupSort;//分组排序
@Generated(hash = 1308680987)
public Book(String id, String name, String chapterUrl, String imgUrl,
String desc, String author, String type, String updateDate,
String newestChapterId, String newestChapterTitle,
String newestChapterUrl, String historyChapterId,
int histtoryChapterNum, int sortCode, int noReadNum,
int chapterTotalNum, int lastReadPosition, String source,
boolean isCloseUpdate, boolean isDownLoadAll) {
boolean isCloseUpdate, boolean isDownLoadAll, String groupId,
int groupSort) {
this.id = id;
this.name = name;
this.chapterUrl = chapterUrl;
@ -88,6 +93,8 @@ public class Book implements Serializable {
this.source = source;
this.isCloseUpdate = isCloseUpdate;
this.isDownLoadAll = isDownLoadAll;
this.groupId = groupId;
this.groupSort = groupSort;
}
public Book(Book book) {
@ -111,6 +118,7 @@ public class Book implements Serializable {
this.source = book.source;
this.isCloseUpdate = book.isCloseUpdate;
this.isDownLoadAll = book.isDownLoadAll;
this.groupId = book.groupId;
}
@Generated(hash = 1839243756)
@ -236,6 +244,21 @@ public class Book implements Serializable {
this.isCloseUpdate = isCloseUpdate;
}
public boolean getIsDownLoadAll() {
return this.isDownLoadAll;
}
public void setIsDownLoadAll(boolean isDownLoadAll) {
this.isDownLoadAll = isDownLoadAll;
}
public String getGroupId() {
return this.groupId;
}
public void setGroupId(String groupId) {
this.groupId = groupId;
}
@Override
public String toString() {
@ -260,6 +283,7 @@ public class Book implements Serializable {
",\nsource='" + source + '\'' +
",\nisCloseUpdate='" + isCloseUpdate + '\'' +
",\nisDownLoadAll='" + isDownLoadAll + '\'' +
",\ngroupId='" + groupId + '\'' +
"\n}";
}
@ -279,12 +303,12 @@ public class Book implements Serializable {
return Objects.hash(name, chapterUrl, author, source);
}
public boolean getIsDownLoadAll() {
return this.isDownLoadAll;
public int getGroupSort() {
return this.groupSort;
}
public void setIsDownLoadAll(boolean isDownLoadAll) {
this.isDownLoadAll = isDownLoadAll;
public void setGroupSort(int groupSort) {
this.groupSort = groupSort;
}
@ -292,4 +316,7 @@ public class Book implements Serializable {
}

@ -0,0 +1,70 @@
package xyz.fycz.myreader.greendao.entity;
import org.greenrobot.greendao.annotation.Entity;
import org.greenrobot.greendao.annotation.Id;
import org.greenrobot.greendao.annotation.NotNull;
import org.greenrobot.greendao.annotation.Generated;
/**
* @author fengyue
* @date 2020/9/23 22:18
*/
@Entity
public class BookGroup {
@Id
private String id;
@NotNull
private int num;
@NotNull
private String name;
private String desc;
@Generated(hash = 1387727906)
public BookGroup(String id, int num, @NotNull String name, String desc) {
this.id = id;
this.num = num;
this.name = name;
this.desc = desc;
}
@Generated(hash = 511810489)
public BookGroup() {
}
public String getId() {
return this.id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public String getDesc() {
return this.desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
public int getNum() {
return this.num;
}
public void setNum(int num) {
this.num = num;
}
}

@ -0,0 +1,77 @@
package xyz.fycz.myreader.greendao.service;
import xyz.fycz.myreader.greendao.GreenDaoManager;
import xyz.fycz.myreader.greendao.entity.BookGroup;
import xyz.fycz.myreader.greendao.gen.BookGroupDao;
import xyz.fycz.myreader.greendao.gen.BookMarkDao;
import xyz.fycz.myreader.util.StringHelper;
import java.util.List;
/**
* @author fengyue
* @date 2020/9/26 12:14
*/
public class BookGroupService extends BaseService{
private static volatile BookGroupService sInstance;
public static BookGroupService getInstance() {
if (sInstance == null){
synchronized (BookGroupService.class){
if (sInstance == null){
sInstance = new BookGroupService();
}
}
}
return sInstance;
}
/**
* 获取所有书籍分组
* @return
*/
public List<BookGroup> getAllGroups(){
return GreenDaoManager.getInstance().getSession().getBookGroupDao()
.queryBuilder()
.orderAsc(BookGroupDao.Properties.Num)
.list();
}
/**
* 通过I的获取书籍分组
* @param groupId
* @return
*/
public BookGroup getGroupById(String groupId){
return GreenDaoManager.getInstance().getSession().getBookGroupDao()
.queryBuilder()
.where(BookGroupDao.Properties.Id.eq(groupId))
.unique();
}
/**
* 添加书籍分组
* @param bookGroup
*/
public void addBookGroup(BookGroup bookGroup){
bookGroup.setNum(countBookGroup());
bookGroup.setId(StringHelper.getStringRandom(25));
addEntity(bookGroup);
}
/**
* 删除书籍分组
* @param bookGroup
*/
public void deleteBookGroup(BookGroup bookGroup){
deleteEntity(bookGroup);
}
private int countBookGroup(){
return (int) GreenDaoManager.getInstance().getSession().getBookGroupDao()
.queryBuilder()
.count();
}
}

@ -31,27 +31,6 @@ public class BookMarkService extends BaseService {
}
return sInstance;
}
private ArrayList<BookMark> findBookMarks(String sql, String[] selectionArgs) {
ArrayList<BookMark> bookMarks = new ArrayList<>();
try {
Cursor cursor = selectBySql(sql, selectionArgs);
if (cursor == null) return bookMarks;
while (cursor.moveToNext()) {
BookMark bookMark = new BookMark();
bookMark.setId(cursor.getString(0));
bookMark.setBookId(cursor.getString(1));
bookMark.setNumber(cursor.getInt(2));
bookMark.setTitle(cursor.getString(3));
bookMark.setBookMarkChapterNum(cursor.getInt(4));
bookMark.setBookMarkReadPosition(cursor.getInt(5));
bookMarks.add(bookMark);
}
} catch (Exception e) {
e.printStackTrace();
return bookMarks;
}
return bookMarks;
}
/**
* 通过ID查书签
@ -69,20 +48,10 @@ public class BookMarkService extends BaseService {
* @return
*/
public BookMark findBookMarkByTitle(String title){
BookMark bookMark = null;
String sql = "select * from book_mark where title = ?";
Cursor cursor = selectBySql(sql,new String[]{title});
if (cursor == null) return null;
if (cursor.moveToNext()){
bookMark = new BookMark();
bookMark.setId(cursor.getString(0));
bookMark.setBookId(cursor.getString(1));
bookMark.setNumber(cursor.getInt(2));
bookMark.setTitle(cursor.getString(3));
bookMark.setBookMarkChapterNum(cursor.getInt(4));
bookMark.setBookMarkReadPosition(cursor.getInt(5));
}
return bookMark;
return GreenDaoManager.getInstance().getSession().getBookMarkDao()
.queryBuilder()
.where(BookMarkDao.Properties.Title.eq(title))
.unique();
}
/**
* 获取书的所有书签
@ -90,12 +59,11 @@ public class BookMarkService extends BaseService {
* @return
*/
public List<BookMark> findBookAllBookMarkByBookId(String bookId) {
if (StringHelper.isEmpty(bookId)) return new ArrayList<>();
String sql = "select * from book_mark where book_id = ? order by number";
return findBookMarks(sql, new String[]{bookId});
return GreenDaoManager.getInstance().getSession().getBookMarkDao()
.queryBuilder()
.where(BookMarkDao.Properties.BookId.eq(bookId))
.orderAsc(BookMarkDao.Properties.Number)
.list();
}
@ -155,7 +123,7 @@ public class BookMarkService extends BaseService {
* @return
*/
public int countBookMarkTotalNumByBookId(String bookId){
int num = 0;
/*int num = 0;
try {
Cursor cursor = selectBySql("select count(*) n from book where book_id = " + bookId,null);
if (cursor.moveToNext()){
@ -163,8 +131,12 @@ public class BookMarkService extends BaseService {
}
} catch (Exception e) {
e.printStackTrace();
}
return num;
}*/
return (int) GreenDaoManager.getInstance().getSession().getBookMarkDao()
.queryBuilder()
.where(BookMarkDao.Properties.BookId.eq(bookId))
.count();
}
/**

@ -10,6 +10,7 @@ import xyz.fycz.myreader.application.SysManager;
import xyz.fycz.myreader.common.APPCONST;
import xyz.fycz.myreader.greendao.entity.Chapter;
import xyz.fycz.myreader.greendao.gen.BookDao;
import xyz.fycz.myreader.greendao.gen.ChapterDao;
import xyz.fycz.myreader.util.*;
import xyz.fycz.myreader.greendao.GreenDaoManager;
import xyz.fycz.myreader.greendao.entity.Book;
@ -50,39 +51,6 @@ public class BookService extends BaseService {
return sInstance;
}
private List<Book> findBooks(String sql, String[] selectionArgs) {
ArrayList<Book> books = new ArrayList<>();
try {
Cursor cursor = selectBySql(sql, selectionArgs);
while (cursor.moveToNext()) {
Book book = new Book();
book.setId(cursor.getString(0));
book.setName(cursor.getString(1));
book.setChapterUrl(cursor.getString(2));
book.setImgUrl(cursor.getString(3));
book.setDesc(cursor.getString(4));
book.setAuthor(cursor.getString(5));
book.setType(cursor.getString(6));
book.setUpdateDate(cursor.getString(7));
book.setNewestChapterId(cursor.getString(8));
book.setNewestChapterTitle(cursor.getString(9));
book.setNewestChapterUrl(cursor.getString(10));
book.setHistoryChapterId(cursor.getString(11));
book.setHisttoryChapterNum(cursor.getInt(12));
book.setSortCode(cursor.getInt(13));
book.setNoReadNum(cursor.getInt(14));
book.setChapterTotalNum(cursor.getInt(15));
book.setLastReadPosition(cursor.getInt(16));
book.setSource(cursor.getString(17));
book.setIsCloseUpdate(cursor.getShort(18) != 0);
book.setIsDownLoadAll(cursor.getShort(19) != 0);
books.add(book);
}
} catch (Exception e) {
e.printStackTrace();
}
return books;
}
/**
* 通过ID查书
@ -101,8 +69,26 @@ public class BookService extends BaseService {
* @return
*/
public List<Book> getAllBooks() {
String sql = "select * from book order by sort_code";
return findBooks(sql, null);
return GreenDaoManager.getInstance().getSession().getBookDao()
.queryBuilder()
.orderAsc(BookDao.Properties.SortCode)
.list();
}
/**
* 获取特定分组的书
*
* @return
*/
public List<Book> getGroupBooks(String groupId) {
if (StringHelper.isEmpty(groupId)){
return getAllBooks();
}
return GreenDaoManager.getInstance().getSession().getBookDao()
.queryBuilder()
.where(BookDao.Properties.GroupId.eq(groupId))
.orderAsc(BookDao.Properties.GroupSort)
.list();
}
/**
@ -112,7 +98,9 @@ public class BookService extends BaseService {
*/
public void addBook(Book book) {
// book.setSortCode(countBookTotalNum() + 1);
book.setSortCode(0);
book.setGroupSort(0);
if (StringHelper.isEmpty(book.getId())) {
book.setId(StringHelper.getStringRandom(25));
}
@ -138,17 +126,10 @@ public class BookService extends BaseService {
* @return
*/
public Book findBookByAuthorAndName(String bookName, String author) {
Book book = null;
try {
Cursor cursor = selectBySql("select id from book where author = ? and name = ?", new String[]{author, bookName});
if (cursor.moveToNext()) {
String id = cursor.getString(0);
book = getBookById(id);
}
} catch (Exception e) {
e.printStackTrace();
}
return book;
return GreenDaoManager.getInstance().getSession().getBookDao()
.queryBuilder()
.where(BookDao.Properties.Name.eq(bookName), BookDao.Properties.Author.eq(author))
.unique();
}
/**
@ -158,17 +139,10 @@ public class BookService extends BaseService {
* @return
*/
public Book findBookByPath(String path) {
Book book = null;
try {
Cursor cursor = selectBySql("select id from book where CHAPTER_URL = ?", new String[]{path});
if (cursor.moveToNext()) {
String id = cursor.getString(0);
book = getBookById(id);
}
} catch (Exception e) {
e.printStackTrace();
}
return book;
return GreenDaoManager.getInstance().getSession().getBookDao()
.queryBuilder()
.where(BookDao.Properties.ChapterUrl.eq(path))
.unique();
}
/**

@ -34,7 +34,7 @@ public class MySQLiteOpenHelper extends DaoMaster.OpenHelper {
DaoMaster.dropAllTables(db, ifExists);
}
},
BookDao.class, ChapterDao.class, SearchHistoryDao.class, BookMarkDao.class
BookDao.class, ChapterDao.class, SearchHistoryDao.class, BookMarkDao.class, BookGroupDao.class
);
}

@ -1,25 +1,28 @@
package xyz.fycz.myreader.ui.activity;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.appcompat.widget.Toolbar;
import androidx.cardview.widget.CardView;
import butterknife.BindView;
import butterknife.ButterKnife;
import xyz.fycz.myreader.R;
import xyz.fycz.myreader.base.BaseActivity;
import xyz.fycz.myreader.ui.presenter.AboutPresenter;
import xyz.fycz.myreader.application.MyApplication;
import xyz.fycz.myreader.base.BaseActivity2;
import xyz.fycz.myreader.creator.DialogCreator;
import xyz.fycz.myreader.util.ShareUtils;
import xyz.fycz.myreader.util.SharedPreUtils;
import xyz.fycz.myreader.util.ToastUtils;
/**
* @author fengyue
* @date 2020/7/31 11:32
* @date 2020/9/18 22:21
*/
public class AboutActivity extends BaseActivity {
@BindView(R.id.ll_title_back)
LinearLayout llTitleBack;
@BindView(R.id.tv_title_text)
TextView tvTitleText;
public class AboutActivity extends BaseActivity2 {
@BindView(R.id.tv_version_name)
TextView tvVersionName;
@BindView(R.id.vm_author)
@ -30,57 +33,72 @@ public class AboutActivity extends BaseActivity {
CardView vmUpdate;
@BindView(R.id.vw_update_log)
CardView vmUpdateLog;
@BindView(R.id.vw_qq)
CardView vmQQ;
@BindView(R.id.vw_git)
CardView vmGit;
@BindView(R.id.vw_disclaimer)
CardView vmDisclaimer;
private AboutPresenter mAboutPresenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_about);
ButterKnife.bind(this);
setStatusBar(R.color.white, false);
mAboutPresenter = new AboutPresenter(this);
mAboutPresenter.start();
protected int getContentId() {
return R.layout.activity_about;
}
public LinearLayout getLlTitleBack() {
return llTitleBack;
@Override
protected void setUpToolbar(Toolbar toolbar) {
super.setUpToolbar(toolbar);
setStatusBarColor(R.color.colorPrimary, true);
getSupportActionBar().setTitle("关于");
}
public TextView getTvTitleText() {
return tvTitleText;
}
public TextView getTvVersionName() {
return tvVersionName;
@Override
protected void initWidget() {
super.initWidget();
tvVersionName.setText("风月读书v" + MyApplication.getStrVersionName());
}
public CardView getVmAuthor() {
return vmAuthor;
@Override
protected void initClick() {
super.initClick();
ClipboardManager mClipboardManager = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
vmAuthor.setOnClickListener(v -> {
//数据
ClipData mClipData = ClipData.newPlainText("Label", "fy@fycz.xyz");
//把数据设置到剪切板上
assert mClipboardManager != null;
mClipboardManager.setPrimaryClip(mClipData);
ToastUtils.showSuccess("邮箱复制成功!");
});
vmShare.setOnClickListener(v -> ShareUtils.share(this, getString(R.string.share_text) +
SharedPreUtils.getInstance().getString("downloadLink")));
vmUpdate.setOnClickListener(v -> MyApplication.checkVersionByServer(this, true, null));
vmUpdateLog.setOnClickListener(v -> DialogCreator.createAssetTipDialog(this, "更新日志", "updatelog.fy"));
vmQQ.setOnClickListener(v -> {
if (!MyApplication.joinQQGroup(this,"8PIOnHFuH6A38hgxvD_Rp2Bu-Ke1ToBn")){
//数据
ClipData mClipData = ClipData.newPlainText("Label", "1085028304");
//把数据设置到剪切板上
assert mClipboardManager != null;
mClipboardManager.setPrimaryClip(mClipData);
ToastUtils.showError("未安装手Q或安装的版本不支持!\n已复制QQ群号,您可自行前往QQ添加!");
}
});
vmGit.setOnClickListener(v -> openIntent(Intent.ACTION_VIEW, getString(R.string.this_github_url)));
vmDisclaimer.setOnClickListener(v -> DialogCreator.createAssetTipDialog(this, "免责声明", "disclaimer.fy"));
public CardView getVmShare() {
return vmShare;
}
public CardView getVmUpdate() {
return vmUpdate;
void openIntent(String intentName, String address) {
try {
Intent intent = new Intent(intentName);
intent.setData(Uri.parse(address));
startActivity(intent);
} catch (Exception e) {
ToastUtils.showError(e.getLocalizedMessage());
}
public CardView getVmUpdateLog() {
return vmUpdateLog;
}
public CardView getVmGit() {
return vmGit;
}
public CardView getVmDisclaimer() {
return vmDisclaimer;
}
}

@ -2,6 +2,7 @@ package xyz.fycz.myreader.ui.activity;
import android.annotation.SuppressLint;
import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
@ -9,6 +10,7 @@ import android.os.Message;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.WindowManager;
import android.widget.*;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.widget.Toolbar;
@ -17,7 +19,9 @@ import androidx.recyclerview.widget.RecyclerView;
import butterknife.BindView;
import butterknife.OnClick;
import com.bumptech.glide.Glide;
import com.bumptech.glide.RequestBuilder;
import com.bumptech.glide.load.resource.bitmap.RoundedCorners;
import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions;
import com.bumptech.glide.request.RequestOptions;
import xyz.fycz.myreader.R;
import xyz.fycz.myreader.application.MyApplication;
@ -25,7 +29,9 @@ import xyz.fycz.myreader.application.SysManager;
import xyz.fycz.myreader.base.BaseActivity2;
import xyz.fycz.myreader.callback.ResultCallback;
import xyz.fycz.myreader.common.APPCONST;
import xyz.fycz.myreader.creator.MyAlertDialog;
import xyz.fycz.myreader.util.ToastUtils;
import xyz.fycz.myreader.util.utils.BlurTransformation;
import xyz.fycz.myreader.webapi.crawler.BookInfoCrawler;
import xyz.fycz.myreader.webapi.crawler.ReadCrawler;
import xyz.fycz.myreader.webapi.crawler.ReadCrawlerUtil;
@ -50,6 +56,8 @@ import java.util.ArrayList;
public class BookDetailedActivity extends BaseActivity2 {
@BindView(R.id.book_detail_iv_cover)
ImageView mIvCover;
/* @BindView(R.id.book_detail_iv_blur_cover)
ImageView mIvBlurCover;*/
@BindView(R.id.book_detail_tv_author)
TextView mTvAuthor;
@BindView(R.id.book_detail_tv_type)
@ -108,6 +116,7 @@ public class BookDetailedActivity extends BaseActivity2 {
DialogCreator.createTipDialog(BookDetailedActivity.this, "未搜索到该书籍,书源加载失败!");
break;
case 4:
pbLoading.setVisibility(View.GONE);
initOtherInfo();
break;
}
@ -139,6 +148,7 @@ public class BookDetailedActivity extends BaseActivity2 {
@Override
protected void setUpToolbar(Toolbar toolbar) {
super.setUpToolbar(toolbar);
//getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
setStatusBarColor(R.color.colorPrimary, true);
getSupportActionBar().setTitle(mBook.getName());
}
@ -230,22 +240,29 @@ public class BookDetailedActivity extends BaseActivity2 {
}
assert mBook.getNewestChapterTitle() != null;
mTvDesc.setText("");
if (mBook.getType() != null) {
mTvType.setText(mBook.getType());
} else {
mTvType.setText("");
}
if (!"null".equals(mBook.getSource())) {
mTvSource.setText("书源:" + BookSource.fromString(mBook.getSource()).text);
}
ReadCrawler rc = ReadCrawlerUtil.getReadCrawler(mBook.getSource());
if (rc instanceof BookInfoCrawler && StringHelper.isEmpty(mBook.getImgUrl())) {
pbLoading.setVisibility(View.VISIBLE);
BookInfoCrawler bic = (BookInfoCrawler) rc;
CommonApi.getBookInfo(mBook, bic, new ResultCallback() {
@Override
public void onFinish(Object o, int code) {
if (!MyApplication.isDestroy(BookDetailedActivity.this)) {
mHandler.sendMessage(mHandler.obtainMessage(4));
}
}
@Override
public void onError(Exception e) {
ToastUtils.showError("书籍详情加载失败!");
}
});
} else {
@ -267,9 +284,22 @@ public class BookDetailedActivity extends BaseActivity2 {
//设置圆角
.apply(RequestOptions.bitmapTransform(new RoundedCorners(8)))
.into(mIvCover);
/*Glide.with(this)
.load(mBook.getImgUrl())
.transition(DrawableTransitionOptions.withCrossFade(1500))
.thumbnail(defaultCover())
.centerCrop()
.apply(RequestOptions.bitmapTransform(new BlurTransformation(this, 25)))
.into(mIvBlurCover);*/
}
}
private RequestBuilder<Drawable> defaultCover() {
return Glide.with(this)
.load(R.mipmap.no_image)
.apply(RequestOptions.bitmapTransform(new BlurTransformation(this, 25)));
}
/**
* 创建换源对话框
*/
@ -290,7 +320,7 @@ public class BookDetailedActivity extends BaseActivity2 {
}
}
final int finalCheckedItem = checkedItem;
AlertDialog dialog = new AlertDialog.Builder(this)
AlertDialog dialog = MyAlertDialog.build(this)
.setTitle("切换书源")
.setCancelable(true)
.setSingleChoiceItems(sources, checkedItem, (dialog1, which) -> {

@ -0,0 +1,420 @@
package xyz.fycz.myreader.ui.activity;
import android.annotation.SuppressLint;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ProgressBar;
import androidx.appcompat.widget.Toolbar;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import butterknife.BindView;
import com.scwang.smartrefresh.layout.SmartRefreshLayout;
import xyz.fycz.myreader.R;
import xyz.fycz.myreader.application.MyApplication;
import xyz.fycz.myreader.base.BaseActivity2;
import xyz.fycz.myreader.callback.ResultCallback;
import xyz.fycz.myreader.common.APPCONST;
import xyz.fycz.myreader.creator.ChangeSourceDialog;
import xyz.fycz.myreader.creator.DialogCreator;
import xyz.fycz.myreader.entity.bookstore.BookType;
import xyz.fycz.myreader.entity.bookstore.QDBook;
import xyz.fycz.myreader.entity.bookstore.RankBook;
import xyz.fycz.myreader.entity.bookstore.SortBook;
import xyz.fycz.myreader.greendao.entity.Book;
import xyz.fycz.myreader.greendao.service.BookService;
import xyz.fycz.myreader.ui.adapter.BookStoreBookAdapter;
import xyz.fycz.myreader.ui.adapter.BookStoreBookTypeAdapter;
import xyz.fycz.myreader.util.SharedPreUtils;
import xyz.fycz.myreader.util.ToastUtils;
import xyz.fycz.myreader.webapi.BookStoreApi;
import xyz.fycz.myreader.webapi.crawler.FindCrawler;
import xyz.fycz.myreader.webapi.crawler.find.ABC;
import xyz.fycz.myreader.widget.RefreshLayout;
import java.util.ArrayList;
import java.util.List;
/**
* @author fengyue
* @date 2020/9/13 21:11
*/
public class BookstoreActivity extends BaseActivity2 {
@BindView(R.id.refresh_layout)
RefreshLayout mRlRefresh;
@BindView(R.id.rv_type_list)
RecyclerView rvTypeList;
@BindView(R.id.rv_book_list)
RecyclerView rvBookList;
@BindView(R.id.srl_book_list)
SmartRefreshLayout srlBookList;
@BindView(R.id.pb_loading)
ProgressBar pbLoading;
private FindCrawler findCrawler;
private LinearLayoutManager mLinearLayoutManager;
private BookStoreBookTypeAdapter mBookStoreBookTypeAdapter;
private List<BookType> mBookTypes;
private BookStoreBookAdapter mBookStoreBookAdapter;
private List<Book> bookList = new ArrayList<>();
private BookType curType;
private int page = 1;
private String title = "";
@SuppressLint("HandlerLeak")
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
if (!MyApplication.isDestroy(BookstoreActivity.this)) {
switch (msg.what) {
case 1:
initTypeList();
mRlRefresh.showFinish();
break;
case 2:
List<Book> bookList = (List<Book>) msg.obj;
initBookList(bookList);
srlBookList.setEnableRefresh(true);
srlBookList.setEnableLoadMore(true);
pbLoading.setVisibility(View.GONE);
break;
case 3:
pbLoading.setVisibility(View.VISIBLE);
break;
case 4:
pbLoading.setVisibility(View.GONE);
srlBookList.finishRefresh(false);
srlBookList.finishLoadMore(false);
break;
case 5:
mRlRefresh.showError();
break;
case 6:
DialogCreator.createTipDialog(BookstoreActivity.this,
getResources().getString(R.string.top_sort_tip, title));
break;
}
}
}
};
@Override
protected int getContentId() {
return R.layout.actiity_bookstore;
}
@Override
protected void setUpToolbar(Toolbar toolbar) {
super.setUpToolbar(toolbar);
setStatusBarColor(R.color.colorPrimary, true);
String subTitle = "";
if (findCrawler != null) {
String name = findCrawler.getFindName();
title = name.substring(0, name.indexOf("["));
subTitle = name.substring(name.indexOf("[") + 1, name.length() - 1);
}
getSupportActionBar().setTitle(title);
getSupportActionBar().setSubtitle(subTitle);
}
@Override
protected void initData(Bundle savedInstanceState) {
super.initData(savedInstanceState);
findCrawler = (FindCrawler) getIntent().getSerializableExtra(APPCONST.FIND_CRAWLER);
}
@Override
protected void initWidget() {
super.initWidget();
srlBookList.setEnableRefresh(false);
srlBookList.setEnableLoadMore(false);
//小说列表下拉加载更多事件
srlBookList.setOnLoadMoreListener(refreshLayout -> {
page++;
getBooksData();
});
//小说列表上拉刷新事件
srlBookList.setOnRefreshListener(refreshLayout -> {
page = 1;
getBooksData();
});
mBookStoreBookAdapter = new BookStoreBookAdapter(findCrawler.hasImg(), this);
rvBookList.setLayoutManager(new LinearLayoutManager(this));
rvBookList.setAdapter(mBookStoreBookAdapter);
mRlRefresh.setOnReloadingListener(this::getData);
}
@Override
protected void initClick() {
super.initClick();
mBookStoreBookAdapter.setOnItemClickListener((view, pos) -> {
Book book = bookList.get(pos);
if (!findCrawler.hasImg()) {
goToBookDetail(book);
} else {
if (BookService.getInstance().isBookCollected(book)) {
goToBookDetail(book);
return;
}
mHandler.sendMessage(mHandler.obtainMessage(3));
ChangeSourceDialog csd = new ChangeSourceDialog(this, book);
csd.initOneBook(new ResultCallback() {
@Override
public void onFinish(Object o, int code) {
Book searchBook = (Book) o;
book.setChapterUrl(searchBook.getChapterUrl());
book.setSource(searchBook.getSource());
goToBookDetail(book);
mHandler.sendMessage(mHandler.obtainMessage(4));
}
@Override
public void onError(Exception e) {
DialogCreator.createTipDialog(BookstoreActivity.this, "未搜索到该书籍,无法进入书籍详情!");
mHandler.sendMessage(mHandler.obtainMessage(4));
}
});
}
});
}
@Override
protected void processLogic() {
super.processLogic();
getData();
if (findCrawler.hasImg()) {
SharedPreUtils spu = SharedPreUtils.getInstance();
boolean isReadTopTip = spu.getBoolean("isReadTopTip", false);
if (!isReadTopTip) {
DialogCreator.createCommonDialog(this, "提示", getResources().getString(R.string.top_sort_tip, title),
true, "知道了", "不再提示", null,
(dialog, which) -> spu.putBoolean("isReadTopTip", true));
}
}
}
/**
* 获取页面数据
*/
private void getData() {
if (findCrawler instanceof ABC) {
SharedPreUtils spu = SharedPreUtils.getInstance();
if (spu.getString("qdCookie", "").equals("")) {
((ABC) findCrawler).initCookie(this, new ResultCallback() {
@Override
public void onFinish(Object o, int code) {
spu.putString("qdCookie", (String) o);
mBookTypes = ((ABC) findCrawler).getRankTypes();
curType = mBookTypes.get(0);
mHandler.sendMessage(mHandler.obtainMessage(1));
page = 1;
getBooksData();
}
@Override
public void onError(Exception e) {
mRlRefresh.showError();
e.printStackTrace();
}
});
} else {
mBookTypes = ((ABC) findCrawler).getRankTypes();
curType = mBookTypes.get(0);
mHandler.sendMessage(mHandler.obtainMessage(1));
page = 1;
getBooksData();
}
} else {
BookStoreApi.getBookTypeList(findCrawler, new ResultCallback() {
@Override
public void onFinish(Object o, int code) {
mBookTypes = (ArrayList<BookType>) o;
curType = mBookTypes.get(0);
mHandler.sendMessage(mHandler.obtainMessage(1));
page = 1;
getBooksData();
}
@Override
public void onError(Exception e) {
e.printStackTrace();
mHandler.sendEmptyMessage(5);
}
});
}
}
/**
* 获取小数列表数据
*/
private void getBooksData() {
if (findCrawler.getTypePage(curType, page)) {
srlBookList.finishLoadMoreWithNoMoreData();
return;
}
mHandler.sendEmptyMessage(3);
if (findCrawler instanceof ABC) {
((ABC) findCrawler).getRankBooks(curType, new ResultCallback() {
@Override
public void onFinish(Object o, int code) {
List<Book> books = new ArrayList<>();
for (QDBook rb : (List<QDBook>) o) {
Book book = new Book();
book.setName(rb.getbName());
book.setAuthor(rb.getbAuth());
book.setImgUrl(rb.getImg());
String cat = rb.getCat();
book.setType(cat.contains("小说") || cat.length() >= 4 ? cat : cat + "小说");
book.setNewestChapterTitle(rb.getDesc());
book.setDesc(rb.getDesc());
if (rb instanceof RankBook) {
boolean hasRankCnt = !((RankBook) rb).getRankCnt().equals("null") &&
MyApplication.isApkInDebug(BookstoreActivity.this);
book.setUpdateDate(hasRankCnt ? book.getType() + "-" + rb.getCnt() : rb.getCnt());
book.setNewestChapterId(hasRankCnt ? ((RankBook) rb).getRankCnt() : book.getType());
} else if (rb instanceof SortBook) {
book.setUpdateDate(rb.getCnt());
book.setNewestChapterId(((SortBook) rb).getState());
}
books.add(book);
}
mHandler.sendMessage(mHandler.obtainMessage(2, books));
}
@Override
public void onError(Exception e) {
mHandler.sendMessage(mHandler.obtainMessage(4));
ToastUtils.showError("数据加载失败!\n" + e.getMessage());
e.printStackTrace();
}
});
} else {
BookStoreApi.getBookRankList(curType.getUrl(), findCrawler, new ResultCallback() {
@Override
public void onFinish(Object o, int code) {
mHandler.sendMessage(mHandler.obtainMessage(2, o));
}
@Override
public void onError(Exception e) {
mHandler.sendMessage(mHandler.obtainMessage(4));
ToastUtils.showError("数据加载失败!\n" + e.getMessage());
e.printStackTrace();
}
});
}
}
/**
* 初始化类别列表
*/
private void initTypeList() {
//设置布局管理器
mLinearLayoutManager = new LinearLayoutManager(this);
mLinearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
rvTypeList.setLayoutManager(mLinearLayoutManager);
mBookStoreBookTypeAdapter = new BookStoreBookTypeAdapter(this, mBookTypes);
rvTypeList.setAdapter(mBookStoreBookTypeAdapter);
//点击事件
mBookStoreBookTypeAdapter.setOnItemClickListener((pos, view) -> {
if (curType.equals(mBookTypes.get(pos))) {
return;
}
page = 1;
curType = mBookTypes.get(pos);
srlBookList.resetNoMoreData();
getBooksData();
});
}
/**
* 初始化小说列表
*/
private void initBookList(List<Book> bookList) {
if (page == 1) {
mBookStoreBookAdapter.refreshItems(bookList);
this.bookList.clear();
this.bookList.addAll(bookList);
rvBookList.scrollToPosition(0);
} else {
this.bookList.addAll(bookList);
mBookStoreBookAdapter.addItems(bookList);
}
//刷新动作完成
srlBookList.finishRefresh();
//加载更多完成
srlBookList.finishLoadMore();
}
/**
* 前往书籍详情
*
* @param book
*/
private void goToBookDetail(Book book) {
Intent intent = new Intent(this, BookDetailedActivity.class);
intent.putExtra(APPCONST.BOOK, book);
BookstoreActivity.this.startActivity(intent);
}
/********************************Event***************************************/
/**
* 创建菜单
*
* @param menu
* @return
*/
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_store, menu);
return true;
}
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
if (findCrawler.hasImg()) {
menu.findItem(R.id.action_tip).setVisible(true);
}
return true;
}
/**
* 导航栏菜单点击事件
*
* @param item
* @return
*/
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_tip:
mHandler.sendEmptyMessage(6);
return true;
case R.id.action_refresh:
mRlRefresh.showLoading();
getData();
return true;
}
return false;
}
}

@ -1,77 +1,117 @@
package xyz.fycz.myreader.ui.activity;
import android.os.Bundle;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import androidx.appcompat.widget.SearchView;
import androidx.appcompat.widget.Toolbar;
import androidx.viewpager.widget.ViewPager;
import butterknife.BindView;
import butterknife.ButterKnife;
import com.google.android.material.tabs.TabLayout;
import xyz.fycz.myreader.R;
import xyz.fycz.myreader.base.BaseActivity;
import xyz.fycz.myreader.ui.presenter.CatalogActivityPresenter;
import xyz.fycz.myreader.base.BaseActivity2;
import xyz.fycz.myreader.common.APPCONST;
import xyz.fycz.myreader.greendao.entity.Book;
import xyz.fycz.myreader.ui.adapter.TabFragmentPageAdapter;
import xyz.fycz.myreader.ui.fragment.BookMarkFragment;
import xyz.fycz.myreader.ui.fragment.CatalogFragment;
/**
* @author fengyue
* @date 2020/7/22 8:04
* 书籍目录activity
*/
public class CatalogActivity extends BaseActivity {
@BindView(R.id.tl_tab_menu)
TabLayout tlTabMenu;
@BindView(R.id.iv_search)
ImageView ivSearch;
@BindView(R.id.rl_common_title)
RelativeLayout rlCommonTitle;
@BindView(R.id.vp_content)
ViewPager vpContent;
@BindView(R.id.iv_back)
ImageView tvBack;
@BindView(R.id.et_search)
EditText etSearch;
@BindView(R.id.iv_cancel)
ImageView ivCancel;
private CatalogActivityPresenter mCatalogPresenter;
public class CatalogActivity extends BaseActivity2 {
@BindView(R.id.catalog_tab)
TabLayout catalogTab;
@BindView(R.id.toolbar)
Toolbar toolbar;
@BindView(R.id.catalog_vp)
ViewPager viewPager;
private SearchView searchView;
private Book mBook;
private TabFragmentPageAdapter tabAdapter;
/*******************Public**********************************/
public Book getmBook() {
return mBook;
}
/*********************Initialization****************************/
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_catalog);
ButterKnife.bind(this);
setStatusBar(0, false);
mCatalogPresenter = new CatalogActivityPresenter(this);
mCatalogPresenter.start();
protected void initData(Bundle savedInstanceState) {
super.initData(savedInstanceState);
mBook = (Book) getIntent().getSerializableExtra(APPCONST.BOOK);
}
public TabLayout getTlTabMenu() {
return tlTabMenu;
@Override
protected int getContentId() {
return R.layout.activity_catalog;
}
public ImageView getIvSearch() {
return ivSearch;
@Override
protected void setUpToolbar(Toolbar toolbar) {
super.setUpToolbar(toolbar);
setStatusBarColor(R.color.colorPrimary, true);
tabAdapter = new TabFragmentPageAdapter(getSupportFragmentManager());
tabAdapter.addFragment(new CatalogFragment(), "目录");
tabAdapter.addFragment(new BookMarkFragment(), "书签");
}
public RelativeLayout getRlCommonTitle() {
return rlCommonTitle;
@Override
protected void initWidget() {
super.initWidget();
viewPager.setAdapter(tabAdapter);
viewPager.setOffscreenPageLimit(2);
catalogTab.setupWithViewPager(viewPager);
}
public ViewPager getVpContent() {
return vpContent;
/*************************************************************************/
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.menu_view_search, menu);
MenuItem search = menu.findItem(R.id.action_search);
searchView = (SearchView) search.getActionView();
searchView.setMaxWidth(getResources().getDisplayMetrics().widthPixels);
searchView.onActionViewCollapsed();
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
return false;
}
public ImageView getTvBack() {
return tvBack;
@Override
public boolean onQueryTextChange(String newText) {
switch (viewPager.getCurrentItem()){
case 0:
((CatalogFragment) tabAdapter.getItem(0)).getmCatalogPresent().startSearch(newText);
break;
case 1:
((BookMarkFragment) tabAdapter.getItem(1)).getmBookMarkPresenter().startSearch(newText);
break;
}
return false;
}
});
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.home:
public EditText getEtSearch() {
return etSearch;
return true;
}
public ImageView getIvCancel() {
return ivCancel;
return super.onOptionsItemSelected(item);
}
}

@ -81,7 +81,7 @@ public class FileSystemActivity extends BaseTabActivity {
@Override
protected void setUpToolbar(Toolbar toolbar) {
super.setUpToolbar(toolbar);
setStatusBarColor(R.color.white, false);
setStatusBarColor(R.color.colorPrimary, true);
getSupportActionBar().setTitle("添加本地");
}

@ -1,49 +1,135 @@
package xyz.fycz.myreader.ui.activity;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;
import xyz.fycz.myreader.R;
import xyz.fycz.myreader.base.BaseActivity;
import butterknife.ButterKnife;
import androidx.appcompat.widget.Toolbar;
import butterknife.BindView;
import xyz.fycz.myreader.R;
import xyz.fycz.myreader.base.BaseActivity2;
import xyz.fycz.myreader.common.APPCONST;
import xyz.fycz.myreader.ui.presenter.FontsPresenter;
import xyz.fycz.myreader.enums.Font;
import xyz.fycz.myreader.ui.adapter.FontsAdapter;
import xyz.fycz.myreader.util.IOUtils;
import xyz.fycz.myreader.util.ToastUtils;
import xyz.fycz.myreader.util.utils.FileUtils;
import static xyz.fycz.myreader.util.UriFileUtil.getPath;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
public class FontsActivity extends BaseActivity {
import static xyz.fycz.myreader.util.UriFileUtil.getPath;
@BindView(R.id.ll_title_back)
LinearLayout llTitleBack;
@BindView(R.id.tv_title_text)
TextView tvTitleText;
@BindView(R.id.system_title)
LinearLayout systemTitle;
/**
* @author fengyue
* @date 2020/9/19 12:04
*/
public class FontsActivity extends BaseActivity2 {
@BindView(R.id.lv_fonts)
ListView lvFonts;
@BindView(R.id.pb_loading)
ProgressBar pbLoading;
private ArrayList<Font> mFonts;
private FontsAdapter mFontsAdapter;
private FontsPresenter mFontsPresenter;
@SuppressLint("HandlerLeak")
private Handler mHandler = new Handler(){
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fonts);
ButterKnife.bind(this);
setStatusBar(R.color.white, false);
mFontsPresenter = new FontsPresenter(this);
mFontsPresenter.start();
public void handleMessage(Message msg) {
switch (msg.what){
case 1:
initWidget();
break;
}
}
};
@Override
protected int getContentId() {
return R.layout.activity_fonts;
}
@Override
protected void setUpToolbar(Toolbar toolbar) {
super.setUpToolbar(toolbar);
setStatusBarColor(R.color.colorPrimary, true);
getSupportActionBar().setTitle("字体");
}
@Override
protected void initData(Bundle savedInstanceState) {
super.initData(savedInstanceState);
initFonts();
}
@Override
protected void initWidget() {
super.initWidget();
mFontsAdapter = new FontsAdapter(this, R.layout.listview_font_item, mFonts, this);
lvFonts.setAdapter(mFontsAdapter);
pbLoading.setVisibility(View.GONE);
}
private void initFonts() {
mFonts = new ArrayList<>();
mFonts.add(Font.默认字体);
mFonts.add(Font.方正楷体);
mFonts.add(Font.经典宋体);
mFonts.add(Font.方正行楷);
mFonts.add(Font.迷你隶书);
mFonts.add(Font.方正黄草);
mFonts.add(Font.方正硬笔行书);
mFonts.add(Font.本地字体);
}
public void saveLocalFont(String path){
File fontFile = new File(path);
if (!fontFile.exists()){
ToastUtils.showWarring("未找到字体文件!");
return;
}
String fontName = fontFile.getName();
if (!fontName.endsWith(".ttf")){
ToastUtils.showError("字体更换失败,请选择ttf格式的字体文件!");
return;
}
String dirPath = fontFile.getParentFile().getAbsolutePath() + "/";
if (dirPath.equals(APPCONST.FONT_BOOK_DIR)){
mFontsAdapter.saveLocalFontName(fontName);
return;
}
FileInputStream fis = null;
FileOutputStream fos = null;
try {
fis = new FileInputStream(fontFile);
fos = new FileOutputStream(FileUtils.getFile(APPCONST.FONT_BOOK_DIR + fontName));
byte[] bytes = new byte[1021];
int len = -1;
while ((len = fis.read(bytes)) != -1){
fos.write(bytes, 0, len);
}
fos.flush();
mFontsAdapter.saveLocalFontName(fontName);
} catch (IOException e) {
e.printStackTrace();
ToastUtils.showError("读取字体文件出错!\n" + e.getLocalizedMessage());
}finally {
IOUtils.close(fis, fos);
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
String path;
@ -54,32 +140,12 @@ public class FontsActivity extends BaseActivity {
}else {
path = getPath(this, uri);
}
mFontsPresenter.saveLocalFont(path);
saveLocalFont(path);
}
}
@Override
protected void onResume() {
super.onResume();
mFontsPresenter.notifyChange();
}
public ProgressBar getPbLoading() {
return pbLoading;
}
public LinearLayout getLlTitleBack() {
return llTitleBack;
}
public TextView getTvTitleText() {
return tvTitleText;
}
public LinearLayout getSystemTitle() {
return systemTitle;
}
public ListView getLvFonts() {
return lvFonts;
mFontsAdapter.notifyDataSetChanged();
}
}

@ -1,33 +1,44 @@
package xyz.fycz.myreader.ui.activity;
/**
* @author fengyue
* @date 2020/4/26 18:49
*/
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Intent;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.MotionEvent;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.*;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.appcompat.widget.Toolbar;
import butterknife.BindView;
import butterknife.ButterKnife;
import com.google.android.material.textfield.TextInputLayout;
import xyz.fycz.myreader.R;
import xyz.fycz.myreader.base.BaseActivity;
import xyz.fycz.myreader.ui.presenter.LoginPresenter;
import xyz.fycz.myreader.backup.UserService;
import xyz.fycz.myreader.base.BaseActivity2;
import xyz.fycz.myreader.callback.ResultCallback;
import xyz.fycz.myreader.common.APPCONST;
import xyz.fycz.myreader.creator.DialogCreator;
import xyz.fycz.myreader.util.CodeUtil;
import xyz.fycz.myreader.util.CyptoUtils;
import xyz.fycz.myreader.util.ToastUtils;
import xyz.fycz.myreader.util.utils.NetworkUtils;
import xyz.fycz.myreader.util.utils.StringUtils;
import java.util.HashMap;
import java.util.Map;
@SuppressLint("Registered")
public class LoginActivity extends BaseActivity implements TextWatcher {
@BindView(R.id.ll_title_back)
LinearLayout llTitleBack;
@BindView(R.id.tv_title_text)
TextView tvTitleText;
/**
* @author fengyue
* @date 2020/9/18 22:27
*/
public class LoginActivity extends BaseActivity2 implements TextWatcher {
@BindView(R.id.et_user)
TextInputLayout user;
@BindView(R.id.et_password)
@ -40,15 +51,122 @@ public class LoginActivity extends BaseActivity implements TextWatcher {
TextInputLayout etCaptcha;
@BindView(R.id.iv_captcha)
ImageView ivCaptcha;
private LoginPresenter mLoginPresenter;
private String code;
@SuppressLint("HandlerLeak")
private Handler mHandler = new Handler() {
@SuppressLint("HandlerLeak")
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case 1:
loginBtn.setEnabled(true);
break;
case 2:
createCaptcha();
break;
}
}
};
@Override
protected int getContentId() {
return R.layout.activity_login;
}
@Override
protected void setUpToolbar(Toolbar toolbar) {
super.setUpToolbar(toolbar);
setStatusBarColor(R.color.colorPrimary, true);
getSupportActionBar().setTitle("登录");
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
ButterKnife.bind(this);
setStatusBar(R.color.white, false);
mLoginPresenter = new LoginPresenter(this);
mLoginPresenter.start();
protected void initData(Bundle savedInstanceState) {
super.initData(savedInstanceState);
}
@Override
protected void initWidget() {
super.initWidget();
mHandler.sendMessage(mHandler.obtainMessage(2));
String username = UserService.readUsername();
user.getEditText().setText(username);
user.getEditText().requestFocus(username.length());
//监听内容改变 -> 控制按钮的点击状态
user.getEditText().addTextChangedListener(this);
password.getEditText().addTextChangedListener(this);
etCaptcha.getEditText().addTextChangedListener(this);
}
@Override
protected void initClick() {
super.initClick();
ivCaptcha.setOnClickListener(v -> mHandler.sendMessage(mHandler.obtainMessage(2)));
loginBtn.setOnClickListener(v -> {
mHandler.sendMessage(mHandler.obtainMessage(2));
if (!code.toLowerCase().equals(etCaptcha.getEditText().getText().toString().toLowerCase())){
DialogCreator.createTipDialog(this, "验证码错误!");
return;
}
if (!NetworkUtils.isNetWorkAvailable()) {
ToastUtils.showError("无网络连接!");
return;
}
ProgressDialog dialog = DialogCreator.createProgressDialog(this, null, "正在登陆...");
loginBtn.setEnabled(false);
final String loginName = user.getEditText().getText().toString().trim();
String loginPwd = password.getEditText().getText().toString();
final Map<String, String> userLoginInfo = new HashMap<>();
userLoginInfo.put("loginName", loginName);
userLoginInfo.put("loginPwd", CyptoUtils.encode(APPCONST.KEY, loginPwd));
//验证用户名和密码
UserService.login(userLoginInfo, new ResultCallback() {
@Override
public void onFinish(Object o, int code) {
String result = (String) o;
String[] info = result.split(":");
int resultCode = Integer.parseInt(info[0].trim());
String resultName = info[1].trim();
//最后输出结果
if (resultCode == 102) {
UserService.writeConfig(userLoginInfo);
UserService.writeUsername(loginName);
Intent intent = new Intent();
intent.putExtra("isLogin", true);
setResult(Activity.RESULT_OK, intent);
finish();
ToastUtils.showSuccess(resultName);
} else {
mHandler.sendMessage(mHandler.obtainMessage(1));
dialog.dismiss();
ToastUtils.showWarring(resultName);
}
}
@Override
public void onError(Exception e) {
ToastUtils.showError("登录失败\n" + e.getLocalizedMessage());
mHandler.sendMessage(mHandler.obtainMessage(1));
dialog.dismiss();
}
});
});
tvRegister.setOnClickListener(v -> {
Intent intent = new Intent(LoginActivity.this, RegisterActivity.class);
startActivity(intent);
});
}
public void createCaptcha() {
code = CodeUtil.getInstance().createCode();
Bitmap codeBitmap = CodeUtil.getInstance().createBitmap(code);
ivCaptcha.setImageBitmap(codeBitmap);
}
@ -110,37 +228,4 @@ public class LoginActivity extends BaseActivity implements TextWatcher {
loginBtn.setEnabled(false);
}
}
public EditText getUser() {
return user.getEditText();
}
public EditText getPassword() {
return password.getEditText();
}
public Button getLoginBtn() {
return loginBtn;
}
public TextView getTvTitleText() {
return tvTitleText;
}
public LinearLayout getLlTitleBack() {
return llTitleBack;
}
public TextView getTvRegister() {
return tvRegister;
}
public EditText getEtCaptcha() {
return etCaptcha.getEditText();
}
public ImageView getIvCaptcha() {
return ivCaptcha;
}
}

@ -1,77 +1,260 @@
package xyz.fycz.myreader.ui.activity;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.provider.Settings;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatDelegate;
import androidx.appcompat.widget.Toolbar;
import androidx.core.content.FileProvider;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentPagerAdapter;
import androidx.viewpager.widget.ViewPager;
import com.google.android.material.tabs.TabLayout;
import butterknife.BindView;
import com.google.android.material.bottomnavigation.BottomNavigationView;
import xyz.fycz.myreader.R;
import xyz.fycz.myreader.application.MyApplication;
import xyz.fycz.myreader.base.BaseActivity;
import xyz.fycz.myreader.application.SysManager;
import xyz.fycz.myreader.base.BaseActivity2;
import xyz.fycz.myreader.common.APPCONST;
import xyz.fycz.myreader.creator.DialogCreator;
import xyz.fycz.myreader.custom.CircleImageView;
import xyz.fycz.myreader.ui.presenter.MainPresenter;
import butterknife.BindView;
import butterknife.ButterKnife;
import xyz.fycz.myreader.ui.fragment.BookStoreFragment;
import xyz.fycz.myreader.ui.fragment.BookcaseFragment;
import xyz.fycz.myreader.ui.fragment.FindFragment;
import xyz.fycz.myreader.ui.fragment.MineFragment;
import xyz.fycz.myreader.ui.presenter.BookcasePresenter;
import xyz.fycz.myreader.util.SharedPreUtils;
import xyz.fycz.myreader.util.ToastUtils;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import static androidx.fragment.app.FragmentPagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT;
import static xyz.fycz.myreader.application.MyApplication.checkVersionByServer;
import static xyz.fycz.myreader.util.UriFileUtil.getPath;
/**
* @author fengyue
* @date 2020/9/13 13:03
*/
public class MainActivity extends BaseActivity2 {
@BindView(R.id.bottom_navigation_view)
BottomNavigationView bottomNavigation;
@BindView(R.id.view_pager_main)
ViewPager viewPagerMain;
private List<Fragment> mFragments = new ArrayList<>();
private String[] titles;
private String groupName;
private File appFile;
private boolean isForceUpdate;
private BookcaseFragment mBookcaseFragment;
private FindFragment mFindFragment;
private MineFragment mMineFragment;
public class MainActivity extends BaseActivity {
@Override
protected int getContentId() {
return R.layout.activity_main;
}
@Override
protected void setUpToolbar(Toolbar toolbar) {
super.setUpToolbar(toolbar);
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.setDisplayHomeAsUpEnabled(false);
actionBar.setDisplayShowHomeEnabled(false);
}
getSupportActionBar().setTitle(titles[0]);
getSupportActionBar().setSubtitle(groupName);
setStatusBarColor(R.color.colorPrimary, true);
}
@BindView(R.id.civ_avatar)
CircleImageView civAvatar;
@BindView(R.id.tl_tab_menu)
TabLayout tlTabMenu;
@BindView(R.id.iv_search)
ImageView ivSearch;
@BindView(R.id.iv_more)
ImageView ivMore;
@BindView(R.id.rl_common_title)
RelativeLayout rlCommonTitle;
@BindView(R.id.tv_edit_finish)
TextView tvEditFinish;
@BindView(R.id.rl_edit_titile)
RelativeLayout rlEditTitle;
@BindView(R.id.vp_content)
ViewPager vpContent;
private MainPresenter mMainPrensenter;
@Override
protected void initData(Bundle savedInstanceState) {
super.initData(savedInstanceState);
groupName = SharedPreUtils.getInstance().getString("curBookGroupName", "");
titles = new String[]{"书架", "发现", "我的"};
mBookcaseFragment = new BookcaseFragment();
mFindFragment = new FindFragment();
mMineFragment = new MineFragment();
mFragments.add(mBookcaseFragment);
mFragments.add(mFindFragment);
mFragments.add(mMineFragment);
}
@Override
protected void initWidget() {
super.initWidget();
viewPagerMain.setOffscreenPageLimit(2);
viewPagerMain.setAdapter(new FragmentPagerAdapter(getSupportFragmentManager(), BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {
@Override
public int getCount() {
return mFragments.size();
}
private File appFile;
private boolean isForceUpdate;
@NonNull
@Override
public Fragment getItem(int position) {
return mFragments.get(position);
}
});
}
@Override
protected void initClick() {
super.initClick();
//BottomNavigationView 点击事件监听
bottomNavigation.setOnNavigationItemSelectedListener(menuItem -> {
int menuId = menuItem.getItemId();
// 跳转指定页面:Fragment
switch (menuId) {
case R.id.menu_bookshelf:
viewPagerMain.setCurrentItem(0);
break;
case R.id.menu_find_book:
viewPagerMain.setCurrentItem(1);
break;
case R.id.menu_my_config:
viewPagerMain.setCurrentItem(2);
break;
}
return false;
});
// ViewPager 滑动事件监听
viewPagerMain.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int i, float v, int i1) {
}
@Override
public void onPageSelected(int i) {
//将滑动到的页面对应的 menu 设置为选中状态
bottomNavigation.getMenu().getItem(i).setChecked(true);
getSupportActionBar().setTitle(titles[i]);
if (i == 0) {
getSupportActionBar().setSubtitle(groupName);
}else {
getSupportActionBar().setSubtitle("");
}
invalidateOptionsMenu();
/*if (i == 1){
((BookStoreFragment) mFragments.get(i)).lazyLoad();
}*/
}
@Override
public void onPageScrollStateChanged(int i) {
}
});
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
setStatusBar(R.color.white, false);
mMainPrensenter = new MainPresenter(this);
mMainPrensenter.start();
protected void processLogic() {
super.processLogic();
try {
int settingVersion = SysManager.getSetting().getSettingVersion();
if (settingVersion < APPCONST.SETTING_VERSION){
SysManager.resetSetting();
}
}catch (Exception e){
SysManager.resetSetting();
}
}
private void reLoadFragment() {
List<Fragment> fragments = getSupportFragmentManager().getFragments();
mBookcaseFragment = (BookcaseFragment) fragments.get(0);
mFindFragment = (FindFragment) fragments.get(1);
mMineFragment = (MineFragment) fragments.get(2);
}
public ViewPager getViewPagerMain() {
return viewPagerMain;
}
/********************************Event***************************************/
/**
* 创建菜单
*
* @param menu
* @return
*/
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_book, menu);
return true;
}
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
if (viewPagerMain.getCurrentItem() == 0) {
if (mBookcaseFragment.getmBookcasePresenter() != null && mBookcaseFragment.getmBookcasePresenter().ismEditState()) {
menu.findItem(R.id.action_finish).setVisible(true);
menu.setGroupVisible(R.id.bookcase_menu, false);
} else {
menu.setGroupVisible(R.id.bookcase_menu, true);
menu.findItem(R.id.action_finish).setVisible(false);
}
} else {
menu.setGroupVisible(R.id.bookcase_menu, false);
menu.findItem(R.id.action_finish).setVisible(false);
}
return super.onPrepareOptionsMenu(menu);
}
/**
* 导航栏菜单点击事件
*
* @param item
* @return
*/
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (mBookcaseFragment.isRecreate()) {
reLoadFragment();
}
switch (item.getItemId()) {
case R.id.action_search:
Intent searchBookIntent = new Intent(this, SearchBookActivity.class);
startActivity(searchBookIntent);
return true;
case R.id.action_finish:
mBookcaseFragment.getmBookcasePresenter().cancelEdit();
invalidateOptionsMenu();
return true;
case R.id.action_change_group:
mBookcaseFragment.getmBookcasePresenter()
.showBookGroupMenu(findViewById(R.id.action_change_group), () -> {
groupName = SharedPreUtils.getInstance().getString("curBookGroupName", "所有书籍");
getSupportActionBar().setSubtitle(groupName);
});
case R.id.action_edit:
invalidateOptionsMenu();
break;
}
return mBookcaseFragment.getmBookcasePresenter().onOptionsItemSelected(item);
}
@Override
public void onBackPressed() {
if (mMainPrensenter.ismEditState()){
mMainPrensenter.cancelEdit();
if (mBookcaseFragment.getmBookcasePresenter() != null && mBookcaseFragment.getmBookcasePresenter().ismEditState()) {
mBookcaseFragment.getmBookcasePresenter().cancelEdit();
invalidateOptionsMenu();
return;
}
if (System.currentTimeMillis() - APPCONST.exitTime > APPCONST.exitConfirmTime) {
@ -88,19 +271,21 @@ public class MainActivity extends BaseActivity {
// MyApplication.checkVersionByServer(this);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if ((resultCode == RESULT_OK || resultCode == RESULT_CANCELED) && requestCode == APPCONST.APP_INSTALL_CODE) {
installProcess(appFile, isForceUpdate);//再次执行安装流程,包含权限判等
}else if (resultCode == RESULT_OK && requestCode == APPCONST.SELECT_FILE_CODE){
String path;
Uri uri = data.getData();
if ("file".equalsIgnoreCase(uri.getScheme())){//使用第三方应用打开
path = uri.getPath();
}else {
path = getPath(this, uri);
}
mMainPrensenter.addLocalBook(path);
if (resultCode == RESULT_OK) {
switch (requestCode) {
case APPCONST.REQUEST_LOGIN:
if (mMineFragment.isRecreate()){
reLoadFragment();
}
mMineFragment.onActivityResult(requestCode, resultCode, data);
break;
}
}
}
@ -119,7 +304,6 @@ public class MainActivity extends BaseActivity {
} else {
ToastUtils.showWarring("用户拒绝开启读写权限");
}
return;
}
}
}
@ -165,6 +349,7 @@ public class MainActivity extends BaseActivity {
/**
* 安装应用
*
* @param file
* @param isForceUpdate
*/
@ -186,35 +371,7 @@ public class MainActivity extends BaseActivity {
}
}
public CircleImageView getCivAvatar() {
return civAvatar;
}
public TabLayout getTlTabMenu() {
return tlTabMenu;
}
public ImageView getIvSearch() {
return ivSearch;
}
public ViewPager getVpContent() {
return vpContent;
}
public RelativeLayout getRlCommonTitle() {
return rlCommonTitle;
}
public TextView getTvEditFinish() {
return tvEditFinish;
}
public RelativeLayout getRlEditTitle() {
return rlEditTitle;
}
public ImageView getIvMore() {
return ivMore;
public interface OnGroupChangeListener{
void onChange();
}
}

@ -18,13 +18,21 @@ import xyz.fycz.myreader.common.APPCONST;
import xyz.fycz.myreader.creator.DialogCreator;
import xyz.fycz.myreader.creator.MultiChoiceDialog;
import xyz.fycz.myreader.entity.Setting;
import xyz.fycz.myreader.enums.BookSource;
import xyz.fycz.myreader.greendao.entity.Book;
import xyz.fycz.myreader.greendao.service.BookService;
import xyz.fycz.myreader.util.utils.FileUtils;
import xyz.fycz.myreader.util.SharedPreUtils;
import xyz.fycz.myreader.util.ToastUtils;
import xyz.fycz.myreader.webapi.crawler.ReadCrawlerUtil;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import static xyz.fycz.myreader.common.APPCONST.BOOK_CACHE_PATH;
/**
* Created by newbiechen on 17-6-6.
* 阅读界面的更多设置
@ -45,6 +53,8 @@ public class MoreSettingActivity extends BaseActivity2 {
SwitchCompat mScAutoRefresh;
@BindView(R.id.more_setting_ll_close_refresh)
LinearLayout mLlCloseRefresh;
@BindView(R.id.more_setting_ll_disable_source)
LinearLayout mLlDisableSource;
@BindView(R.id.more_setting_iv_match_chapter_tip)
ImageView mIvMatchChapterTip;
@BindView(R.id.more_setting_rl_match_chapter)
@ -63,11 +73,16 @@ public class MoreSettingActivity extends BaseActivity2 {
RelativeLayout mRlDeleteCathe;
@BindView(R.id.more_setting_ll_download_all)
LinearLayout mLlDownloadAll;
/*@BindView(R.id.more_setting_rl_bookstore)
RelativeLayout mRlBookstore;
@BindView(R.id.more_setting_sc_bookstore)
SwitchCompat mScBookstore;*/
private Setting mSetting;
private boolean isVolumeTurnPage;
private int resetScreenTime;
private boolean autoRefresh;
private boolean isMatchChapter;
private boolean openBookStore;
private float matchChapterSuitability;
private int catheCap;
@ -77,8 +92,12 @@ public class MoreSettingActivity extends BaseActivity2 {
//选择禁用更新书籍对话框
private AlertDialog mCloseRefreshDia;
//选择禁用更新书源对话框
private AlertDialog mDisableSourceDia;
//选择一键缓存书籍对话框
private AlertDialog mDownloadAllDia;
//选择清除缓存对话框
private AlertDialog mDeleteCatheDia;
@Override
protected int getContentId() {
@ -95,6 +114,7 @@ public class MoreSettingActivity extends BaseActivity2 {
matchChapterSuitability = mSetting.getMatchChapterSuitability();
catheCap = mSetting.getCatheGap();
autoRefresh = mSetting.isRefreshWhenStart();
openBookStore = mSetting.isOpenBookStore();
}
@Override
@ -119,6 +139,7 @@ public class MoreSettingActivity extends BaseActivity2 {
mScVolume.setChecked(isVolumeTurnPage);
mScMatchChapter.setChecked(isMatchChapter);
mScAutoRefresh.setChecked(autoRefresh);
//mScBookstore.setChecked(openBookStore);
}
@Override
@ -194,6 +215,52 @@ public class MoreSettingActivity extends BaseActivity2 {
});
});
mLlDisableSource.setOnClickListener(v -> {
if (mDisableSourceDia != null) {
mDisableSourceDia.show();
return;
}
HashMap<CharSequence, Boolean> mSources = ReadCrawlerUtil.getDisableSources();
CharSequence[] mSourcesName = new CharSequence[mSources.keySet().size()];
boolean[] isDisables = new boolean[mSources.keySet().size()];
int dSourceCount = 0;
int i = 0;
for (CharSequence sourceName : mSources.keySet()) {
mSourcesName[i] = sourceName;
Boolean isDisable = mSources.get(sourceName);
if (isDisable == null) isDisable = false;
if (isDisable) dSourceCount++;
isDisables[i++] = isDisable;
}
mDisableSourceDia = new MultiChoiceDialog().create(this, "选择禁用的书源",
mSourcesName, isDisables, dSourceCount, (dialog, which) -> {
SharedPreUtils spu = SharedPreUtils.getInstance();
StringBuilder sb = new StringBuilder();
for (CharSequence sourceName : mSources.keySet()) {
if (!mSources.get(sourceName)) {
sb.append(BookSource.getFromName(String.valueOf(sourceName)));
sb.append(",");
}
}
if (sb.lastIndexOf(",") >= 0) sb.deleteCharAt(sb.lastIndexOf(","));
spu.putString("searchSource", sb.toString());
}, null, new DialogCreator.OnMultiDialogListener() {
@Override
public void onItemClick(DialogInterface dialog, int which, boolean isChecked) {
mSources.put(mSourcesName[which], isChecked);
}
@Override
public void onSelectAll(boolean isSelectAll) {
for (CharSequence sourceName : mSources.keySet()) {
mSources.put(sourceName, isSelectAll);
}
}
});
});
mRlMatchChapter.setOnClickListener(
(v) -> {
if (isMatchChapter) {
@ -264,12 +331,52 @@ public class MoreSettingActivity extends BaseActivity2 {
mRlCatheGap.setOnClickListener(v -> mScCatheGap.performClick());
mRlDeleteCathe.setOnClickListener(v -> {
DialogCreator.createCommonDialog(this, "清除缓存", "确定要清除全部书籍缓存吗?",
true, (dialog, which) -> {
MyApplication.runOnUiThread(() -> {
File catheFile = getCacheDir();
String catheFileSize = FileUtils.getFileSize(FileUtils.getDirSize(catheFile));
File eCatheFile = new File(BOOK_CACHE_PATH);
String eCatheFileSize;
if (eCatheFile.exists() && eCatheFile.isDirectory()) {
eCatheFileSize = FileUtils.getFileSize(FileUtils.getDirSize(eCatheFile));
}else {
eCatheFileSize = "0";
}
CharSequence[] cathes = {"章节缓存:" + eCatheFileSize, "图片缓存:" + catheFileSize};
boolean[] catheCheck = {true, true};
mDeleteCatheDia = new MultiChoiceDialog().create(this, "清除缓存", cathes, catheCheck, 2,
(dialog, which) -> {
String tip = "";
if (catheCheck[0]) {
BookService.getInstance().deleteAllBookCathe();
ToastUtils.showSuccess("清除缓存成功!");
}, null);
tip += "章节缓存 ";
}
if (catheCheck[1]) {
FileUtils.deleteFile(catheFile.getAbsolutePath());
tip += "图片缓存 ";
}
if (tip.length() > 0) {
tip += "清除成功";
ToastUtils.showSuccess(tip);
}
}, null, null);
});
});
/*mRlBookstore.setOnClickListener(
(v) -> {
if (openBookStore) {
openBookStore = false;
} else {
openBookStore = true;
}
mScBookstore.setChecked(openBookStore);
mSetting.setOpenBookStore(openBookStore);
SysManager.saveSetting(mSetting);
ToastUtils.showInfo("重启后生效!");
}
);*/
}
@Override
@ -281,8 +388,8 @@ public class MoreSettingActivity extends BaseActivity2 {
private void initSpinner() {
// initSwitchStatus() be called earlier than onCreate(), so setSelection() won't work
ArrayAdapter<CharSequence> resetScreenAdapter = ArrayAdapter.createFromResource(this,
R.array.reset_screen_time, android.R.layout.simple_spinner_item);
resetScreenAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
R.array.reset_screen_time, R.layout.spinner);
resetScreenAdapter.setDropDownViewResource(R.layout.spinner_item);
mScResetScreen.setAdapter(resetScreenAdapter);
int resetScreenSelection = 0;
@ -332,8 +439,8 @@ public class MoreSettingActivity extends BaseActivity2 {
ArrayAdapter<CharSequence> matchSuiAdapter = ArrayAdapter.createFromResource(this,
R.array.match_chapter_suitability, android.R.layout.simple_spinner_item);
matchSuiAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
R.array.match_chapter_suitability, R.layout.spinner);
matchSuiAdapter.setDropDownViewResource(R.layout.spinner_item);
mScMatchChapterSuitability.setAdapter(matchSuiAdapter);
if (matchChapterSuitability == 0.0) {
@ -360,8 +467,8 @@ public class MoreSettingActivity extends BaseActivity2 {
ArrayAdapter<CharSequence> catheGapAdapter = ArrayAdapter.createFromResource(this,
R.array.cathe_chapter_gap, android.R.layout.simple_spinner_item);
catheGapAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
R.array.cathe_chapter_gap, R.layout.spinner);
catheGapAdapter.setDropDownViewResource(R.layout.spinner_item);
mScCatheGap.setAdapter(catheGapAdapter);
if (catheCap == 0) {

@ -15,6 +15,7 @@ import androidx.appcompat.app.AppCompatActivity;
import butterknife.BindView;
import butterknife.ButterKnife;
import com.h6ah4i.android.widget.verticalseekbar.VerticalSeekBar;
import xyz.fycz.myreader.ActivityManage;
import xyz.fycz.myreader.R;
import xyz.fycz.myreader.application.SysManager;
import xyz.fycz.myreader.base.BaseActivity;
@ -25,7 +26,6 @@ import xyz.fycz.myreader.widget.page.PageView;
public class ReadActivity extends BaseActivity {
@BindView(R.id.pb_loading)
ProgressBar pbLoading;
@BindView(R.id.read_pv_page)
@ -117,9 +117,14 @@ public class ReadActivity extends BaseActivity {
result.putExtra(APPCONST.RESULT_HISTORY_CHAPTER, mReadPresenter.getmPageLoader().getChapterPos());
}
setResult(AppCompatActivity.RESULT_OK, result);
if (!ActivityManage.isExist(MainActivity.class)) {
Intent intent = new Intent(this, MainActivity.class);
startActivity(intent);
}
super.onBackPressed();
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
boolean isVolumeTurnPage = SysManager.getSetting().isVolumeTurnPage();

@ -1,27 +1,39 @@
package xyz.fycz.myreader.ui.activity;
/**
* @author fengyue
* @date 2020/4/26 18:49
*/
import android.annotation.SuppressLint;
import android.app.ProgressDialog;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.widget.*;
import android.os.Handler;
import android.os.Message;
import android.text.Editable;
import android.text.TextWatcher;
import android.text.method.LinkMovementMethod;
import android.view.View;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.appcompat.widget.Toolbar;
import butterknife.BindView;
import butterknife.ButterKnife;
import com.google.android.material.textfield.TextInputLayout;
import xyz.fycz.myreader.R;
import xyz.fycz.myreader.base.BaseActivity;
import xyz.fycz.myreader.ui.presenter.RegisterPresenter;
import xyz.fycz.myreader.backup.UserService;
import xyz.fycz.myreader.base.BaseActivity2;
import xyz.fycz.myreader.callback.ResultCallback;
import xyz.fycz.myreader.creator.DialogCreator;
import xyz.fycz.myreader.util.CodeUtil;
import xyz.fycz.myreader.util.ToastUtils;
import xyz.fycz.myreader.util.utils.StringUtils;
import java.util.HashMap;
import java.util.Map;
@SuppressLint("Registered")
public class RegisterActivity extends BaseActivity{
@BindView(R.id.ll_title_back)
LinearLayout llTitleBack;
@BindView(R.id.tv_title_text)
TextView tvTitleText;
/**
* @author fengyue
* @date 2020/9/18 22:37
*/
public class RegisterActivity extends BaseActivity2 {
@BindView(R.id.et_username)
TextInputLayout etUsername;
@BindView(R.id.et_password)
@ -40,58 +52,221 @@ public class RegisterActivity extends BaseActivity{
CheckBox cbAgreement;
@BindView(R.id.tv_agreement)
TextView tvAgreement;
private RegisterPresenter mRegisterPresenter;
private String code;
private String username = "";
private String password = "";
private String rpPassword = "";
private String inputCode = "";
@SuppressLint("HandlerLeak")
private Handler mHandler = new Handler() {
@SuppressLint("HandlerLeak")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_register);
ButterKnife.bind(this);
setStatusBar(R.color.white, false);
mRegisterPresenter = new RegisterPresenter(this);
mRegisterPresenter.start();
public void handleMessage(Message msg) {
switch (msg.what) {
case 1:
createCaptcha();
break;
case 2:
showTip((String) msg.obj);
break;
case 3:
tvRegisterTip.setVisibility(View.GONE);
break;
}
}
};
public LinearLayout getLlTitleBack() {
return llTitleBack;
@Override
protected int getContentId() {
return R.layout.activity_register;
}
public TextView getTvTitleText() {
return tvTitleText;
@Override
protected void setUpToolbar(Toolbar toolbar) {
super.setUpToolbar(toolbar);
setStatusBarColor(R.color.colorPrimary, true);
getSupportActionBar().setTitle("注册");
}
public EditText getEtUsername() {
return etUsername.getEditText();
@Override
protected void initWidget() {
super.initWidget();
mHandler.sendMessage(mHandler.obtainMessage(1));
etUsername.requestFocus();
etUsername.getEditText().addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
public EditText getEtPassword() {
return etPassword.getEditText();
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
public EditText getEtRpPassword() {
return etRpPassword.getEditText();
@Override
public void afterTextChanged(Editable s) {
StringUtils.isNotChinese(s);
username = s.toString();
if (username.length() < 6 || username.length() >14){
mHandler.sendMessage(mHandler.obtainMessage(2, "用户名必须在6-14位之间"));
} else if(!username.substring(0, 1).matches("^[A-Za-z]$")){
mHandler.sendMessage(mHandler.obtainMessage(2,
"用户名只能以字母开头"));
}else if(!username.matches("^[A-Za-z0-9-_]+$")){
mHandler.sendMessage(mHandler.obtainMessage(2,
"用户名只能由数字、字母、下划线、减号组成"));
}else {
mHandler.sendMessage(mHandler.obtainMessage(3));
}
checkNotNone();
}
});
etPassword.getEditText().addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
public EditText getEtCaptcha() {
return etCaptcha.getEditText();
}
public ImageView getIvCaptcha() {
return ivCaptcha;
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
public Button getBtRegister() {
return btRegister;
@Override
public void afterTextChanged(Editable s) {
password = s.toString();
if (password.length() < 8 || password.length() > 16){
mHandler.sendMessage(mHandler.obtainMessage(2, "密码必须在8-16位之间"));
} else if(password.matches("^\\d+$")){
mHandler.sendMessage(mHandler.obtainMessage(2, "密码不能是纯数字"));
} else {
mHandler.sendMessage(mHandler.obtainMessage(3));
}
checkNotNone();
}
});
etRpPassword.getEditText().addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
public TextView getTvRegisterTip() {
return tvRegisterTip;
}
public CheckBox getCbAgreement() {
return cbAgreement;
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
public TextView getTvAgreement() {
return tvAgreement;
@Override
public void afterTextChanged(Editable s) {
rpPassword = s.toString();
if (!rpPassword.equals(password)){
mHandler.sendMessage(mHandler.obtainMessage(2, "两次输入的密码不一致"));
} else {
mHandler.sendMessage(mHandler.obtainMessage(3));
}
checkNotNone();
}
});
etCaptcha.getEditText().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) {
}
@Override
public void afterTextChanged(Editable s) {
inputCode = s.toString().trim().toLowerCase();
if (!inputCode.equals(code.toLowerCase())){
mHandler.sendMessage(mHandler.obtainMessage(2, "验证码错误"));
} else {
mHandler.sendMessage(mHandler.obtainMessage(3));
}
checkNotNone();
}
});
tvAgreement.setMovementMethod(LinkMovementMethod.getInstance());
}
@Override
protected void initClick() {
super.initClick();
ivCaptcha.setOnClickListener(v -> mHandler.sendMessage(mHandler.obtainMessage(1)));
btRegister.setOnClickListener(v -> {
if (!username.matches("^[A-Za-z][A-Za-z0-9]{5,13}$")){
DialogCreator.createTipDialog(this, "用户名格式错误",
"用户名必须在6-14位之间\n用户名只能以字母开头\n用户名只能由数字、字母、下划线、减号组成");
}else if(password.matches("^\\d+$") || !password.matches("^.{8,16}$")){
DialogCreator.createTipDialog(this, "密码格式错误",
"密码必须在8-16位之间\n密码不能是纯数字");
}else if(!password.equals(rpPassword)){
DialogCreator.createTipDialog(this, "重复密码错误",
"两次输入的密码不一致");
}else if(!inputCode.trim().toLowerCase().equals(code.toLowerCase())){
DialogCreator.createTipDialog(this, "验证码错误");
}else if(!cbAgreement.isChecked()){
DialogCreator.createTipDialog(this, "请勾选同意《用户服务协议》");
}else {
ProgressDialog dialog = DialogCreator.createProgressDialog(this, null, "正在注册...");
Map<String, String> userRegisterInfo = new HashMap<>();
userRegisterInfo.put("username", username);
userRegisterInfo.put("password", password);
UserService.register(userRegisterInfo, new ResultCallback() {
@Override
public void onFinish(Object o, int code) {
String[] info = ((String) o).split(":");
int result = Integer.parseInt(info[0].trim());
if (result == 101){
UserService.writeUsername(username);
ToastUtils.showSuccess(info[1]);
finish();
}else {
ToastUtils.showWarring(info[1]);
}
dialog.dismiss();
}
@Override
public void onError(Exception e) {
ToastUtils.showError("注册失败:\n" + e.getLocalizedMessage());
dialog.dismiss();
}
});
}
mHandler.sendMessage(mHandler.obtainMessage(1));
});
}
public void createCaptcha() {
code = CodeUtil.getInstance().createCode();
Bitmap codeBitmap = CodeUtil.getInstance().createBitmap(code);
ivCaptcha.setImageBitmap(codeBitmap);
}
public void showTip(String tip) {
tvRegisterTip.setVisibility(View.VISIBLE);
tvRegisterTip.setText(tip);
}
public void checkNotNone(){
if ("".equals(username) || "".equals(password) || "".equals(rpPassword) || "".equals(inputCode)){
btRegister.setEnabled(false);
}else {
btRegister.setEnabled(true);
}
}
}

@ -1,36 +1,59 @@
package xyz.fycz.myreader.ui.activity;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.KeyEvent;
import android.view.View;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import android.widget.*;
import com.scwang.smartrefresh.layout.SmartRefreshLayout;
import xyz.fycz.myreader.R;
import xyz.fycz.myreader.base.BaseActivity;
import butterknife.ButterKnife;
import androidx.appcompat.widget.Toolbar;
import butterknife.BindView;
import com.scwang.smartrefresh.layout.SmartRefreshLayout;
import me.gujun.android.taggroup.TagGroup;
import xyz.fycz.myreader.R;
import xyz.fycz.myreader.application.MyApplication;
import xyz.fycz.myreader.base.BaseActivity2;
import xyz.fycz.myreader.callback.ResultCallback;
import xyz.fycz.myreader.common.APPCONST;
import xyz.fycz.myreader.custom.DragSortGridView;
import xyz.fycz.myreader.ui.presenter.SearchBookPrensenter;
import xyz.fycz.myreader.entity.SearchBookBean;
import xyz.fycz.myreader.greendao.entity.Book;
import xyz.fycz.myreader.greendao.entity.SearchHistory;
import xyz.fycz.myreader.greendao.service.SearchHistoryService;
import xyz.fycz.myreader.mulvalmap.ConcurrentMultiValueMap;
import xyz.fycz.myreader.ui.adapter.SearchBookAdapter;
import xyz.fycz.myreader.ui.adapter.SearchHistoryAdapter;
import xyz.fycz.myreader.util.StringHelper;
import xyz.fycz.myreader.util.ToastUtils;
import xyz.fycz.myreader.webapi.CommonApi;
import xyz.fycz.myreader.webapi.crawler.ReadCrawler;
import xyz.fycz.myreader.webapi.crawler.ReadCrawlerUtil;
public class SearchBookActivity extends BaseActivity {
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@BindView(R.id.ll_title_back)
LinearLayout llTitleBack;
@BindView(R.id.tv_title_text)
TextView tvTitleText;
@BindView(R.id.system_title)
LinearLayout systemTitle;
/**
* @author fengyue
* @date 2020/9/18 21:58
*/
public class SearchBookActivity extends BaseActivity2 {
@BindView(R.id.et_search_key)
EditText etSearchKey;
@BindView(R.id.tv_search_conform)
TextView tvSearchConform;
@BindView(R.id.ll_refresh_suggest_books)
LinearLayout llRefreshSuggestBooks;
/*@BindView(R.id.lv_search_books_list)
ListView lvSearchBooksList;*/
@BindView(R.id.gv_search_books_list)
DragSortGridView gvSearchBooksList;
@BindView(R.id.ll_suggest_books_view)
@ -53,90 +76,344 @@ public class SearchBookActivity extends BaseActivity {
SmartRefreshLayout srlSearchBookList;
private SearchBookPrensenter mSearchBookPrensenter;
private SearchBookAdapter mSearchBookAdapter;
private String searchKey;//搜索关键字
private ArrayList<SearchBookBean> mBooksBean = new ArrayList<>();
private ConcurrentMultiValueMap<SearchBookBean, Book> mBooks = new ConcurrentMultiValueMap<>();
private ArrayList<Book> mAdapterBooks = new ArrayList<>();
private ArrayList<SearchHistory> mSearchHistories = new ArrayList<>();
private ArrayList<String> mSuggestions = new ArrayList<>();
private SearchHistoryService mSearchHistoryService;
private SearchHistoryAdapter mSearchHistoryAdapter;
private int curThreadCount;
private int allThreadCount;
private boolean isStopSearch;
private int inputConfirm = 0;//搜索输入确认
private int confirmTime = 1000;//搜索输入确认时间(毫秒)
private static String[] suggestion = {"第一序列", "大道朝天", "伏天氏", "终极斗罗", "我师兄实在太稳健了", "烂柯棋缘", "诡秘之主"};
private static String[] suggestion2 = {"不朽凡人", "圣墟", "我是至尊", "龙王传说", "太古神王", "一念永恒", "雪鹰领主", "大主宰"};
@SuppressLint("HandlerLeak")
private Handler mHandler = new Handler() {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_search_book);
ButterKnife.bind(this);
setStatusBar(R.color.white, false);
mSearchBookPrensenter = new SearchBookPrensenter(this);
mSearchBookPrensenter.start();
public void handleMessage(Message msg) {
switch (msg.what) {
case 1:
search();
break;
case 2:
if (curThreadCount == 0 && !isStopSearch) {
initSearchList();
srlSearchBookList.finishRefresh();
pbLoading.setVisibility(View.GONE);
}/*else {
notifyDataSetChanged();
mSearchBookActivity.getSrlSearchBookList().finishRefresh();
}*/
break;
}
}
};
@Override
protected int getContentId() {
return R.layout.activity_search_book;
}
@Override
public void onBackPressed() {
if (!mSearchBookPrensenter.onBackPressed()){
super.onBackPressed();
protected void setUpToolbar(Toolbar toolbar) {
super.setUpToolbar(toolbar);
setStatusBarColor(R.color.colorPrimary, true);
getSupportActionBar().setTitle("搜索");
}
@Override
protected void initData(Bundle savedInstanceState) {
super.initData(savedInstanceState);
mSearchHistoryService = SearchHistoryService.getInstance();
for (int i = 0; i < suggestion.length; i++) {
mSuggestions.add(suggestion[i]);
}
}
@Override
protected void initWidget() {
super.initWidget();
etSearchKey.requestFocus();//get the focus
//enter事件
etSearchKey.setOnEditorActionListener((textView, i, keyEvent) -> {
if (i == EditorInfo.IME_ACTION_UNSPECIFIED) {
mHandler.sendMessage(mHandler.obtainMessage(1));
return (keyEvent.getKeyCode() == KeyEvent.KEYCODE_ENTER);
}
return false;
});
//搜索框改变事件
etSearchKey.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
public LinearLayout getLlTitleBack() {
return llTitleBack;
}
public TextView getTvTitleText() {
return tvTitleText;
@Override
public void afterTextChanged(final Editable editable) {
searchKey = editable.toString();
if (StringHelper.isEmpty(searchKey)) {
mHandler.sendMessage(mHandler.obtainMessage(1));
}
public LinearLayout getSystemTitle() {
return systemTitle;
}
public EditText getEtSearchKey() {
return etSearchKey;
});
//上拉刷新
srlSearchBookList.setOnRefreshListener(refreshLayout -> mHandler.sendMessage(mHandler.obtainMessage(1)));
srlSearchBookList.setEnableRefresh(false);
gvSearchBooksList.setNumColumns(1);
gvSearchBooksList.setDragModel(-1);
initSuggestionBook();
initHistoryList();
}
public TextView getTvSearchConform() {
return tvSearchConform;
@Override
protected void initClick() {
super.initClick();
//换一批点击事件
renewByImage.setOnClickListener(new RenewSuggestionBook());
//换一批点击事件
renewByText.setOnClickListener(new RenewSuggestionBook());
//进入书籍详情页
gvSearchBooksList.setOnItemClickListener((adapterView, view, i, l) -> {
Intent intent = new Intent(this, BookDetailedActivity.class);
intent.putExtra(APPCONST.SEARCH_BOOK_BEAN, new ArrayList<>(mBooks.getValues(mBooksBean.get(i))));
startActivity(intent);
});
//搜索按钮点击事件
tvSearchConform.setOnClickListener(view -> mHandler.sendMessage(mHandler.obtainMessage(1)));
//suggestion搜索事件
tgSuggestBook.setOnTagClickListener(tag -> {
etSearchKey.setText(tag);
etSearchKey.setSelection(tag.length());
mHandler.sendMessage(mHandler.obtainMessage(1));
});
//历史记录搜索事件
lvHistoryList.setOnItemClickListener((parent, view, position, id) -> {
etSearchKey.setText(mSearchHistories.get(position).getContent());
etSearchKey.setSelection(mSearchHistories.get(position).getContent().length());
mHandler.sendMessage(mHandler.obtainMessage(1));
});
//清空历史记录
llClearHistory.setOnClickListener(v -> {
mSearchHistoryService.clearHistory();
initHistoryList();
});
//清除单个历史记录
lvHistoryList.setOnItemLongClickListener((parent, view, position, id) -> {
if (mSearchHistories.get(position) != null) {
mSearchHistoryService.deleteHistory(mSearchHistories.get(position));
initHistoryList();
}
return true;
});
}
public TagGroup getTgSuggestBook() {
return tgSuggestBook;
/**
* 初始化建议书目
*/
private void initSuggestionBook() {
tgSuggestBook.setTags(suggestion);
}
public LinearLayout getLlRefreshSuggestBooks() {
return llRefreshSuggestBooks;
private class RenewSuggestionBook implements View.OnClickListener {
@Override
public void onClick(View v) {
String[] s = tgSuggestBook.getTags();
if (Arrays.equals(s, suggestion)) {
tgSuggestBook.setTags(suggestion2);
} else {
tgSuggestBook.setTags(suggestion);
}
}
}
// public ListView getLvSearchBooksList() {
// return lvSearchBooksList;
// }
/**
* 初始化历史列表
*/
private void initHistoryList() {
mSearchHistories = mSearchHistoryService.findAllSearchHistory();
if (mSearchHistories == null || mSearchHistories.size() == 0) {
llHistoryView.setVisibility(View.GONE);
} else {
mSearchHistoryAdapter = new SearchHistoryAdapter(this, R.layout.listview_search_history_item, mSearchHistories);
lvHistoryList.setAdapter(mSearchHistoryAdapter);
llHistoryView.setVisibility(View.VISIBLE);
}
}
public DragSortGridView getGvSearchBooksList() {
return gvSearchBooksList;
/**
* 初始化搜索列表
*/
private void initSearchList() {
initmBooksBean();
mSearchBookAdapter = new SearchBookAdapter(this,
R.layout.listview_search_book_item, mBooksBean, mBooks);
gvSearchBooksList.setAdapter(mSearchBookAdapter);
gvSearchBooksList.setVisibility(View.VISIBLE);
llSuggestBooksView.setVisibility(View.GONE);
llSuggestBooksView.setVisibility(View.GONE);
}
public LinearLayout getLlSuggestBooksView() {
return llSuggestBooksView;
/**
* 更新搜索列表
*/
private void notifyDataSetChanged() {
if (curThreadCount == 0) {
pbLoading.setVisibility(View.GONE);
}
initmBooksBean();
}
public ProgressBar getPbLoading() {
return pbLoading;
/**
* 初始化mBooksBean
*/
private void initmBooksBean() {
synchronized (this) {
mBooksBean.clear();
mBooksBean.addAll(mBooks.keySet());
//排序,基于最符合关键字的搜书结果应该是最短的
//TODO ;这里只做了简单的比较排序,还需要继续完善
Collections.sort(mBooksBean, (o1, o2) -> {
if (searchKey.equals(o1.getName()))
return -1;
if (searchKey.equals(o2.getName()))
return 1;
if (searchKey.equals(o1.getAuthor()))
return -1;
if (searchKey.equals(o2.getAuthor()))
return 1;
if (o1.getName().length() < o2.getName().length())
return -1;
if (o1.getName().length() == o2.getName().length())
return 0;
return 1;
});
/*MyApplication.runOnUiThread(new Runnable() {
@Override
public void run() {
mSearchBookAdapter.notifyDataSetChanged();
}
});*/
}
}
public ListView getLvHistoryList() {
return lvHistoryList;
/**
* 获取搜索数据
*/
private void getData() {
mBooksBean.clear();
mBooks.clear();
ArrayList<ReadCrawler> readCrawlers = ReadCrawlerUtil.getReadCrawlers();
allThreadCount = readCrawlers.size();
if (allThreadCount == 0){
ToastUtils.showWarring("当前书源已全部禁用,无法搜索!");
pbLoading.setVisibility(View.GONE);
return;
}
curThreadCount = allThreadCount;
for (ReadCrawler readCrawler : readCrawlers){
searchBookByCrawler(readCrawler, readCrawler.getSearchCharset());
}
}
public LinearLayout getLlClearHistory() {
return llClearHistory;
/**
* 搜索
*/
private void search() {
pbLoading.setVisibility(View.VISIBLE);
if (StringHelper.isEmpty(searchKey)) {
isStopSearch = true;
pbLoading.setVisibility(View.GONE);
gvSearchBooksList.setVisibility(View.GONE);
llSuggestBooksView.setVisibility(View.VISIBLE);
initHistoryList();
gvSearchBooksList.setAdapter(null);
srlSearchBookList.setEnableRefresh(false);
} else {
isStopSearch = false;
gvSearchBooksList.setVisibility(View.VISIBLE);
llSuggestBooksView.setVisibility(View.GONE);
llHistoryView.setVisibility(View.GONE);
getData();
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (gvSearchBooksList.getmScrollView().getScrollY() == 0){
srlSearchBookList.setEnableRefresh(true);
}
//滑动监听器
gvSearchBooksList.getmScrollView().setOnScrollChangeListener((v, scrollX, scrollY, oldScrollX, oldScrollY) -> {
srlSearchBookList.setEnableRefresh(scrollY == 0);
});
}
mSearchHistoryService.addOrUpadteHistory(searchKey);
//收起软键盘
InputMethodManager imm = (InputMethodManager) MyApplication.getmContext().getSystemService(Context.INPUT_METHOD_SERVICE);
assert imm != null;
imm.hideSoftInputFromWindow(etSearchKey.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
}
}
public LinearLayout getLlHistoryView() {
return llHistoryView;
@Override
public void onBackPressed() {
if (StringHelper.isEmpty(searchKey)) {
super.onBackPressed();
} else {
etSearchKey.setText("");
}
}
public ImageView getRenewByImage() {
return renewByImage;
private void searchBookByCrawler(ReadCrawler rc, String charset) {
String searchKey = this.searchKey;
if (charset.toLowerCase().equals("gbk")) {
try {
searchKey = URLEncoder.encode(this.searchKey, charset);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
CommonApi.search(searchKey, rc, new ResultCallback() {
@Override
public void onFinish(Object o, int code) {
ConcurrentMultiValueMap<SearchBookBean, Book> sbb =
(ConcurrentMultiValueMap<SearchBookBean, Book>) o;
mBooks.addAll(sbb);
curThreadCount--;
mHandler.sendMessage(mHandler.obtainMessage(2));
}
public TextView getRenewByText() {
return renewByText;
@Override
public void onError(Exception e) {
curThreadCount--;
mHandler.sendMessage(mHandler.obtainMessage(2));
}
});
}
public SmartRefreshLayout getSrlSearchBookList() {
return srlSearchBookList;
@Override
protected void onDestroy() {
super.onDestroy();
isStopSearch = true;
}
}

@ -64,12 +64,13 @@ public class BookMarkAdapter extends ArrayAdapter<BookMark> {
} else {
viewHolder.tvTitle.setCompoundDrawablesWithIntrinsicBounds(getContext().getResources().getDrawable(R.drawable.selector_category_unload),null,null,null);
}
if (!setting.isDayStyle()) {
viewHolder.tvTitle.setTextColor(getContext().getColor(R.color.textSecondary));
/*if (!setting.isDayStyle()) {
viewHolder.tvTitle.setTextColor(getContext().getResources().getColor(R.color.sys_night_word));
viewHolder.vLine.setBackground(getContext().getDrawable(R.color.sys_dialog_setting_line));
}else {
viewHolder.tvTitle.setTextColor(getContext().getColor(R.color.title_black));
}
}*/
}
/**

@ -1,6 +1,8 @@
package xyz.fycz.myreader.ui.adapter;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Handler;
import android.os.Message;
import android.view.LayoutInflater;
@ -8,14 +10,23 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.resource.bitmap.RoundedCorners;
import com.bumptech.glide.request.RequestOptions;
import xyz.fycz.myreader.R;
import xyz.fycz.myreader.base.adapter.BaseListAdapter;
import xyz.fycz.myreader.base.adapter.IViewHolder;
import xyz.fycz.myreader.callback.ResultCallback;
import xyz.fycz.myreader.common.APPCONST;
import xyz.fycz.myreader.custom.DragAdapter;
import xyz.fycz.myreader.greendao.entity.Chapter;
import xyz.fycz.myreader.ui.activity.BookDetailedActivity;
import xyz.fycz.myreader.ui.adapter.holder.BookStoreBookHolder;
import xyz.fycz.myreader.webapi.crawler.BiQuGeReadCrawler;
import xyz.fycz.myreader.enums.BookSource;
import xyz.fycz.myreader.greendao.entity.Book;
@ -26,142 +37,18 @@ import xyz.fycz.myreader.webapi.CommonApi;
import java.util.List;
public class BookStoreBookAdapter extends RecyclerView.Adapter<BookStoreBookAdapter.ViewHolder> {
public class BookStoreBookAdapter extends BaseListAdapter<Book> {
private boolean hasImg;
private Activity mActivity;
private LayoutInflater mInflater;
private View view;
private List<Book> mDatas;
private Context mContext;
private RecyclerView rvContent;
private OnItemClickListener onItemClickListener;
private Handler mHandle = new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(Message message) {
switch (message.what) {
case 1:
ViewHolder holder = (ViewHolder) message.obj;
int pos = message.arg1;
BookStoreBookAdapter.this.initOtherInfo(pos, holder);
break;
}
return false;
}
});
public BookStoreBookAdapter(Context context, List<Book> datas) {
mInflater = LayoutInflater.from(context);
mDatas = datas;
mContext = context;
}
class ViewHolder extends RecyclerView.ViewHolder {
TextView tvBookName;
TextView tvBookAuthor;
TextView tvBookDesc;
TextView tvBookNewestChapter;
TextView tvBookSource;
ImageView ivBookImg;
ViewHolder() {
super(view);
}
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
if (rvContent == null) rvContent = (RecyclerView) parent;
view = mInflater.inflate(R.layout.listview_book_store_book_item, parent, false);
ViewHolder viewHolder = new ViewHolder();
viewHolder.tvBookName = view.findViewById(R.id.tv_book_name);
viewHolder.tvBookAuthor = view.findViewById(R.id.tv_book_author);
viewHolder.tvBookDesc = view.findViewById(R.id.tv_book_desc);
viewHolder.ivBookImg = view.findViewById(R.id.iv_book_img);
viewHolder.tvBookNewestChapter = view.findViewById(R.id.tv_book_newest_chapter);
viewHolder.tvBookSource = view.findViewById(R.id.tv_book_source);
return viewHolder;
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, final int position) {
initView(position, holder);
if (onItemClickListener != null){
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
onItemClickListener.onClick(position, view);
}
});
}
public BookStoreBookAdapter(boolean hasImg, Activity mActivity) {
this.hasImg = hasImg;
this.mActivity = mActivity;
}
@Override
public int getItemCount() {
return mDatas.size();
}
private void initView(final int position, final ViewHolder holder) {
Book book = mDatas.get(position);
holder.tvBookName.setText(book.getName());
holder.tvBookAuthor.setText(book.getAuthor());
holder.tvBookNewestChapter.setText("");
holder.tvBookSource.setText("书源:" + BookSource.fromString(book.getSource()).text);
holder.tvBookDesc.setText("");
if (StringHelper.isEmpty(book.getImgUrl())){
//获取小说详情
CommonApi.getBookInfo(book, new BiQuGeReadCrawler(), new ResultCallback() {
@Override
public void onFinish(Object o, int code) {
mDatas.set(position,(Book) o);
//防止列表快速滑动时出现书的信息加载混乱的问题
if (holder.tvBookName.getTag() == null || (int) holder.tvBookName.getTag() == position) {
mHandle.sendMessage(mHandle.obtainMessage(1,position,0,holder));
}
}
@Override
public void onError(Exception e) {
protected IViewHolder<Book> createViewHolder(int viewType) {
return new BookStoreBookHolder(hasImg, mActivity);
}
});
}else{
initOtherInfo(position,holder);
}
}
private void initOtherInfo(final int position, final ViewHolder holder){
Book book = mDatas.get(position);
//图片
Glide.with(mContext)
.load(book.getImgUrl())
// .override(DipPxUtil.dip2px(getContext(), 80), DipPxUtil.dip2px(getContext(), 150))
.error(R.mipmap.no_image)
.placeholder(R.mipmap.no_image)
//设置圆角
.apply(RequestOptions.bitmapTransform(new RoundedCorners(8)))
.into(holder.ivBookImg);
//简介
holder.tvBookDesc.setText("简介:" + book.getDesc());
holder.tvBookNewestChapter.setText("最新章节:" + book.getNewestChapterTitle());
}
public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
this.onItemClickListener = onItemClickListener;
}
public interface OnItemClickListener{
void onClick(int pos, View view);
}
}

@ -57,9 +57,15 @@ public class BookStoreBookTypeAdapter extends RecyclerView.Adapter<BookStoreBook
public void onBindViewHolder(@NonNull ViewHolder holder, final int position) {
initView(position, holder);
if (position == selectPos) {
holder.itemView.setBackgroundResource(R.color.white);
holder.itemView.setBackgroundResource(R.color.colorForeground);
holder.tvTypeName.setTextColor(mContext.getColor(R.color.textPrimary));
holder.tvTypeName.setTextSize(15);
holder.tvTypeName.getPaint().setFakeBoldText(true);
} else {
holder.itemView.setBackgroundResource(R.color.sys_book_type_bg);
holder.itemView.setBackgroundResource(R.color.colorBackground);
holder.tvTypeName.setTextColor(mContext.getColor(R.color.textSecondary));
holder.tvTypeName.getPaint().setFakeBoldText(false);
holder.tvTypeName.setTextSize(14);
}
if (onItemClickListener != null) {

@ -2,9 +2,7 @@ package xyz.fycz.myreader.ui.adapter;
import android.content.Context;
import android.content.DialogInterface;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.*;
import androidx.appcompat.app.AlertDialog;
@ -14,14 +12,13 @@ import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.*;
import xyz.fycz.myreader.R;
import xyz.fycz.myreader.application.MyApplication;
import xyz.fycz.myreader.common.APPCONST;
import xyz.fycz.myreader.creator.DialogCreator;
import xyz.fycz.myreader.creator.MyAlertDialog;
import xyz.fycz.myreader.custom.DragAdapter;
import xyz.fycz.myreader.greendao.entity.Book;
import xyz.fycz.myreader.greendao.entity.Chapter;
@ -40,6 +37,10 @@ import xyz.fycz.myreader.widget.BadgeView;
public abstract class BookcaseAdapter extends DragAdapter {
private final Map<String, Boolean> isLoading = new HashMap<>();
private final Map<String, Boolean> mCheckMap = new LinkedHashMap<>();
private int mCheckedCount = 0;
protected OnBookCheckedListener mListener;
protected boolean isCheckedAll;
protected int mResourceId;
protected ArrayList<Book> list;
protected Context mContext;
@ -47,6 +48,7 @@ public abstract class BookcaseAdapter extends DragAdapter {
protected BookService mBookService;
protected ChapterService mChapterService;
protected BookcasePresenter mBookcasePresenter;
protected boolean isGroup;
protected String[] menu = {
MyApplication.getmContext().getResources().getString(R.string.menu_book_Top),
MyApplication.getmContext().getResources().getString(R.string.menu_book_download),
@ -56,7 +58,7 @@ public abstract class BookcaseAdapter extends DragAdapter {
public BookcaseAdapter(Context context, int textViewResourceId, ArrayList<Book> objects
, boolean editState, BookcasePresenter bookcasePresenter) {
, boolean editState, BookcasePresenter bookcasePresenter, boolean isGroup) {
mContext = context;
mResourceId = textViewResourceId;
list = objects;
@ -64,6 +66,7 @@ public abstract class BookcaseAdapter extends DragAdapter {
mBookService = BookService.getInstance();
mChapterService = ChapterService.getInstance();
mBookcasePresenter = bookcasePresenter;
this.isGroup = isGroup;
}
@ -72,7 +75,11 @@ public abstract class BookcaseAdapter extends DragAdapter {
Book b = list.remove(from);
list.add(to, b);
for (int i = 0; i < list.size(); i++) {
if (!isGroup) {
list.get(i).setSortCode(i);
}else {
list.get(i).setGroupSort(i);
}
}
mBookService.updateBooks(list);
}
@ -89,7 +96,7 @@ public abstract class BookcaseAdapter extends DragAdapter {
@Override
public long getItemId(int position) {
return list.get(position).getSortCode();
return !isGroup ? list.get(position).getSortCode() : list.get(position).getGroupSort();
}
@ -104,19 +111,43 @@ public abstract class BookcaseAdapter extends DragAdapter {
notifyDataSetChanged();
mBookService.addBook(item);
}
protected void showDeleteBookDialog(final Book book) {
if (!isGroup) {
DialogCreator.createCommonDialog(mContext, "删除书籍", "确定删除《" + book.getName() + "》及其所有缓存吗?",
true, (dialogInterface, i) -> {
remove(book);
dialogInterface.dismiss();
}, (dialogInterface, i) -> dialogInterface.dismiss());
ToastUtils.showSuccess("书籍删除成功!");
mBookcasePresenter.init();
}, null);
}else {
DialogCreator.createCommonDialog(mContext, "删除/移除书籍", "您是希望删除《" + book.getName() + "》及其所有缓存还是从分组中移除该书籍(不会删除书籍)呢?",
true, "删除书籍", "从分组中移除书籍",(dialogInterface, i) -> {
remove(book);
ToastUtils.showSuccess("书籍删除成功!");
mBookcasePresenter.init();
}, (dialog, which) -> {
book.setGroupId("");
mBookService.updateEntity(book);
ToastUtils.showSuccess("书籍已从分组中移除!");
mBookcasePresenter.init();
});
}
}
/**
* 设置是否处于编辑状态
*
* @param mEditState
*/
public void setmEditState(boolean mEditState) {
if (mEditState) {
mCheckMap.clear();
for (Book book : list) {
mCheckMap.put(book.getId(), false);
}
mCheckedCount = 0;
}
this.mEditState = mEditState;
notifyDataSetChanged();
}
@ -124,8 +155,10 @@ public abstract class BookcaseAdapter extends DragAdapter {
public boolean ismEditState() {
return mEditState;
}
/**
* getter方法
*
* @return
*/
public Map<String, Boolean> getIsLoading() {
@ -167,6 +200,68 @@ public abstract class BookcaseAdapter extends DragAdapter {
return true;
}
//设置点击切换
public void setCheckedBook(String bookId) {
boolean isSelected = mCheckMap.get(bookId);
if (isSelected) {
mCheckMap.put(bookId, false);
--mCheckedCount;
} else {
mCheckMap.put(bookId, true);
++mCheckedCount;
}
notifyDataSetChanged();
}
//全选
public void setCheckedAll(boolean isChecked) {
mCheckedCount = isChecked ? mCheckMap.size() : 0;
for (String bookId : mCheckMap.keySet()) {
mCheckMap.put(bookId, isChecked);
}
mListener.onItemCheckedChange(true);
notifyDataSetChanged();
}
public boolean getBookIsChecked(String bookId) {
return mCheckMap.get(bookId);
}
public int getmCheckedCount() {
return mCheckedCount;
}
public int getmCheckableCount() {
return mCheckMap.size();
}
public boolean isCheckedAll() {
return isCheckedAll;
}
public void setIsCheckedAll(boolean isCheckedAll) {
this.isCheckedAll = isCheckedAll;
}
public List<Book> getSelectBooks() {
List<Book> mSelectBooks = new ArrayList<>();
for (String bookId : mCheckMap.keySet()) {
if (mCheckMap.get(bookId)) {
mSelectBooks.add(mBookService.getBookById(bookId));
}
}
return mSelectBooks;
}
public boolean isGroup() {
return isGroup;
}
public void setGroup(boolean group) {
isGroup = group;
}
/*******************************************缓存书籍*********************************************************/
private int selectedIndex;//对话框选择下标
@ -181,7 +276,7 @@ public abstract class BookcaseAdapter extends DragAdapter {
}
final int[] begin = new int[1];
final int[] end = new int[1];
new AlertDialog.Builder(mContext)
MyAlertDialog.build(mContext)
.setTitle("缓存书籍")
.setSingleChoiceItems(APPCONST.DIALOG_DOWNLOAD, selectedIndex, new DialogInterface.OnClickListener() {
@Override
@ -217,10 +312,19 @@ public abstract class BookcaseAdapter extends DragAdapter {
}
static class ViewHolder {
CheckBox cbBookChecked;
ImageView ivBookImg;
TextView tvBookName;
BadgeView tvNoReadNum;
ImageView ivDelete;
ProgressBar pbLoading;
}
public void setOnBookCheckedListener(OnBookCheckedListener listener) {
mListener = listener;
}
//书籍点击监听器
public interface OnBookCheckedListener {
void onItemCheckedChange(boolean isChecked);
}
}

@ -22,6 +22,7 @@ import xyz.fycz.myreader.R;
import xyz.fycz.myreader.application.MyApplication;
import xyz.fycz.myreader.common.APPCONST;
import xyz.fycz.myreader.creator.DialogCreator;
import xyz.fycz.myreader.creator.MyAlertDialog;
import xyz.fycz.myreader.greendao.entity.Book;
import xyz.fycz.myreader.ui.activity.BookDetailedActivity;
import xyz.fycz.myreader.ui.activity.ReadActivity;
@ -39,8 +40,8 @@ public class BookcaseDetailedAdapter extends BookcaseAdapter {
ViewHolder viewHolder = null;
public BookcaseDetailedAdapter(Context context, int textViewResourceId, ArrayList<Book> objects,
boolean editState, BookcasePresenter bookcasePresenter) {
super(context, textViewResourceId, objects, editState, bookcasePresenter);
boolean editState, BookcasePresenter bookcasePresenter, boolean isGroup) {
super(context, textViewResourceId, objects, editState, bookcasePresenter, isGroup);
}
@Override
@ -48,10 +49,10 @@ public class BookcaseDetailedAdapter extends BookcaseAdapter {
if (convertView == null || convertView.getTag() instanceof BookcaseDragAdapter.ViewHolder) {
viewHolder = new ViewHolder();
convertView = LayoutInflater.from(mContext).inflate(mResourceId, null);
viewHolder.cbBookChecked = convertView.findViewById(R.id.cb_book_select);
viewHolder.ivBookImg = convertView.findViewById(R.id.iv_book_img);
viewHolder.tvBookName = convertView.findViewById(R.id.tv_book_name);
viewHolder.tvNoReadNum = convertView.findViewById(R.id.tv_no_read_num);
viewHolder.ivDelete = convertView.findViewById(R.id.iv_delete);
viewHolder.tvBookAuthor = convertView.findViewById(R.id.tv_book_author);
viewHolder.tvHistoryChapter = convertView.findViewById(R.id.tv_book_history_chapter);
viewHolder.tvNewestChapter = convertView.findViewById(R.id.tv_book_newest_chapter);
@ -79,7 +80,6 @@ public class BookcaseDetailedAdapter extends BookcaseAdapter {
.into(viewHolder.ivBookImg);
viewHolder.tvBookName.setText(book.getName());
viewHolder.ivDelete.setOnClickListener(v -> showDeleteBookDialog(book));
viewHolder.tvBookAuthor.setText(book.getAuthor());
viewHolder.tvHistoryChapter.setText(book.getHistoryChapterId());
@ -88,12 +88,25 @@ public class BookcaseDetailedAdapter extends BookcaseAdapter {
if (mEditState) {
viewHolder.tvNoReadNum.setVisibility(View.GONE);
viewHolder.ivDelete.setVisibility(View.VISIBLE);
viewHolder.ivBookImg.setOnClickListener(null);
viewHolder.llBookRead.setOnClickListener(null);
viewHolder.pbLoading.setVisibility(View.GONE);
viewHolder.cbBookChecked.setVisibility(View.VISIBLE);
viewHolder.cbBookChecked.setChecked(getBookIsChecked(book.getId()));
viewHolder.llBookRead.setOnClickListener(v -> {
setCheckedBook(book.getId());
mListener.onItemCheckedChange(getBookIsChecked(book.getId()));
});
viewHolder.ivBookImg.setOnClickListener(v -> {
setCheckedBook(book.getId());
mListener.onItemCheckedChange(getBookIsChecked(book.getId()));
});
viewHolder.cbBookChecked.setOnClickListener(v -> {
setCheckedBook(book.getId());
mListener.onItemCheckedChange(getBookIsChecked(book.getId()));
});
} else {
viewHolder.ivDelete.setVisibility(View.GONE);
viewHolder.cbBookChecked.setVisibility(View.GONE);
boolean isLoading = false;
try {
isLoading = isBookLoading(book.getId());
@ -133,14 +146,16 @@ public class BookcaseDetailedAdapter extends BookcaseAdapter {
});
viewHolder.llBookRead.setOnLongClickListener(v -> {
if (!ismEditState()) {
AlertDialog bookDialog = new AlertDialog.Builder(mContext)
AlertDialog bookDialog = MyAlertDialog.build(mContext)
.setTitle(book.getName())
.setAdapter(new ArrayAdapter<>(mContext,
android.R.layout.simple_list_item_1, menu),
(dialog, which) -> {
.setItems(menu, (dialog, which) -> {
switch (which) {
case 0:
if (!isGroup) {
book.setSortCode(0);
}else {
book.setGroupSort(0);
}
mBookService.updateEntity(book);
mBookcasePresenter.init();
ToastUtils.showSuccess("书籍《" + book.getName() + "》移至顶部成功!");

@ -21,6 +21,7 @@ import xyz.fycz.myreader.R;
import xyz.fycz.myreader.application.MyApplication;
import xyz.fycz.myreader.common.APPCONST;
import xyz.fycz.myreader.creator.DialogCreator;
import xyz.fycz.myreader.creator.MyAlertDialog;
import xyz.fycz.myreader.greendao.entity.Book;
import xyz.fycz.myreader.ui.activity.BookDetailedActivity;
import xyz.fycz.myreader.ui.activity.ReadActivity;
@ -39,8 +40,8 @@ public class BookcaseDragAdapter extends BookcaseAdapter {
MyApplication.getmContext().getResources().getString(R.string.menu_book_delete)
};
public BookcaseDragAdapter(Context context, int textViewResourceId, ArrayList<Book> objects,
boolean editState, BookcasePresenter bookcasePresenter) {
super(context, textViewResourceId, objects, editState, bookcasePresenter);
boolean editState, BookcasePresenter bookcasePresenter, boolean isGroup) {
super(context, textViewResourceId, objects, editState, bookcasePresenter, isGroup);
}
@ -49,10 +50,10 @@ public class BookcaseDragAdapter extends BookcaseAdapter {
if (convertView == null || convertView.getTag() instanceof BookcaseDetailedAdapter.ViewHolder) {
viewHolder = new ViewHolder();
convertView = LayoutInflater.from(mContext).inflate(mResourceId, null);
viewHolder.cbBookChecked = convertView.findViewById(R.id.cb_book_select);
viewHolder.ivBookImg = convertView.findViewById(R.id.iv_book_img);
viewHolder.tvBookName = convertView.findViewById(R.id.tv_book_name);
viewHolder.tvNoReadNum = convertView.findViewById(R.id.tv_no_read_num);
viewHolder.ivDelete = convertView.findViewById(R.id.iv_delete);
viewHolder.pbLoading = convertView.findViewById(R.id.pb_loading);
convertView.setTag(viewHolder);
} else {
@ -77,16 +78,18 @@ public class BookcaseDragAdapter extends BookcaseAdapter {
.into(viewHolder.ivBookImg);
viewHolder.tvBookName.setText(book.getName());
viewHolder.ivDelete.setOnClickListener(v -> showDeleteBookDialog(book));
if (mEditState) {
viewHolder.tvNoReadNum.setVisibility(View.GONE);
viewHolder.ivDelete.setVisibility(View.VISIBLE);
viewHolder.pbLoading.setVisibility(View.GONE);
viewHolder.ivBookImg.setOnClickListener(null);
viewHolder.ivBookImg.setOnClickListener(v -> {
setCheckedBook(book.getId());
mListener.onItemCheckedChange(getBookIsChecked(book.getId()));
});
viewHolder.cbBookChecked.setVisibility(View.VISIBLE);
viewHolder.cbBookChecked.setChecked(getBookIsChecked(book.getId()));
} else {
viewHolder.ivDelete.setVisibility(View.GONE);
viewHolder.cbBookChecked.setVisibility(View.GONE);
boolean isLoading = false;
try {
isLoading = isBookLoading(book.getId());
@ -121,11 +124,9 @@ public class BookcaseDragAdapter extends BookcaseAdapter {
});
viewHolder.ivBookImg.setOnLongClickListener(v -> {
if (!ismEditState()) {
AlertDialog bookDialog = new AlertDialog.Builder(mContext)
AlertDialog bookDialog = MyAlertDialog.build(mContext)
.setTitle(book.getName())
.setAdapter(new ArrayAdapter<>(mContext,
android.R.layout.simple_list_item_1, menu),
(dialog, which) -> {
.setItems(menu, (dialog, which) -> {
switch (which) {
case 0:
Intent intent = new Intent(mContext, BookDetailedActivity.class);
@ -133,7 +134,11 @@ public class BookcaseDragAdapter extends BookcaseAdapter {
mContext.startActivity(intent);
break;
case 1:
if (!isGroup) {
book.setSortCode(0);
}else {
book.setGroupSort(0);
}
mBookService.updateEntity(book);
mBookcasePresenter.init();
ToastUtils.showSuccess("书籍《" + book.getName() + "》移至顶部成功!");

@ -71,12 +71,13 @@ public class ChapterTitleAdapter extends ArrayAdapter<Chapter> {
} else {
viewHolder.tvTitle.setCompoundDrawablesWithIntrinsicBounds(getContext().getResources().getDrawable(R.drawable.selector_category_unload), null, null, null);
}
if (!setting.isDayStyle()) {
viewHolder.tvTitle.setTextColor(getContext().getColor(R.color.textSecondary));
/*if (!setting.isDayStyle()) {
viewHolder.tvTitle.setTextColor(getContext().getResources().getColor(R.color.sys_night_word));
viewHolder.vLine.setBackground(getContext().getDrawable(R.color.sys_dialog_setting_line));
}else {
viewHolder.tvTitle.setTextColor(getContext().getColor(R.color.title_black));
}
}*/
if (chapter.getNumber() == mBook.getHisttoryChapterNum()) {
viewHolder.tvTitle.setTextColor(getContext().getResources().getColor(R.color.colorAccent));

@ -10,7 +10,6 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.TextView;
import androidx.annotation.NonNull;
@ -118,6 +117,7 @@ public class FontsAdapter extends ArrayAdapter<Font> {
//viewHolder.tvExample.setTypeface(typeFace);
// viewHolder.tvExample.setTypeface(mTypefaceMap.get(font));
viewHolder.tvFontName.setText(font.toString());
viewHolder.tvFontName.setTextColor(mFontsActivity.getColor(R.color.textPrimary));
File fontFile = new File(APPCONST.FONT_BOOK_DIR + font.fileName);
if (font == Font.本地字体) {
if (setting.getFont() == Font.本地字体) {
@ -145,7 +145,7 @@ public class FontsAdapter extends ArrayAdapter<Font> {
checkedItem = i;
}
}
AlertDialog dialog = new AlertDialog.Builder(getContext())
MyAlertDialog dialog = new MyAlertDialog.Builder(getContext())
.setTitle(getContext().getString(R.string.font_select))
.setCancelable(true)
.setSingleChoiceItems(fontNames, checkedItem, new DialogInterface.OnClickListener() {

@ -0,0 +1,54 @@
package xyz.fycz.myreader.ui.adapter;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentPagerAdapter;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Zhouas666 on 2019-03-28
* Github: https://github.com/zas023
*/
public class TabFragmentPageAdapter extends FragmentPagerAdapter {
private List<Fragment> mFragmentList;
private List<String> mTitleList;
public TabFragmentPageAdapter(@NonNull FragmentManager fm) {
super(fm);
mFragmentList = new ArrayList<>();
mTitleList = new ArrayList<>();
}
public void addFragment(Fragment fragment) {
mFragmentList.add(fragment);
}
public void addFragment(Fragment fragment,String title) {
mFragmentList.add(fragment);
mTitleList.add(title);
}
public void addTitle(String title) {
mTitleList.add(title);
}
@NonNull
@Override
public Fragment getItem(int position) {
return mFragmentList.get(position);
}
@Override
public int getCount() {
return mFragmentList.size();
}
@Override
public CharSequence getPageTitle(int position) {
return mTitleList.get(position);
}
}

@ -0,0 +1,82 @@
package xyz.fycz.myreader.ui.adapter.holder;
import android.app.Activity;
import android.content.Intent;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.resource.bitmap.RoundedCorners;
import com.bumptech.glide.request.RequestOptions;
import xyz.fycz.myreader.R;
import xyz.fycz.myreader.application.MyApplication;
import xyz.fycz.myreader.base.adapter.ViewHolderImpl;
import xyz.fycz.myreader.common.APPCONST;
import xyz.fycz.myreader.enums.BookSource;
import xyz.fycz.myreader.greendao.entity.Book;
import xyz.fycz.myreader.ui.activity.BookDetailedActivity;
/**
* @author fengyue
* @date 2020/9/7 7:35
*/
public class BookStoreBookHolder extends ViewHolderImpl<Book> {
private ImageView tvBookImg;
private TextView tvBookName;
private TextView tvBookAuthor;
private TextView tvBookTime;
private TextView tvBookNewestChapter;
private TextView tvBookSource;
private boolean hasImg;
private Activity mActivity;
public BookStoreBookHolder(boolean hasImg, Activity mActivity) {
this.hasImg = hasImg;
this.mActivity = mActivity;
}
@Override
protected int getItemLayoutId() {
return R.layout.listview_book_store_book_item;
}
@Override
public void initView() {
tvBookImg = findById(R.id.iv_book_img);
tvBookName = findById(R.id.tv_book_name);
tvBookAuthor = findById(R.id.tv_book_author);
tvBookNewestChapter = findById(R.id.tv_book_newest_chapter);
tvBookTime = findById(R.id.tv_book_time);
tvBookSource = findById(R.id.tv_book_source);
}
@Override
public void onBind(Book data, int pos) {
tvBookName.setText(data.getName());
tvBookAuthor.setText(data.getAuthor());
tvBookNewestChapter.setText(data.getNewestChapterTitle());
tvBookTime.setText(data.getUpdateDate());
if (hasImg){
tvBookImg.setVisibility(View.VISIBLE);
if (!MyApplication.isDestroy(mActivity)) {
Glide.with(getContext())
.load(data.getImgUrl())
.error(R.mipmap.no_image)
.placeholder(R.mipmap.no_image)
//设置圆角
.apply(RequestOptions.bitmapTransform(new RoundedCorners(8)))
.into(tvBookImg);
}
}
if (data.getSource() != null) {
tvBookSource.setText("书源:" + BookSource.fromString(data.getSource()).text);
}else {
tvBookSource.setText(data.getNewestChapterId());
}
}
}

@ -2,9 +2,14 @@ package xyz.fycz.myreader.ui.fragment;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.webkit.CookieManager;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.ProgressBar;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.RecyclerView;
import butterknife.BindView;
@ -12,22 +17,30 @@ import butterknife.ButterKnife;
import butterknife.Unbinder;
import com.scwang.smartrefresh.layout.SmartRefreshLayout;
import xyz.fycz.myreader.R;
import xyz.fycz.myreader.custom.DragSortGridView;
import xyz.fycz.myreader.ui.presenter.BookStorePresenter;
import xyz.fycz.myreader.util.SharedPreUtils;
import xyz.fycz.myreader.util.StringHelper;
import xyz.fycz.myreader.widget.RefreshLayout;
/**
* A simple {@link Fragment} subclass.
*/
public class BookStoreFragment extends Fragment {
@BindView(R.id.refresh_layout)
RefreshLayout mRlRefresh;
@BindView(R.id.rv_type_list)
RecyclerView rvTypeList;
@BindView(R.id.rv_book_list)
RecyclerView rvBookList;
@BindView(R.id.srl_book_list)
SmartRefreshLayout srlBookList;
@BindView(R.id.pb_loading)
ProgressBar pbLoading;
Unbinder unbinder;
private BookStorePresenter mBookStorePresenter;
private boolean isFirstInit;
public BookStoreFragment() {
// Required empty public constructor
@ -40,12 +53,22 @@ public class BookStoreFragment extends Fragment {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_book_store, container, false);
unbinder = ButterKnife.bind(this, view);
mBookStorePresenter = new BookStorePresenter(this);
mBookStorePresenter.start();
/*mBookStorePresenter = new BookStorePresenter(this);
mBookStorePresenter.start();*/
isFirstInit = true;
return view;
}
public void lazyLoad() {
if (isFirstInit) {
mBookStorePresenter = new BookStorePresenter(this);
mBookStorePresenter.start();
isFirstInit = false;
}
}
public RecyclerView getRvTypeList() {
return rvTypeList;
}
@ -58,4 +81,11 @@ public class BookStoreFragment extends Fragment {
return srlBookList;
}
public ProgressBar getPbLoading() {
return pbLoading;
}
public RefreshLayout getmRlRefresh() {
return mRlRefresh;
}
}

@ -3,17 +3,16 @@ package xyz.fycz.myreader.ui.fragment;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.*;
import android.widget.ProgressBar;
import android.widget.RelativeLayout;
import android.widget.TextView;
import androidx.fragment.app.Fragment;
import com.scwang.smartrefresh.layout.SmartRefreshLayout;
import xyz.fycz.myreader.R;
import xyz.fycz.myreader.application.MyApplication;
import xyz.fycz.myreader.custom.DragSortGridView;
import butterknife.ButterKnife;
@ -39,6 +38,14 @@ public class BookcaseFragment extends Fragment {
TextView tvStopDownload;
@BindView(R.id.pb_download)
ProgressBar pbDownload;
@BindView(R.id.rl_book_edit)
RelativeLayout rlBookEdit;
@BindView(R.id.book_selected_all)
CheckBox mCbSelectAll;
@BindView(R.id.book_btn_delete)
Button mBtnDelete;
@BindView(R.id.book_add_group)
Button mBtnAddGroup;
Unbinder unbinder;
@ -108,4 +115,24 @@ public class BookcaseFragment extends Fragment {
public BookcasePresenter getmBookcasePresenter() {
return mBookcasePresenter;
}
public boolean isRecreate() {
return unbinder == null;
}
public RelativeLayout getRlBookEdit() {
return rlBookEdit;
}
public CheckBox getmCbSelectAll() {
return mCbSelectAll;
}
public Button getmBtnDelete() {
return mBtnDelete;
}
public Button getmBtnAddGroup() {
return mBtnAddGroup;
}
}

@ -0,0 +1,57 @@
package xyz.fycz.myreader.ui.fragment;
import android.content.Intent;
import android.widget.RelativeLayout;
import butterknife.BindView;
import xyz.fycz.myreader.R;
import xyz.fycz.myreader.base.BaseFragment;
import xyz.fycz.myreader.common.APPCONST;
import xyz.fycz.myreader.ui.activity.BookstoreActivity;
import xyz.fycz.myreader.webapi.crawler.FindCrawler;
import xyz.fycz.myreader.webapi.crawler.QB5ReadCrawler;
import xyz.fycz.myreader.webapi.crawler.find.ABC;
/**
* @author fengyue
* @date 2020/9/13 21:07
*/
public class FindFragment extends BaseFragment {
@BindView(R.id.find_rl_qidian_top)
RelativeLayout mRlQiDianTop;
@BindView(R.id.find_rl_qidian_ns_top)
RelativeLayout mRlQiDianNSTop;
@BindView(R.id.find_rl_qidian_sort)
RelativeLayout mRlQiDianSort;
@BindView(R.id.find_rl_qidian_ns_sort)
RelativeLayout mRlQiDianNSSort;
@BindView(R.id.find_rl_qb5_store)
RelativeLayout mRlQB5Store;
@BindView(R.id.find_rl_biquge_store)
RelativeLayout mRlBiQuGeStore;
@Override
protected int getContentId() {
return R.layout.fragment_find;
}
@Override
protected void initClick() {
super.initClick();
mRlQiDianTop.setOnClickListener(v -> comeToBookstore(new ABC(false)));
mRlQiDianNSTop.setOnClickListener(v -> comeToBookstore(new ABC(true)));
mRlQiDianSort.setOnClickListener(v -> comeToBookstore(new ABC(false, true)));
mRlQiDianNSSort.setOnClickListener(v -> comeToBookstore(new ABC(true, true)));
mRlQB5Store.setOnClickListener(v -> comeToBookstore(new QB5ReadCrawler()));
}
private void comeToBookstore(FindCrawler findCrawler){
Intent intent = new Intent(getContext(), BookstoreActivity.class);
intent.putExtra(APPCONST.FIND_CRAWLER, findCrawler);
startActivity(intent);
}
public boolean isRecreate() {
return unbinder == null;
}
}

@ -0,0 +1,397 @@
package xyz.fycz.myreader.ui.fragment;
import android.annotation.SuppressLint;
import android.content.*;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.widget.ArrayAdapter;
import android.widget.RelativeLayout;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import butterknife.BindView;
import xyz.fycz.myreader.R;
import xyz.fycz.myreader.application.MyApplication;
import xyz.fycz.myreader.application.SysManager;
import xyz.fycz.myreader.backup.BackupAndRestore;
import xyz.fycz.myreader.backup.UserService;
import xyz.fycz.myreader.base.BaseFragment;
import xyz.fycz.myreader.common.APPCONST;
import xyz.fycz.myreader.creator.DialogCreator;
import xyz.fycz.myreader.creator.MyAlertDialog;
import xyz.fycz.myreader.entity.Setting;
import xyz.fycz.myreader.greendao.entity.Book;
import xyz.fycz.myreader.greendao.service.BookService;
import xyz.fycz.myreader.ui.activity.AboutActivity;
import xyz.fycz.myreader.ui.activity.LoginActivity;
import xyz.fycz.myreader.ui.activity.MoreSettingActivity;
import xyz.fycz.myreader.util.SharedPreUtils;
import xyz.fycz.myreader.util.ToastUtils;
import xyz.fycz.myreader.util.utils.NetworkUtils;
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import static android.app.Activity.RESULT_OK;
/**
* @author fengyue
* @date 2020/9/13 13:20
*/
public class MineFragment extends BaseFragment {
@BindView(R.id.mine_rl_user)
RelativeLayout mRlUser;
@BindView(R.id.tv_user)
TextView mTvUser;
@BindView(R.id.mine_rl_backup)
RelativeLayout mRlBackup;
@BindView(R.id.mine_rl_syn)
RelativeLayout mRlSyn;
@BindView(R.id.mine_rl_setting)
RelativeLayout mRlSetting;
@BindView(R.id.mine_rl_theme_mode)
RelativeLayout mRlThemeMode;
@BindView(R.id.tv_theme_mode_select)
TextView tvThemeModeSelect;
@BindView(R.id.mine_rl_feedback)
RelativeLayout mRlFeedback;
@BindView(R.id.mine_rl_about)
RelativeLayout mRlAbout;
private boolean isLogin;
private BackupAndRestore mBackupAndRestore;
private Setting mSetting;
private String[] webSynMenu;
private String[] backupMenu;
private AlertDialog themeModeDia;
private int themeMode;
private String[] themeModeArr;
@SuppressLint("HandlerLeak")
private Handler mHandler = new Handler() {
@Override
public void handleMessage(@NonNull Message msg) {
switch (msg.what) {
case 1:
mTvUser.setText("登录/注册");
break;
case 2:
backup();
break;
case 3:
restore();
break;
}
}
};
public MineFragment() {
}
@Override
protected int getContentId() {
return R.layout.fragment_mine;
}
@Override
protected void initData(Bundle savedInstanceState) {
super.initData(savedInstanceState);
isLogin = UserService.isLogin();
mBackupAndRestore = new BackupAndRestore();
mSetting = SysManager.getSetting();
webSynMenu = new String[]{
MyApplication.getmContext().getString(R.string.menu_backup_webBackup),
MyApplication.getmContext().getString(R.string.menu_backup_webRestore),
MyApplication.getmContext().getString(R.string.menu_backup_autoSyn)
};
backupMenu = new String[]{
MyApplication.getmContext().getResources().getString(R.string.menu_backup_backup),
MyApplication.getmContext().getResources().getString(R.string.menu_backup_restore),
};
themeMode = MyApplication.getApplication().isNightFS() ? 0 : mSetting.isDayStyle() ? 1 : 2;
themeModeArr = getResources().getStringArray(R.array.theme_mode_arr);
}
@Override
protected void initWidget(Bundle savedInstanceState) {
super.initWidget(savedInstanceState);
if (isLogin) {
mTvUser.setText(UserService.readUsername());
}
tvThemeModeSelect.setText(themeModeArr[themeMode]);
}
@Override
protected void initClick() {
super.initClick();
mRlUser.setOnClickListener(v -> {
if (isLogin) {
DialogCreator.createCommonDialog(getActivity(), "退出登录", "确定要退出登录吗?"
, true, (dialog, which) -> {
File file = MyApplication.getApplication().getFileStreamPath("userConfig.fy");
if (file.delete()) {
ToastUtils.showSuccess("退出成功");
isLogin = false;
mHandler.sendEmptyMessage(1);
Intent intent = new Intent(getActivity(), LoginActivity.class);
getActivity().startActivityForResult(intent, APPCONST.REQUEST_LOGIN);
} else {
ToastUtils.showError("退出失败(Error:file.delete())");
}
}, (dialog, which) -> dialog.dismiss());
} else {
Intent intent = new Intent(getActivity(), LoginActivity.class);
getActivity().startActivityForResult(intent, APPCONST.REQUEST_LOGIN);
}
});
mRlBackup.setOnClickListener(v -> {
AlertDialog bookDialog = MyAlertDialog.build(getContext())
.setTitle(getContext().getResources().getString(R.string.menu_bookcase_backup))
.setItems(backupMenu, (dialog, which) -> {
switch (which) {
case 0:
mHandler.sendMessage(mHandler.obtainMessage(2));
break;
case 1:
mHandler.sendMessage(mHandler.obtainMessage(3));
break;
}
})
.setNegativeButton(null, null)
.setPositiveButton(null, null)
.create();
bookDialog.show();
});
mRlSyn.setOnClickListener(v -> {
if (!UserService.isLogin()) {
ToastUtils.showWarring("请先登录!");
Intent loginIntent = new Intent(getActivity(), LoginActivity.class);
getActivity().startActivityForResult(loginIntent, APPCONST.REQUEST_LOGIN);
return;
}
if (mSetting.isAutoSyn()) {
webSynMenu[2] = MyApplication.getmContext().getString(R.string.menu_backup_autoSyn) + "已开启";
} else {
webSynMenu[2] = MyApplication.getmContext().getString(R.string.menu_backup_autoSyn) + "已关闭";
}
MyAlertDialog.build(getContext())
.setTitle(getActivity().getString(R.string.menu_bookcase_syn))
.setItems(webSynMenu, (dialog, which) -> {
switch (which) {
case 0:
synBookcaseToWeb(false);
break;
case 1:
webRestore();
break;
case 2:
String tip = "";
if (mSetting.isAutoSyn()) {
mSetting.setAutoSyn(false);
tip = "每日自动同步已关闭!";
} else {
mSetting.setAutoSyn(true);
tip = "每日自动同步已开启!";
}
SysManager.saveSetting(mSetting);
ToastUtils.showSuccess(tip);
break;
}
})
.setNegativeButton(null, null)
.setPositiveButton(null, null)
.show();
});
mRlSetting.setOnClickListener(v -> {
Intent settingIntent = new Intent(getActivity(), MoreSettingActivity.class);
startActivity(settingIntent);
});
mRlThemeMode.setOnClickListener(v -> {
if (themeModeDia != null) {
themeModeDia.show();
return;
}
themeModeDia = MyAlertDialog.build(getContext())
.setTitle("主题模式")
.setSingleChoiceItems(themeModeArr, themeMode
, (dialog, which) -> {
if (themeMode == which) {
dialog.dismiss();
return;
}
themeMode = which;
switch (which) {
case 0:
SharedPreUtils.getInstance().putBoolean("isNightFS", true);
break;
case 1:
SharedPreUtils.getInstance().putBoolean("isNightFS", false);
mSetting.setDayStyle(true);
SysManager.saveSetting(mSetting);
break;
case 2:
SharedPreUtils.getInstance().putBoolean("isNightFS", false);
mSetting.setDayStyle(false);
SysManager.saveSetting(mSetting);
break;
}
dialog.dismiss();
tvThemeModeSelect.setText(themeModeArr[themeMode]);
MyApplication.getApplication().initNightTheme();
})
.setNegativeButton("取消", null)
.create();
themeModeDia.show();
});
mRlAbout.setOnClickListener(v -> {
Intent aboutIntent = new Intent(getActivity(), AboutActivity.class);
startActivity(aboutIntent);
});
mRlFeedback.setOnClickListener(v -> {
DialogCreator.createCommonDialog(getContext(), "问题反馈", "请加入QQ群(1085028304)反馈问题!", true,
"加入QQ群", "取消", (dialog, which) -> {
if (!MyApplication.joinQQGroup(getContext(),"8PIOnHFuH6A38hgxvD_Rp2Bu-Ke1ToBn")){
ClipboardManager mClipboardManager = (ClipboardManager) getActivity().getSystemService(Context.CLIPBOARD_SERVICE);
//数据
ClipData mClipData = ClipData.newPlainText("Label", "1085028304");
//把数据设置到剪切板上
assert mClipboardManager != null;
mClipboardManager.setPrimaryClip(mClipData);
ToastUtils.showError("未安装手Q或安装的版本不支持!\n已复制QQ群号,您可自行前往QQ添加!");
}
}, null);
});
}
@Override
protected void processLogic() {
super.processLogic();
}
/**
* 备份
*/
private void backup() {
ArrayList<Book> mBooks = (ArrayList<Book>) BookService.getInstance().getAllBooks();
if (mBooks.size() == 0) {
ToastUtils.showWarring("当前书架无任何书籍,无法备份!");
return;
}
DialogCreator.createCommonDialog(getContext(), "确认备份吗?", "新备份会替换原有备份!", true,
(dialogInterface, i) -> {
dialogInterface.dismiss();
if (mBackupAndRestore.backup("localBackup")) {
DialogCreator.createTipDialog(getContext(), "备份成功,备份文件路径:" + APPCONST.BACKUP_FILE_DIR);
} else {
DialogCreator.createTipDialog(getContext(), "未给予储存权限,备份失败!");
}
}, (dialogInterface, i) -> dialogInterface.dismiss());
}
/**
* 恢复
*/
private void restore() {
DialogCreator.createCommonDialog(getContext(), "确认恢复吗?", "恢复书架会覆盖原有书架!", true,
(dialogInterface, i) -> {
dialogInterface.dismiss();
if (mBackupAndRestore.restore("localBackup")) {
mHandler.sendMessage(mHandler.obtainMessage(7));
// DialogCreator.createTipDialog(mMainActivity,
// "恢复成功!\n注意:本功能属于实验功能,书架恢复后,书籍初次加载时可能加载失败,返回重新加载即可!");
mSetting = SysManager.getSetting();
ToastUtils.showSuccess("书架恢复成功!");
} else {
DialogCreator.createTipDialog(getContext(), "未找到备份文件或未给予储存权限,恢复失败!");
}
}, (dialogInterface, i) -> dialogInterface.dismiss());
}
/**
* 同步书架
*/
private void synBookcaseToWeb(boolean isAutoSyn) {
if (!NetworkUtils.isNetWorkAvailable()) {
if (!isAutoSyn) {
ToastUtils.showWarring("无网络连接!");
}
return;
}
ArrayList<Book> mBooks = (ArrayList<Book>) BookService.getInstance().getAllBooks();
if (mBooks.size() == 0) {
if (!isAutoSyn) {
ToastUtils.showWarring("当前书架无任何书籍,无法同步!");
}
return;
}
Date nowTime = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yy-MM-dd");
String nowTimeStr = sdf.format(nowTime);
SharedPreUtils spb = SharedPreUtils.getInstance();
String synTime = spb.getString("synTime");
if (!nowTimeStr.equals(synTime) || !isAutoSyn) {
MyApplication.getApplication().newThread(() -> {
if (UserService.webBackup()) {
spb.putString("synTime", nowTimeStr);
if (!isAutoSyn) {
DialogCreator.createTipDialog(getContext(), "成功将书架同步至网络!");
}
} else {
if (!isAutoSyn) {
DialogCreator.createTipDialog(getContext(), "同步失败,请重试!");
}
}
});
}
}
/**
* 恢复
*/
private void webRestore() {
if (!NetworkUtils.isNetWorkAvailable()) {
ToastUtils.showWarring("无网络连接!");
return;
}
DialogCreator.createCommonDialog(getContext(), "确认同步吗?", "将书架从网络同步至本地会覆盖原有书架!", true,
(dialogInterface, i) -> {
dialogInterface.dismiss();
MyApplication.getApplication().newThread(() -> {
if (UserService.webRestore()) {
mHandler.sendMessage(mHandler.obtainMessage(7));
// DialogCreator.createTipDialog(mMainActivity,
// "恢复成功!\n注意:本功能属于实验功能,书架恢复后,书籍初次加载时可能加载失败,返回重新加载即可!");、
mSetting = SysManager.getSetting();
ToastUtils.showSuccess("成功将书架从网络同步至本地!");
} else {
DialogCreator.createTipDialog(getContext(), "未找到同步文件,同步失败!");
}
});
}, (dialogInterface, i) -> dialogInterface.dismiss());
}
@Override
public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
if (resultCode == RESULT_OK) {
switch (requestCode) {
case APPCONST.REQUEST_LOGIN:
assert data != null;
isLogin = data.getBooleanExtra("isLogin", false);
if (isLogin) {
mTvUser.setText(UserService.readUsername());
}
break;
}
}
}
public boolean isRecreate() {
return unbinder == null;
}
}

@ -1,62 +0,0 @@
package xyz.fycz.myreader.ui.presenter;
import android.annotation.SuppressLint;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import xyz.fycz.myreader.R;
import xyz.fycz.myreader.application.MyApplication;
import xyz.fycz.myreader.base.BasePresenter;
import xyz.fycz.myreader.creator.DialogCreator;
import xyz.fycz.myreader.ui.activity.AboutActivity;
import xyz.fycz.myreader.util.ShareUtils;
import xyz.fycz.myreader.util.SharedPreUtils;
import xyz.fycz.myreader.util.ToastUtils;
/**
* @author fengyue
* @date 2020/7/31 11:39
*/
public class AboutPresenter implements BasePresenter {
private AboutActivity mAboutActivity;
public AboutPresenter(AboutActivity mAboutActivity) {
this.mAboutActivity = mAboutActivity;
}
@SuppressLint("SetTextI18n")
@Override
public void start() {
mAboutActivity.getLlTitleBack().setOnClickListener(v -> mAboutActivity.finish());
mAboutActivity.getTvTitleText().setText("关于");
mAboutActivity.getTvVersionName().setText("风月读书v" + MyApplication.getStrVersionName());
mAboutActivity.getVmAuthor().setOnClickListener(v -> {
ClipboardManager mClipboardManager = (ClipboardManager) mAboutActivity.getSystemService(Context.CLIPBOARD_SERVICE);
//数据
ClipData mClipData = ClipData.newPlainText("Label", "fy@fycz.xyz");
//把数据设置到剪切板上
assert mClipboardManager != null;
mClipboardManager.setPrimaryClip(mClipData);
ToastUtils.showSuccess("邮箱复制成功!");
});
mAboutActivity.getVmShare().setOnClickListener(v -> ShareUtils.share(mAboutActivity, mAboutActivity.getString(R.string.share_text) +
SharedPreUtils.getInstance().getString("downloadLink")));
mAboutActivity.getVmUpdate().setOnClickListener(v -> MyApplication.checkVersionByServer(mAboutActivity, true, null));
mAboutActivity.getVmUpdateLog().setOnClickListener(v -> DialogCreator.createAssetTipDialog(mAboutActivity, "更新日志", "updatelog.fy"));
mAboutActivity.getVmGit().setOnClickListener(v -> openIntent(Intent.ACTION_VIEW, mAboutActivity.getString(R.string.this_github_url)));
mAboutActivity.getVmDisclaimer().setOnClickListener(v -> DialogCreator.createAssetTipDialog(mAboutActivity, "免责声明", "disclaimer.fy"));
}
void openIntent(String intentName, String address) {
try {
Intent intent = new Intent(intentName);
intent.setData(Uri.parse(address));
mAboutActivity.startActivity(intent);
} catch (Exception e) {
ToastUtils.showError(e.getLocalizedMessage());
}
}
}

@ -9,6 +9,7 @@ import xyz.fycz.myreader.common.APPCONST;
import xyz.fycz.myreader.greendao.entity.Book;
import xyz.fycz.myreader.greendao.entity.BookMark;
import xyz.fycz.myreader.greendao.service.BookMarkService;
import xyz.fycz.myreader.ui.activity.CatalogActivity;
import xyz.fycz.myreader.ui.adapter.BookMarkAdapter;
import xyz.fycz.myreader.ui.fragment.BookMarkFragment;
@ -32,10 +33,7 @@ public class BookMarkPresenter implements BasePresenter {
@Override
public void start() {
mBook = (Book) mBookMarkFragment.getActivity().getIntent().getSerializableExtra(APPCONST.BOOK);
if (!SysManager.getSetting().isDayStyle()) {
mBookMarkFragment.getLvBookmarkList().setBackground(mBookMarkFragment.getActivity().getDrawable(R.color.sys_dialog_setting_bg));
}
mBook = ((CatalogActivity) mBookMarkFragment.getActivity()).getmBook();;
initBookMarkList();
mBookMarkFragment.getLvBookmarkList().setOnItemClickListener((parent, view, position, id) -> {
BookMark bookMark = mBookMarks.get(position);

@ -5,15 +5,14 @@ import android.content.Intent;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.LinearLayoutManager;
import com.scwang.smartrefresh.layout.api.RefreshLayout;
import com.scwang.smartrefresh.layout.listener.OnRefreshListener;
import xyz.fycz.myreader.base.BasePresenter;
import xyz.fycz.myreader.callback.ResultCallback;
import xyz.fycz.myreader.common.APPCONST;
import xyz.fycz.myreader.common.URLCONST;
import xyz.fycz.myreader.creator.ChangeSourceDialog;
import xyz.fycz.myreader.creator.DialogCreator;
import xyz.fycz.myreader.entity.bookstore.BookType;
import xyz.fycz.myreader.entity.bookstore.RankBook;
import xyz.fycz.myreader.greendao.entity.Book;
import xyz.fycz.myreader.ui.activity.BookDetailedActivity;
import xyz.fycz.myreader.ui.activity.MainActivity;
@ -21,7 +20,7 @@ import xyz.fycz.myreader.ui.adapter.BookStoreBookAdapter;
import xyz.fycz.myreader.ui.adapter.BookStoreBookTypeAdapter;
import xyz.fycz.myreader.ui.fragment.BookStoreFragment;
import xyz.fycz.myreader.util.ToastUtils;
import xyz.fycz.myreader.webapi.BookStoreApi;
import xyz.fycz.myreader.webapi.crawler.find.ABC;
import java.util.ArrayList;
@ -39,14 +38,13 @@ public class BookStorePresenter implements BasePresenter {
private BookStoreBookTypeAdapter mBookStoreBookTypeAdapter;
private List<BookType> mBookTypes;
private BookStoreBookAdapter mBookStoreBookAdapter;
private List<Book> bookList;
private List<Book> bookList = new ArrayList<>();
private BookType curType;
private ABC findCrawler;
private int page = 1;
@SuppressLint("HandlerLeak")
private Handler mHandler = new Handler() {
@ -55,15 +53,26 @@ public class BookStorePresenter implements BasePresenter {
switch (msg.what) {
case 1:
initTypeList();
mBookStoreFragment.getmRlRefresh().showFinish();
break;
case 2:
initBookList();
List<Book> bookList = (List<Book>) msg.obj;
initBookList(bookList);
mBookStoreFragment.getSrlBookList().setEnableRefresh(true);
mBookStoreFragment.getSrlBookList().setEnableLoadMore(true);
mBookStoreFragment.getPbLoading().setVisibility(View.GONE);
break;
case 3:
mBookStoreFragment.getPbLoading().setVisibility(View.VISIBLE);
break;
case 4:
mBookStoreFragment.getPbLoading().setVisibility(View.GONE);
mBookStoreFragment.getSrlBookList().finishRefresh(false);
mBookStoreFragment.getSrlBookList().finishLoadMore(false);
break;
case 5:
mBookStoreFragment.getmRlRefresh().showError();
break;
}
}
};
@ -75,20 +84,57 @@ public class BookStorePresenter implements BasePresenter {
@Override
public void start() {
//无需加载更多
mBookStoreFragment.getSrlBookList().setEnableRefresh(false);
mBookStoreFragment.getSrlBookList().setEnableLoadMore(false);
findCrawler = new ABC(true);
//小说列表下拉加载更多事件
mBookStoreFragment.getSrlBookList().setOnLoadMoreListener(refreshLayout -> {
page++;
BookStorePresenter.this.getBooksData();
});
//小说列表上拉刷新事件
mBookStoreFragment.getSrlBookList().setOnRefreshListener(new OnRefreshListener() {
@Override
public void onRefresh(@NonNull RefreshLayout refreshLayout) {
mBookStoreFragment.getSrlBookList().setOnRefreshListener(refreshLayout -> {
page = 1;
BookStorePresenter.this.getBooksData();
});
mBookStoreBookAdapter = new BookStoreBookAdapter(findCrawler.hasImg(), mMainActivity);
mBookStoreFragment.getRvBookList().setLayoutManager(new LinearLayoutManager(mMainActivity));
mBookStoreFragment.getRvBookList().setAdapter(mBookStoreBookAdapter);
mBookStoreBookAdapter.setOnItemClickListener((view, pos) -> {
Book book = bookList.get(pos);
if (!findCrawler.hasImg()) {
Intent intent = new Intent(mMainActivity, BookDetailedActivity.class);
intent.putExtra(APPCONST.BOOK, book);
mMainActivity.startActivity(intent);
} else {
mHandler.sendMessage(mHandler.obtainMessage(3));
ChangeSourceDialog csd = new ChangeSourceDialog(mMainActivity, bookList.get(pos));
csd.initOneBook(new ResultCallback() {
@Override
public void onFinish(Object o, int code) {
Book searchBook = (Book) o;
book.setChapterUrl(searchBook.getChapterUrl());
book.setSource(searchBook.getSource());
Intent intent = new Intent(mMainActivity, BookDetailedActivity.class);
intent.putExtra(APPCONST.BOOK, book);
mMainActivity.startActivity(intent);
mHandler.sendMessage(mHandler.obtainMessage(4));
}
@Override
public void onError(Exception e) {
DialogCreator.createTipDialog(mMainActivity,"未搜索到该书籍,无法进入书籍详情!");
}
});
}
});
getData();
mBookStoreFragment.getmRlRefresh().setOnReloadingListener(this::getData);
}
@ -97,20 +143,28 @@ public class BookStorePresenter implements BasePresenter {
* 获取页面数据
*/
private void getData() {
BookStoreApi.getBookTypeList(URLCONST.nameSpace_biquge, new ResultCallback() {
/*BookStoreApi.getBookTypeList(findCrawler, new ResultCallback() {
@Override
public void onFinish(Object o, int code) {
mBookTypes = (ArrayList<BookType>) o;
curType = mBookTypes.get(0);
mHandler.sendMessage(mHandler.obtainMessage(1));
page = 1;
getBooksData();
}
@Override
public void onError(Exception e) {
ToastUtils.showError(e.getMessage());
e.printStackTrace();
mHandler.sendEmptyMessage(5);
}
});
});*/
mBookTypes = findCrawler.getRankTypes();
curType = mBookTypes.get(0);
mHandler.sendMessage(mHandler.obtainMessage(1));
page = 1;
getBooksData();
}
@ -119,25 +173,53 @@ public class BookStorePresenter implements BasePresenter {
* 获取小数列表数据
*/
private void getBooksData() {
BookStoreApi.getBookRankList(curType.getUrl(), new ResultCallback() {
if (findCrawler.getTypePage(curType, page)) {
mBookStoreFragment.getSrlBookList().finishLoadMoreWithNoMoreData();
return;
}
mHandler.sendEmptyMessage(3);
/*BookStoreApi.getBookRankList(curType.getUrl(), findCrawler, new ResultCallback() {
@Override
public void onFinish(Object o, int code) {
bookList= (ArrayList<Book>)o;
mHandler.sendMessage(mHandler.obtainMessage(2));
mHandler.sendMessage(mHandler.obtainMessage(2, o));
}
@Override
public void onError(Exception e) {
ToastUtils.showError(e.getMessage());
mHandler.sendMessage(mHandler.obtainMessage(4));
ToastUtils.showError("数据加载失败!\n" + e.getMessage());
e.printStackTrace();
}
});*/
findCrawler.getRankBooks(curType, new ResultCallback() {
@Override
public void onFinish(Object o, int code) {
List<Book> books = new ArrayList<>();
for (RankBook rb : (List<RankBook>) o){
Book book = new Book();
book.setName(rb.getbName());
book.setAuthor(rb.getbAuth());
book.setImgUrl(rb.getImg());
String cat = rb.getCat();
book.setType(cat.contains("小说") || cat.length() >= 4 ? cat : cat + "小说");
book.setNewestChapterTitle(rb.getDesc());
book.setDesc(rb.getDesc());
book.setUpdateDate(rb.getCnt());
books.add(book);
}
mHandler.sendMessage(mHandler.obtainMessage(2, books));
}
@Override
public void onError(Exception e) {
mHandler.sendMessage(mHandler.obtainMessage(4));
ToastUtils.showError("数据加载失败!\n" + e.getMessage());
e.printStackTrace();
}
});
}
/**
* 初始化类别列表
*/
@ -151,40 +233,38 @@ public class BookStorePresenter implements BasePresenter {
mBookStoreFragment.getRvTypeList().setAdapter(mBookStoreBookTypeAdapter);
//点击事件
mBookStoreBookTypeAdapter.setOnItemClickListener(new BookStoreBookTypeAdapter.OnItemClickListener() {
@Override
public void onClick(int pos, View view) {
mBookStoreBookTypeAdapter.setOnItemClickListener((pos, view) -> {
if (curType.equals(mBookTypes.get(pos))) {
return;
}
page = 1;
curType = mBookTypes.get(pos);
mBookStoreFragment.getSrlBookList().resetNoMoreData();
BookStorePresenter.this.getBooksData();
}
});
}
/**
* 初始化小说列表
*/
private void initBookList(){
//设置布局管理器
mLinearLayoutManager = new LinearLayoutManager(mBookStoreFragment.getActivity());
mLinearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
mBookStoreFragment.getRvBookList().setLayoutManager(mLinearLayoutManager);
mBookStoreBookAdapter = new BookStoreBookAdapter(mBookStoreFragment.getActivity(), bookList);
mBookStoreFragment.getRvBookList().setAdapter(mBookStoreBookAdapter);
//点击事件
mBookStoreBookAdapter.setOnItemClickListener(new BookStoreBookAdapter.OnItemClickListener() {
@Override
public void onClick(int pos, View view) {
Intent intent = new Intent(mBookStoreFragment.getActivity(), BookDetailedActivity.class);
intent.putExtra(APPCONST.BOOK, bookList.get(pos));
mBookStoreFragment.getActivity().startActivity(intent);
private void initBookList(List<Book> bookList) {
if (page == 1) {
mBookStoreBookAdapter.refreshItems(bookList);
this.bookList.clear();
this.bookList.addAll(bookList);
mBookStoreFragment.getRvBookList().scrollToPosition(0);
} else {
this.bookList.addAll(bookList);
mBookStoreBookAdapter.addItems(bookList);
}
});
//刷新动作完成
mBookStoreFragment.getSrlBookList().finishRefresh();
//加载更多完成
mBookStoreFragment.getSrlBookList().finishLoadMore();
}

@ -9,17 +9,22 @@ import android.graphics.BitmapFactory;
import android.os.Build;
import android.os.Handler;
import android.os.Message;
import android.view.Menu;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.PopupMenu;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.PopupMenu;
import androidx.appcompat.app.AlertDialog;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import java.io.File;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
@ -27,6 +32,8 @@ import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import com.google.android.material.textfield.TextInputEditText;
import com.google.android.material.textfield.TextInputLayout;
import xyz.fycz.myreader.R;
import xyz.fycz.myreader.application.MyApplication;
import xyz.fycz.myreader.application.SysManager;
@ -35,6 +42,10 @@ import xyz.fycz.myreader.backup.UserService;
import xyz.fycz.myreader.base.BasePresenter;
import xyz.fycz.myreader.callback.ResultCallback;
import xyz.fycz.myreader.common.APPCONST;
import xyz.fycz.myreader.creator.MultiChoiceDialog;
import xyz.fycz.myreader.creator.MyAlertDialog;
import xyz.fycz.myreader.greendao.entity.BookGroup;
import xyz.fycz.myreader.greendao.service.BookGroupService;
import xyz.fycz.myreader.ui.activity.*;
import xyz.fycz.myreader.webapi.crawler.ReadCrawler;
import xyz.fycz.myreader.webapi.crawler.ReadCrawlerUtil;
@ -56,14 +67,19 @@ import xyz.fycz.myreader.util.notification.NotificationUtil;
import xyz.fycz.myreader.util.utils.NetworkUtils;
import xyz.fycz.myreader.webapi.CommonApi;
import static xyz.fycz.myreader.application.MyApplication.checkVersionByServer;
public class BookcasePresenter implements BasePresenter {
private final BookcaseFragment mBookcaseFragment;
private final ArrayList<Book> mBooks = new ArrayList<>();//书目数组
private ArrayList<BookGroup> mBookGroups = new ArrayList<>();//书籍分组
private CharSequence[] mGroupNames;//书籍分组名称
private BookcaseAdapter mBookcaseAdapter;
private final BookService mBookService;
private final ChapterService mChapterService;
private final BookGroupService mBookGroupService;
private final MainActivity mMainActivity;
private PermissionsChecker mPermissionsChecker;
private boolean isBookcaseStyleChange;
@ -91,22 +107,11 @@ public class BookcasePresenter implements BasePresenter {
private int tempCount;//下载超时时间
private int downloadInterval = 150;//下载间隔
private Runnable sendDownloadNotification;//发送通知的线程
private PopupMenu pm;//菜单
private boolean isFirstRefresh = true;//是否首次进入刷新
private boolean isGroup;
public static final String CANCEL_ACTION = "cancelAction";
private final String[] backupMenu = {
MyApplication.getmContext().getResources().getString(R.string.menu_backup_backup),
MyApplication.getmContext().getResources().getString(R.string.menu_backup_restore),
};
private final String[] webSynMenu = {
MyApplication.getmContext().getString(R.string.menu_backup_webBackup),
MyApplication.getmContext().getString(R.string.menu_backup_webRestore),
MyApplication.getmContext().getString(R.string.menu_backup_autoSyn)
};
static final String[] PERMISSIONS = {
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE
@ -118,9 +123,11 @@ public class BookcasePresenter implements BasePresenter {
public void handleMessage(Message msg) {
switch (msg.what) {
case 1:
if (!MyApplication.isDestroy(mMainActivity)) {
MyApplication.runOnUiThread(() -> mBookcaseAdapter.notifyDataSetChanged());
finishLoadBookCount++;
mBookcaseFragment.getSrlContent().finishRefresh();
}
break;
case 2:
mBookcaseFragment.getSrlContent().finishRefresh();
@ -139,10 +146,8 @@ public class BookcasePresenter implements BasePresenter {
}
break;
case 5:
backup();
break;
case 6:
restore();
break;
case 7:
init();
@ -151,7 +156,7 @@ public class BookcasePresenter implements BasePresenter {
sendNotification();
break;
case 9:
mBookcaseFragment.getRlDownloadTip().setVisibility(View.GONE);
//mBookcaseFragment.getRlDownloadTip().setVisibility(View.GONE);
isDownloadFinish = true;
break;
case 10:
@ -160,9 +165,6 @@ public class BookcasePresenter implements BasePresenter {
mBookcaseFragment.getRlDownloadTip().setVisibility(View.VISIBLE);
break;
case 11:
MyApplication.runOnUiThread(() -> createMenu());
break;
case 12:
ToastUtils.showInfo("正在后台缓存书籍,具体进度可查看通知栏!");
notificationUtil.requestNotificationPermissionDialog(mMainActivity);
break;
@ -170,19 +172,22 @@ public class BookcasePresenter implements BasePresenter {
}
};
//构造方法
public BookcasePresenter(BookcaseFragment bookcaseFragment) {
mBookcaseFragment = bookcaseFragment;
mBookService = BookService.getInstance();
;
mChapterService = ChapterService.getInstance();
mMainActivity = ((MainActivity) (mBookcaseFragment.getActivity()));
mBookGroupService = BookGroupService.getInstance();
mMainActivity = (MainActivity) (mBookcaseFragment.getActivity());
// mChapterService = new ChapterService();
mSetting = SysManager.getSetting();
mBackupAndRestore = new BackupAndRestore();
}
//启动
@Override
public void start() {
checkVersionByServer(mMainActivity, false, mBookcaseFragment);
if (mSetting.getBookcaseStyle() == null) {
mSetting.setBookcaseStyle(BookcaseStyle.listMode);
}
@ -213,12 +218,6 @@ public class BookcasePresenter implements BasePresenter {
//长按事件监听
mBookcaseFragment.getGvBook().setOnItemLongClickListener((parent, view, position, id) -> false);
//更多按钮监听器
mMainActivity.getIvMore().setOnClickListener(v -> mHandler.sendMessage(mHandler.obtainMessage(11)));
//完成按钮监听器
mMainActivity.getTvEditFinish().setOnClickListener(v -> editBookcase(false));
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
//滑动监听器
mBookcaseFragment.getGvBook().getmScrollView().setOnScrollChangeListener((v, scrollX, scrollY, oldScrollX, oldScrollY) -> {
@ -228,44 +227,61 @@ public class BookcasePresenter implements BasePresenter {
});
}
//全选监听器
mBookcaseFragment.getmCbSelectAll().setOnClickListener(v -> {
//设置全选状态
boolean isChecked = mBookcaseFragment.getmCbSelectAll().isChecked();
mBookcaseAdapter.setCheckedAll(isChecked);
});
//删除监听器
mBookcaseFragment.getmBtnDelete().setOnClickListener(v -> {
DialogCreator.createCommonDialog(mMainActivity, "批量删除书籍",
"确定要删除这些书籍吗?", true, (dialog, which) -> {
for (Book book : mBookcaseAdapter.getSelectBooks()) {
mBookService.deleteBook(book);
}
ToastUtils.showSuccess("书籍删除成功!");
init();
}, null);
});
/**
* 编辑书架
*
* @param isEdit
*/
private void editBookcase(boolean isEdit) {
if (isEdit) {
if (mBooks.size() > 0) {
mBookcaseFragment.getSrlContent().setEnableRefresh(false);
mBookcaseAdapter.setmEditState(true);
mBookcaseFragment.getGvBook().setDragModel(DragSortGridView.DRAG_BY_LONG_CLICK);
mBookcaseAdapter.notifyDataSetChanged();
mMainActivity.getRlCommonTitle().setVisibility(View.GONE);
mMainActivity.getRlEditTitle().setVisibility(View.VISIBLE);
mMainActivity.getIvMore().setVisibility(View.GONE);
// VibratorUtil.Vibrate(mBookcaseFragment.getActivity(), 100);
} else {
ToastUtils.showWarring("当前无任何书籍,无法编辑书架!");
//加入分组监听器
mBookcaseFragment.getmBtnAddGroup().setOnClickListener(v -> {
initBookGroups(true);
showSelectGroupDia((dialog, which) -> {
if (which < mBookGroups.size()) {
BookGroup bookGroup = mBookGroups.get(which);
ArrayList<Book> mSelectBooks = (ArrayList<Book>) mBookcaseAdapter.getSelectBooks();
for (Book book : mSelectBooks) {
book.setGroupId(bookGroup.getId());
}
mBookService.updateBooks(mSelectBooks);
ToastUtils.showSuccess("成功将《" + mSelectBooks.get(0).getName() + "》"
+ (mSelectBooks.size() > 1 ? "等" : "")
+ "加入[" + bookGroup.getName() + "]分组");
init();
} else if (which == mBookGroups.size()) {
showAddOrRenameGroupDia(false, 0);
}
} else {
mMainActivity.getRlCommonTitle().setVisibility(View.VISIBLE);
mMainActivity.getIvMore().setVisibility(View.VISIBLE);
mMainActivity.getRlEditTitle().setVisibility(View.GONE);
if (mBookcaseFragment.getGvBook().getmScrollView().getScrollY() == 0
&& android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
mBookcaseFragment.getSrlContent().setEnableRefresh(true);
});
});
}
mBookcaseFragment.getGvBook().setDragModel(-1);
mBookcaseAdapter.setmEditState(false);
mBookcaseAdapter.notifyDataSetChanged();
//获取数据
public void getData() {
init();
initBookGroups(true);
if (mSetting.isRefreshWhenStart() || android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
initNoReadNum();
}
}
//初始化
public void init() {
initBook();
mSetting = SysManager.getSetting();
if (mBooks.size() == 0) {
mBookcaseFragment.getGvBook().setVisibility(View.GONE);
mBookcaseFragment.getLlNoDataTips().setVisibility(View.VISIBLE);
@ -273,16 +289,21 @@ public class BookcasePresenter implements BasePresenter {
if (mBookcaseAdapter == null || isBookcaseStyleChange) {
switch (mSetting.getBookcaseStyle()) {
case listMode:
mBookcaseAdapter = new BookcaseDetailedAdapter(mBookcaseFragment.getContext(), R.layout.gridview_book_detailed_item, mBooks, false, this);
mBookcaseAdapter = new BookcaseDetailedAdapter(mBookcaseFragment.getContext(), R.layout.gridview_book_detailed_item, mBooks, false, this, isGroup);
mBookcaseFragment.getGvBook().setNumColumns(1);
break;
case threePalaceMode:
mBookcaseAdapter = new BookcaseDragAdapter(mBookcaseFragment.getContext(), R.layout.gridview_book_item, mBooks, false, this);
mBookcaseAdapter = new BookcaseDragAdapter(mBookcaseFragment.getContext(), R.layout.gridview_book_item, mBooks, false, this, isGroup);
mBookcaseFragment.getGvBook().setNumColumns(3);
break;
}
mBookcaseAdapter.setOnBookCheckedListener(isChecked -> {
changeCheckedAllStatus();
//设置删除和加入分组按钮是否可用
setBtnClickable(mBookcaseAdapter.getmCheckedCount() > 0);
});
mBookcaseFragment.getGvBook().setDragModel(-1);
mBookcaseFragment.getGvBook().setTouchClashparent(((MainActivity) (mBookcaseFragment.getActivity())).getVpContent());
mBookcaseFragment.getGvBook().setTouchClashparent(((MainActivity) (mBookcaseFragment.getActivity())).getViewPagerMain());
mBookcaseFragment.getGvBook().setAdapter(mBookcaseAdapter);
isBookcaseStyleChange = false;
} else {
@ -293,25 +314,43 @@ public class BookcasePresenter implements BasePresenter {
}
}
public void getData() {
init();
if (mSetting.isRefreshWhenStart() || android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
initNoReadNum();
}
}
//初始化书籍
private void initBook() {
mBooks.clear();
mBooks.addAll(mBookService.getAllBooks());
String curBookGroupId = SharedPreUtils.getInstance().getString("curBookGroupId", "");
isGroup = !"".equals(curBookGroupId);
if (mBookcaseAdapter != null) {
mBookcaseAdapter.setGroup(isGroup);
}
mBooks.addAll(mBookService.getGroupBooks(curBookGroupId));
for (int i = 0; i < mBooks.size(); i++) {
if (mBooks.get(i).getSortCode() != i + 1) {
int sort = !isGroup ? mBooks.get(i).getSortCode() : mBooks.get(i).getGroupSort();
if (sort != i + 1) {
if (!isGroup) {
mBooks.get(i).setSortCode(i + 1);
}else {
mBooks.get(i).setGroupSort(i + 1);
}
mBookService.updateEntity(mBooks.get(i));
}
}
}
//初始化书籍分组
private void initBookGroups(boolean isAdd) {
mBookGroups.clear();
mBookGroups.addAll(mBookGroupService.getAllGroups());
mGroupNames = new CharSequence[isAdd ? mBookGroups.size() + 1 : mBookGroups.size()];
for (int i = 0; i < mBookGroups.size(); i++) {
String groupName = mBookGroups.get(i).getName();
mGroupNames[i] = groupName.getBytes().length > 20 ? groupName.substring(0, 8) + "···" : groupName;
}
if (isAdd) {
mGroupNames[mBookGroups.size()] = "添加分组";
}
}
//检查书籍更新
private void initNoReadNum() {
errorLoadingBooks.clear();
finishLoadBookCount = 0;
@ -364,15 +403,6 @@ public class BookcasePresenter implements BasePresenter {
});
}
private void setThemeColor(int colorPrimary, int colorPrimaryDark) {
// mToolbar.setBackgroundResource(colorPrimary);
mBookcaseFragment.getSrlContent().setPrimaryColorsId(colorPrimary, android.R.color.white);
if (Build.VERSION.SDK_INT >= 21) {
mBookcaseFragment.getActivity().getWindow().setStatusBarColor(ContextCompat.getColor(mBookcaseFragment.getContext(), colorPrimaryDark));
}
}
/**
* 显示更新失败的书籍信息
*/
@ -389,22 +419,7 @@ public class BookcasePresenter implements BasePresenter {
}
}
/**
* 创建菜单栏
*/
private void createMenu() {
//如果菜单栏已经创建直接show
if (pm != null) {
pm.show();
return;
}
pm = new PopupMenu(mMainActivity, mMainActivity.getIvMore());
pm.getMenuInflater().inflate(R.menu.menu_book, pm.getMenu());
setIconEnable(pm.getMenu(), true);
if (MyApplication.isApkInDebug(mMainActivity)) {
pm.getMenu().getItem(5).setVisible(true);
}
pm.setOnMenuItemClickListener(item -> {
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_edit:
editBookcase(true);
@ -422,6 +437,9 @@ public class BookcasePresenter implements BasePresenter {
SysManager.saveSetting(mSetting);
init();
return true;
case R.id.action_group_man:
showGroupManDia();
return true;
case R.id.action_addLocalBook:
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.M) {
if (mPermissionsChecker == null) {
@ -435,50 +453,8 @@ public class BookcasePresenter implements BasePresenter {
return true;
}
}
Intent intent = new Intent(mMainActivity, FileSystemActivity.class);
mMainActivity.startActivity(intent);
break;
case R.id.action_syn:
if (!UserService.isLogin()) {
ToastUtils.showWarring("请先登录!");
Intent loginIntent = new Intent(mMainActivity, LoginActivity.class);
mMainActivity.startActivity(loginIntent);
return true;
}
if (mSetting.isAutoSyn()) {
webSynMenu[2] = MyApplication.getmContext().getString(R.string.menu_backup_autoSyn) + "已开启";
} else {
webSynMenu[2] = MyApplication.getmContext().getString(R.string.menu_backup_autoSyn) + "已关闭";
}
new AlertDialog.Builder(mMainActivity)
.setTitle(mMainActivity.getString(R.string.menu_bookcase_syn))
.setAdapter(new ArrayAdapter<>(mMainActivity,
android.R.layout.simple_list_item_1, webSynMenu),
(dialog, which) -> {
switch (which) {
case 0:
synBookcaseToWeb(false);
break;
case 1:
webRestore();
break;
case 2:
String tip = "";
if (mSetting.isAutoSyn()) {
mSetting.setAutoSyn(false);
tip = "每日自动同步已关闭!";
} else {
mSetting.setAutoSyn(true);
tip = "每日自动同步已开启!";
}
SysManager.saveSetting(mSetting);
ToastUtils.showSuccess(tip);
break;
}
})
.setNegativeButton(null, null)
.setPositiveButton(null, null)
.show();
Intent fileSystemIntent = new Intent(mMainActivity, FileSystemActivity.class);
mMainActivity.startActivity(fileSystemIntent);
break;
case R.id.action_download_all:
if (!SharedPreUtils.getInstance().getBoolean("isReadDownloadAllTip")) {
@ -491,122 +467,185 @@ public class BookcasePresenter implements BasePresenter {
} else {
downloadAll(true);
}
return true;
case R.id.action_backup:
AlertDialog bookDialog = new AlertDialog.Builder(mMainActivity)
.setTitle(mMainActivity.getResources().getString(R.string.menu_bookcase_backup))
.setAdapter(new ArrayAdapter<>(mMainActivity,
android.R.layout.simple_list_item_1, backupMenu),
(dialog, which) -> {
switch (which) {
case 0:
mHandler.sendMessage(mHandler.obtainMessage(5));
break;
case 1:
mHandler.sendMessage(mHandler.obtainMessage(6));
break;
}
})
.setNegativeButton(null, null)
.setPositiveButton(null, null)
.create();
bookDialog.show();
return true;
case R.id.action_setting:
Intent settingIntent = new Intent(mMainActivity, MoreSettingActivity.class);
mMainActivity.startActivity(settingIntent);
return true;
case R.id.action_about:
Intent aboutIntent = new Intent(mMainActivity, AboutActivity.class);
mMainActivity.startActivity(aboutIntent);
return true;
}
return false;
}
//显示书籍分组菜单
public void showBookGroupMenu(View view, MainActivity.OnGroupChangeListener ogcl) {
initBookGroups(false);
PopupMenu popupMenu = new PopupMenu(mMainActivity, view, Gravity.END);
popupMenu.getMenu().add(0, 0, 0, "所有书籍");
for (int i = 0; i < mGroupNames.length; i++) {
popupMenu.getMenu().add(0, 0, i + 1, mGroupNames[i]);
}
popupMenu.setOnMenuItemClickListener(menuItem -> {
String curBookGroupId = "";
String curBookGroupName = "";
if (menuItem.getOrder() > 0) {
curBookGroupId = mBookGroups.get(menuItem.getOrder() - 1).getId();
curBookGroupName = mBookGroups.get(menuItem.getOrder() - 1).getName();
}
SharedPreUtils.getInstance().putString("curBookGroupId", curBookGroupId);
SharedPreUtils.getInstance().putString("curBookGroupName", curBookGroupName);
ogcl.onChange();
init();
return true;
});
pm.show();
popupMenu.show();
}
/**
* 显示菜单图标
* 编辑书架
*
* @param menu 菜单
* @param enable 是否显示图标
* @param isEdit
*/
private void setIconEnable(Menu menu, boolean enable) {
try {
Class<?> clazz = Class.forName("com.android.internal.view.menu.MenuBuilder");
Method m = clazz.getDeclaredMethod("setOptionalIconsVisible", boolean.class);
m.setAccessible(true);
//MenuBuilder实现Menu接口,创建菜单时,传进来的menu其实就是MenuBuilder对象(java的多态特征)
m.invoke(menu, enable);
} catch (Exception e) {
e.printStackTrace();
private void editBookcase(boolean isEdit) {
if (isEdit) {
if (mBooks.size() > 0) {
mBookcaseFragment.getSrlContent().setEnableRefresh(false);
mBookcaseAdapter.setmEditState(true);
mBookcaseFragment.getGvBook().setDragModel(DragSortGridView.DRAG_BY_LONG_CLICK);
mBookcaseFragment.getRlBookEdit().setVisibility(View.VISIBLE);
setBtnClickable(false);
changeCheckedAllStatus();
mBookcaseAdapter.notifyDataSetChanged();
} else {
ToastUtils.showWarring("当前无任何书籍,无法编辑书架!");
}
} else {
if (mBookcaseFragment.getGvBook().getmScrollView().getScrollY() == 0
&& android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
mBookcaseFragment.getSrlContent().setEnableRefresh(true);
}
mBookcaseFragment.getGvBook().setDragModel(-1);
mBookcaseAdapter.setmEditState(false);
mBookcaseFragment.getRlBookEdit().setVisibility(View.GONE);
mBookcaseAdapter.notifyDataSetChanged();
}
}
/**
* 备份
* 分组管理对话框
*/
private void backup() {
if (mBooks.size() == 0){
ToastUtils.showWarring("当前书架无任何书籍,无法备份!");
return;
}
DialogCreator.createCommonDialog(mMainActivity, "确认备份吗?", "新备份会替换原有备份!", true,
(dialogInterface, i) -> {
dialogInterface.dismiss();
if (mBackupAndRestore.backup("localBackup")) {
DialogCreator.createTipDialog(mMainActivity, "备份成功,备份文件路径:" + APPCONST.BACKUP_FILE_DIR);
} else {
DialogCreator.createTipDialog(mMainActivity, "未给予储存权限,备份失败!");
private void showGroupManDia() {
MyAlertDialog.build(mMainActivity)
.setTitle("分组管理")
.setItems(mMainActivity.getResources().getStringArray(R.array.group_man)
, (dialog, which) -> {
initBookGroups(false);
switch (which){
case 0:
showAddOrRenameGroupDia(false, 0);
break;
case 1:
showSelectGroupDia((dialog1, which1) -> {
showAddOrRenameGroupDia(true, which1);
});
break;
case 2:
showDeleteGroupDia();
break;
}
}, (dialogInterface, i) -> dialogInterface.dismiss());
}).show();
}
/**
* 恢复
* 添加/重命名分组对话框
*/
private void restore() {
DialogCreator.createCommonDialog(mMainActivity, "确认恢复吗?", "恢复书架会覆盖原有书架!", true,
(dialogInterface, i) -> {
dialogInterface.dismiss();
if (mBackupAndRestore.restore("localBackup")) {
mHandler.sendMessage(mHandler.obtainMessage(7));
// DialogCreator.createTipDialog(mMainActivity,
// "恢复成功!\n注意:本功能属于实验功能,书架恢复后,书籍初次加载时可能加载失败,返回重新加载即可!");
mSetting = SysManager.getSetting();
ToastUtils.showSuccess("书架恢复成功!");
private void showAddOrRenameGroupDia(boolean isRename, int groupNum){
View view = LayoutInflater.from(mMainActivity).inflate(R.layout.edit_dialog, null);
TextInputLayout textInputLayout = view.findViewById(R.id.text_input_lay);
EditText editText = textInputLayout.getEditText();
editText.setHint("请输入分组名");
BookGroup bookGroup = !isRename ? new BookGroup() : mBookGroups.get(groupNum);
String oldName = bookGroup.getName();
if (isRename) {
editText.setText(oldName);
}
editText.requestFocus();
mHandler.postDelayed(() ->{
InputMethodManager imm = (InputMethodManager) mMainActivity
.getSystemService(Context.INPUT_METHOD_SERVICE);
imm.toggleSoftInput(0, InputMethodManager.SHOW_FORCED);
}, 220);
AlertDialog newGroupDia = MyAlertDialog.build(mMainActivity)
.setTitle(!isRename ? "新建分组" : "重命名分组")
.setView(view)
.setCancelable(false)
.setPositiveButton("确认", null)
.setNegativeButton("取消", null)
.show();
Button posBtn = newGroupDia.getButton(AlertDialog.BUTTON_POSITIVE);
posBtn.setEnabled(false);
posBtn.setOnClickListener(v1 -> {
bookGroup.setName(editText.getText().toString());
if (!isRename) {
mBookGroupService.addBookGroup(bookGroup);
}else {
DialogCreator.createTipDialog(mMainActivity, "未找到备份文件或未给予储存权限,恢复失败!");
mBookGroupService.updateEntity(bookGroup);
}
}, (dialogInterface, i) -> dialogInterface.dismiss());
ToastUtils.showSuccess("成功" +
(!isRename ? "添加分组[" : "成功将[" + oldName + "]重命名为[")
+ bookGroup.getName() + "]");
newGroupDia.dismiss();
});
editText.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) {
/**
* 恢复
*/
private void webRestore() {
if (!NetworkUtils.isNetWorkAvailable()) {
ToastUtils.showWarring("无网络连接!");
return;
}
DialogCreator.createCommonDialog(mMainActivity, "确认同步吗?", "将书架从网络同步至本地会覆盖原有书架!", true,
(dialogInterface, i) -> {
dialogInterface.dismiss();
MyApplication.getApplication().newThread(() -> {
if (UserService.webRestore()) {
mHandler.sendMessage(mHandler.obtainMessage(7));
// DialogCreator.createTipDialog(mMainActivity,
// "恢复成功!\n注意:本功能属于实验功能,书架恢复后,书籍初次加载时可能加载失败,返回重新加载即可!");、
mSetting = SysManager.getSetting();
ToastUtils.showSuccess("成功将书架从网络同步至本地!");
@Override
public void afterTextChanged(Editable s) {
String text = editText.getText().toString();
if (editText.getText().length() > 0 && editText.getText().length() <= 10 && !text.equals(oldName)) {
posBtn.setEnabled(true);
} else {
DialogCreator.createTipDialog(mMainActivity, "未找到同步文件,同步失败!");
posBtn.setEnabled(false);
}
}
});
}, (dialogInterface, i) -> dialogInterface.dismiss());
}
/**
* 删除分组对话框
*/
private void showDeleteGroupDia() {
boolean[] checkedItems = new boolean[mGroupNames.length];
new MultiChoiceDialog().create(mMainActivity, "删除分组", mGroupNames
, checkedItems, 0, (dialog, which) -> {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < checkedItems.length; i++) {
if (checkedItems[i]) {
mBookGroupService.deleteEntity(mBookGroups.get(i));
sb.append(mBookGroups.get(i).getName()).append("、");
}
}
if (sb.length() > 0){
sb.deleteCharAt(sb.lastIndexOf("、"));
}
ToastUtils.showSuccess("分组[" + sb.toString() + "]删除成功!");
}, null, null);
}
//显示选择书籍对话框
private void showSelectGroupDia(DialogInterface.OnClickListener onClickListener){
MyAlertDialog.build(mMainActivity)
.setTitle("选择分组")
.setItems(mGroupNames, onClickListener)
.setCancelable(false)
.setPositiveButton("取消", null)
.show();
}
/**********************************************缓存书籍***************************************************************/
@ -635,7 +674,7 @@ public class BookcasePresenter implements BasePresenter {
return;
}
if (isDownloadAllChapters) {
mHandler.sendEmptyMessage(12);
mHandler.sendEmptyMessage(11);
}
downloadFor:
for (final Book book : needDownloadBooks) {
@ -735,7 +774,7 @@ public class BookcasePresenter implements BasePresenter {
}
needCacheChapterNum = needDownloadChapters.size();
if (!isDownloadAll && needCacheChapterNum > 0) {
mHandler.sendEmptyMessage(12);
mHandler.sendEmptyMessage(11);
}
mHandler.postDelayed(sendDownloadNotification, 2 * downloadInterval);
for (Chapter chapter : needDownloadChapters) {
@ -839,36 +878,6 @@ public class BookcasePresenter implements BasePresenter {
}
}
/**
* 添加本地书籍
*
* @param path
*/
public void addLocalBook(String path) {
File file = new File(path);
if (!file.exists()) {
return;
}
Book book = new Book();
book.setName(file.getName().replace(".txt", ""));
book.setChapterUrl(path);
book.setType("本地书籍");
book.setHistoryChapterId("未开始阅读");
book.setNewestChapterTitle("未拆分章节");
book.setAuthor("本地书籍");
book.setSource(BookSource.local.toString());
book.setDesc("");
//判断书籍是否已经添加
Book existsBook = mBookService.findBookByAuthorAndName(book.getName(), book.getAuthor());
if (book.equals(existsBook)) {
ToastUtils.showWarring("该书籍已存在,请勿重复添加!");
return;
}
mBookService.addBook(book);
ToastUtils.showSuccess("本地书籍添加成功");
init();
}
/**
* 同步书架
@ -928,7 +937,7 @@ public class BookcasePresenter implements BasePresenter {
}
/**
*
* 销毁
*/
public void destroy() {
notificationUtil.cancelAll();
@ -939,28 +948,30 @@ public class BookcasePresenter implements BasePresenter {
}
/*class NotificationService extends Service{
/********************************编辑状态下下方按钮********************************************/
private void setBtnClickable(boolean isClickable) {
mBookcaseFragment.getmBtnDelete().setEnabled(isClickable);
mBookcaseFragment.getmBtnDelete().setClickable(isClickable);
mBookcaseFragment.getmBtnAddGroup().setEnabled(isClickable);
mBookcaseFragment.getmBtnAddGroup().setClickable(isClickable);
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
/**
* 改变全选按钮的状态
*/
private void changeCheckedAllStatus() {
//设置是否全选
if (mBookcaseAdapter.getmCheckedCount() == mBookcaseAdapter.getmCheckableCount()) {
mBookcaseAdapter.setIsCheckedAll(true);
} else if (mBookcaseAdapter.isCheckedAll()) {
mBookcaseAdapter.setIsCheckedAll(false);
}
mBookcaseFragment.getmCbSelectAll().setChecked(mBookcaseAdapter.isCheckedAll());
//重置全选的文字
if (mBookcaseAdapter.isCheckedAll()) {
mBookcaseFragment.getmCbSelectAll().setText("取消");
} else {
mBookcaseFragment.getmCbSelectAll().setText("全选");
}
public void sendNotification(Book book, String chapterTitle){
//创建 Notification.Builder 对象
NotificationCompat.Builder builder = new NotificationCompat.Builder(mMainActivity, "channel_download")
.setSmallIcon(R.drawable.ic_download)
//通知栏大图标
.setLargeIcon(BitmapFactory.decodeResource(mMainActivity.getResources(), R.mipmap.ic_launcher))
//点击通知后自动清除
.setAutoCancel(true)
.setContentTitle("正在下载:" + book.getName())
.setContentText(chapterTitle);
builder.addAction(R.drawable.ic_stop_black_24dp, "取消", null);
//发送通知
startForeground(1, builder.build());
}
}*/
}

@ -1,134 +0,0 @@
package xyz.fycz.myreader.ui.presenter;
import android.content.Context;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentPagerAdapter;
import xyz.fycz.myreader.R;
import xyz.fycz.myreader.application.SysManager;
import xyz.fycz.myreader.base.BasePresenter;
import xyz.fycz.myreader.entity.Setting;
import xyz.fycz.myreader.ui.activity.CatalogActivity;
import xyz.fycz.myreader.ui.fragment.CatalogFragment;
import xyz.fycz.myreader.ui.fragment.BookMarkFragment;
import java.util.ArrayList;
import static androidx.fragment.app.FragmentPagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT;
/**
* @author fengyue
* @date 2020/7/22 8:10
*/
public class CatalogActivityPresenter implements BasePresenter {
private CatalogActivity mCatalogActivity;
private ArrayList<Fragment> mFragments = new ArrayList<>();
private String[] tabTitle = {"目录", "书签"};
private boolean isDayStyle;
private FragmentPagerAdapter tabAdapter;
public CatalogActivityPresenter(CatalogActivity mCatalogActivity) {
this.mCatalogActivity = mCatalogActivity;
}
@Override
public void start() {
Setting setting = SysManager.getSetting();
isDayStyle = setting.isDayStyle();
//设置日夜间
if (!isDayStyle){
mCatalogActivity.setStatusBar(R.color.sys_dialog_setting_bg, true);
mCatalogActivity.getRlCommonTitle().setBackground(mCatalogActivity.getDrawable(R.color.sys_dialog_setting_bg));
mCatalogActivity.getTvBack().setImageDrawable(mCatalogActivity.getDrawable(R.mipmap.larrow_white2));
mCatalogActivity.getIvCancel().setImageDrawable(mCatalogActivity.getDrawable(R.mipmap.ic_cha_black));
mCatalogActivity.getIvSearch().setImageDrawable(mCatalogActivity.getDrawable(R.mipmap.b9));
mCatalogActivity.getEtSearch().setTextColor(mCatalogActivity.getResources().getColor(R.color.sys_night_word));
mCatalogActivity.getEtSearch().setHintTextColor(mCatalogActivity.getResources().getColor(R.color.sys_night_word));
}
init();
InputMethodManager manager = ((InputMethodManager) mCatalogActivity.getSystemService(Context.INPUT_METHOD_SERVICE));
mCatalogActivity.getTvBack().setOnClickListener(v -> mCatalogActivity.finish());
mCatalogActivity.getIvSearch().setOnClickListener(v -> {
mCatalogActivity.getTlTabMenu().setVisibility(View.GONE);
mCatalogActivity.getIvSearch().setVisibility(View.GONE);
mCatalogActivity.getEtSearch().setVisibility(View.VISIBLE);
mCatalogActivity.getIvCancel().setVisibility(View.VISIBLE);
mCatalogActivity.getEtSearch().setFocusable(true);
mCatalogActivity.getEtSearch().setFocusableInTouchMode(true);
mCatalogActivity.getEtSearch().requestFocus();
});
mCatalogActivity.getEtSearch().setOnFocusChangeListener((v, hasFocus) -> {
if (hasFocus){
if (manager != null) manager.showSoftInput(v, InputMethodManager.SHOW_IMPLICIT);
}else {
if (manager != null) manager.hideSoftInputFromWindow(v.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
}
});
mCatalogActivity.getIvCancel().setOnClickListener(v -> {
mCatalogActivity.getTlTabMenu().setVisibility(View.VISIBLE);
mCatalogActivity.getIvSearch().setVisibility(View.VISIBLE);
mCatalogActivity.getEtSearch().setVisibility(View.GONE);
mCatalogActivity.getIvCancel().setVisibility(View.GONE);
if(!"".equals(mCatalogActivity.getEtSearch().getText().toString())){
mCatalogActivity.getEtSearch().setText("");
}
});
mCatalogActivity.getEtSearch().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) {
}
@Override
public void afterTextChanged(Editable s) {
switch (mCatalogActivity.getVpContent().getCurrentItem()){
case 0:
((CatalogFragment) tabAdapter.getItem(0)).getmCatalogPresent().startSearch(s.toString());
break;
case 1:
((BookMarkFragment) tabAdapter.getItem(1)).getmBookMarkPresenter().startSearch(s.toString());
break;
}
}
});
}
private void init(){
mFragments.add(new CatalogFragment());
mFragments.add(new BookMarkFragment());
tabAdapter = new FragmentPagerAdapter(mCatalogActivity.getSupportFragmentManager(),BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {
@Override
public Fragment getItem(int position) {
return mFragments.get(position);
}
@Override
public int getCount() {
return mFragments.size();
}
@Override
public CharSequence getPageTitle(int position) {
return tabTitle[position];
}
};
mCatalogActivity.getVpContent().setAdapter(tabAdapter);
mCatalogActivity.getTlTabMenu().setupWithViewPager(mCatalogActivity.getVpContent());
mCatalogActivity.getVpContent().setCurrentItem(0);
}
}

@ -9,6 +9,7 @@ import xyz.fycz.myreader.application.SysManager;
import xyz.fycz.myreader.base.BasePresenter;
import xyz.fycz.myreader.callback.ResultCallback;
import xyz.fycz.myreader.common.APPCONST;
import xyz.fycz.myreader.ui.activity.CatalogActivity;
import xyz.fycz.myreader.util.ToastUtils;
import xyz.fycz.myreader.webapi.crawler.ReadCrawlerUtil;
import xyz.fycz.myreader.greendao.entity.Book;
@ -42,11 +43,7 @@ public class CatalogPresenter implements BasePresenter {
@Override
public void start() {
mBook = (Book) mCatalogFragment.getActivity().getIntent().getSerializableExtra(APPCONST.BOOK);
isDayStyle = SysManager.getSetting().isDayStyle();
if (!isDayStyle) {
mCatalogFragment.getLvChapterList().setBackground(mCatalogFragment.getActivity().getDrawable(R.color.sys_dialog_setting_bg));
}
mBook = ((CatalogActivity) mCatalogFragment.getActivity()).getmBook();
mCatalogFragment.getFcChangeSort().setOnClickListener(view -> {
if (curSortflag == 0) {//当前正序
curSortflag = 1;

@ -1,118 +0,0 @@
package xyz.fycz.myreader.ui.presenter;
import android.annotation.SuppressLint;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import xyz.fycz.myreader.R;
import xyz.fycz.myreader.base.BasePresenter;
import xyz.fycz.myreader.common.APPCONST;
import xyz.fycz.myreader.enums.Font;
import xyz.fycz.myreader.ui.activity.FontsActivity;
import xyz.fycz.myreader.ui.adapter.FontsAdapter;
import xyz.fycz.myreader.util.IOUtils;
import xyz.fycz.myreader.util.ToastUtils;
import xyz.fycz.myreader.util.utils.FileUtils;
import java.io.*;
import java.util.ArrayList;
/**
* Created by zhao on 2017/8/7.
*/
public class FontsPresenter implements BasePresenter {
private FontsActivity mFontsActivity;
private ArrayList<Font> mFonts;
private FontsAdapter mFontsAdapter;
@SuppressLint("HandlerLeak")
private Handler mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
switch (msg.what){
case 1:
init();
break;
}
}
};
public FontsPresenter(FontsActivity fontsActivity) {
mFontsActivity = fontsActivity;
}
@Override
public void start() {
mFontsActivity.getLlTitleBack().setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mFontsActivity.finish();
}
});
mFontsActivity.getTvTitleText().setText(mFontsActivity.getString(R.string.font));
init();
}
private void init() {
initFonts();
mFontsAdapter = new FontsAdapter(mFontsActivity, R.layout.listview_font_item, mFonts, mFontsActivity);
mFontsActivity.getLvFonts().setAdapter(mFontsAdapter);
mFontsActivity.getPbLoading().setVisibility(View.GONE);
}
private void initFonts() {
mFonts = new ArrayList<>();
mFonts.add(Font.默认字体);
mFonts.add(Font.方正楷体);
mFonts.add(Font.经典宋体);
mFonts.add(Font.方正行楷);
mFonts.add(Font.迷你隶书);
mFonts.add(Font.方正黄草);
mFonts.add(Font.方正硬笔行书);
mFonts.add(Font.本地字体);
}
public void notifyChange(){
mFontsAdapter.notifyDataSetChanged();
}
public void saveLocalFont(String path){
File fontFile = new File(path);
if (!fontFile.exists()){
ToastUtils.showWarring("未找到字体文件!");
return;
}
String fontName = fontFile.getName();
if (!fontName.endsWith(".ttf")){
ToastUtils.showError("字体更换失败,请选择ttf格式的字体文件!");
return;
}
String dirPath = fontFile.getParentFile().getAbsolutePath() + "/";
if (dirPath.equals(APPCONST.FONT_BOOK_DIR)){
mFontsAdapter.saveLocalFontName(fontName);
return;
}
FileInputStream fis = null;
FileOutputStream fos = null;
try {
fis = new FileInputStream(fontFile);
fos = new FileOutputStream(FileUtils.getFile(APPCONST.FONT_BOOK_DIR + fontName));
byte[] bytes = new byte[1021];
int len = -1;
while ((len = fis.read(bytes)) != -1){
fos.write(bytes, 0, len);
}
fos.flush();
mFontsAdapter.saveLocalFontName(fontName);
} catch (IOException e) {
e.printStackTrace();
ToastUtils.showError("读取字体文件出错!\n" + e.getLocalizedMessage());
}finally {
IOUtils.close(fis, fos);
}
}
}

@ -1,137 +0,0 @@
package xyz.fycz.myreader.ui.presenter;
import android.annotation.SuppressLint;
import android.app.ProgressDialog;
import android.content.Intent;
import android.graphics.Bitmap;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import xyz.fycz.myreader.backup.UserService;
import xyz.fycz.myreader.base.BasePresenter;
import xyz.fycz.myreader.callback.ResultCallback;
import xyz.fycz.myreader.common.APPCONST;
import xyz.fycz.myreader.creator.DialogCreator;
import xyz.fycz.myreader.ui.activity.LoginActivity;
import xyz.fycz.myreader.ui.activity.RegisterActivity;
import xyz.fycz.myreader.util.CodeUtil;
import xyz.fycz.myreader.util.CyptoUtils;
import xyz.fycz.myreader.util.ToastUtils;
import xyz.fycz.myreader.util.utils.NetworkUtils;
import java.util.HashMap;
import java.util.Map;
/**
* @author fengyue
* @date 2020/4/26 20:31
*/
public class LoginPresenter implements BasePresenter {
private LoginActivity mLoginActivity;
private String code;
public LoginPresenter(LoginActivity mLoginActivity) {
this.mLoginActivity = mLoginActivity;
}
@SuppressLint("HandlerLeak")
private Handler mHandler = new Handler() {
@SuppressLint("HandlerLeak")
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case 1:
mLoginActivity.getLoginBtn().setEnabled(true);
break;
case 2:
createCaptcha();
break;
}
}
};
@Override
public void start() {
mHandler.sendMessage(mHandler.obtainMessage(2));
mLoginActivity.getTvTitleText().setText("登录");
mLoginActivity.getLlTitleBack().setOnClickListener(v -> mLoginActivity.finish());
String username = UserService.readUsername();
mLoginActivity.getUser().setText(username);
mLoginActivity.getUser().requestFocus(username.length());
//监听内容改变 -> 控制按钮的点击状态
mLoginActivity.getUser().addTextChangedListener(mLoginActivity);
mLoginActivity.getPassword().addTextChangedListener(mLoginActivity);
mLoginActivity.getEtCaptcha().addTextChangedListener(mLoginActivity);
mLoginActivity.getIvCaptcha().setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mHandler.sendMessage(mHandler.obtainMessage(2));
}
});
mLoginActivity.getLoginBtn().setOnClickListener(v -> {
mHandler.sendMessage(mHandler.obtainMessage(2));
if (!code.toLowerCase().equals(mLoginActivity.getEtCaptcha().getText().toString().toLowerCase())){
DialogCreator.createTipDialog(mLoginActivity, "验证码错误!");
return;
}
if (!NetworkUtils.isNetWorkAvailable()) {
ToastUtils.showError("无网络连接!");
return;
}
ProgressDialog dialog = DialogCreator.createProgressDialog(mLoginActivity, null, "正在登陆...");
mLoginActivity.getLoginBtn().setEnabled(false);
final String loginName = mLoginActivity.getUser().getText().toString().trim();
String loginPwd = mLoginActivity.getPassword().getText().toString();
final Map<String, String> userLoginInfo = new HashMap<>();
userLoginInfo.put("loginName", loginName);
userLoginInfo.put("loginPwd", CyptoUtils.encode(APPCONST.KEY, loginPwd));
//验证用户名和密码
UserService.login(userLoginInfo, new ResultCallback() {
@Override
public void onFinish(Object o, int code) {
String result = (String) o;
String[] info = result.split(":");
int resultCode = Integer.parseInt(info[0].trim());
String resultName = info[1].trim();
//最后输出结果
if (resultCode == 102) {
UserService.writeConfig(userLoginInfo);
UserService.writeUsername(loginName);
mLoginActivity.finish();
ToastUtils.showSuccess(resultName);
} else {
mHandler.sendMessage(mHandler.obtainMessage(1));
dialog.dismiss();
ToastUtils.showWarring(resultName);
}
}
@Override
public void onError(Exception e) {
ToastUtils.showError("登录失败\n" + e.getLocalizedMessage());
mHandler.sendMessage(mHandler.obtainMessage(1));
dialog.dismiss();
}
});
});
mLoginActivity.getTvRegister().setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(mLoginActivity, RegisterActivity.class);
mLoginActivity.startActivity(intent);
}
});
}
public void createCaptcha() {
code = CodeUtil.getInstance().createCode();
Bitmap codeBitmap = CodeUtil.getInstance().createBitmap(code);
mLoginActivity.getIvCaptcha().setImageBitmap(codeBitmap);
}
}

@ -1,134 +0,0 @@
package xyz.fycz.myreader.ui.presenter;
import android.content.DialogInterface;
import android.content.Intent;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentPagerAdapter;
import xyz.fycz.myreader.application.MyApplication;
import xyz.fycz.myreader.application.SysManager;
import xyz.fycz.myreader.base.BasePresenter;
import xyz.fycz.myreader.common.APPCONST;
import xyz.fycz.myreader.creator.DialogCreator;
import xyz.fycz.myreader.entity.Setting;
import xyz.fycz.myreader.ui.activity.MainActivity;
import xyz.fycz.myreader.ui.fragment.BookcaseFragment;
import xyz.fycz.myreader.ui.activity.SearchBookActivity;
import xyz.fycz.myreader.ui.activity.LoginActivity;
import xyz.fycz.myreader.util.ToastUtils;
import java.io.File;
import java.util.ArrayList;
import static androidx.fragment.app.FragmentPagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT;
import static xyz.fycz.myreader.application.MyApplication.checkVersionByServer;
public class MainPresenter implements BasePresenter {
private MainActivity mMainActivity;
private ArrayList<Fragment> mFragments = new ArrayList<>();
private String[] tabTitle = {"书架"};
private BookcaseFragment mBookcaseFragment;
public MainPresenter(MainActivity mainActivity) {
mMainActivity = mainActivity;
}
@Override
public void start() {
try {
Setting mSetting = SysManager.getSetting();
int settingVersion = mSetting.getSettingVersion();
if (settingVersion < APPCONST.SETTING_VERSION){
SysManager.resetSetting();
//DialogCreator.createTipDialog(mMainActivity, "因组件升级,阅读字体及背景颜色已恢复默认颜色!");
}
}catch (Exception e){
SysManager.resetSetting();
//DialogCreator.createTipDialog(mMainActivity, "因组件升级,阅读字体及背景颜色已恢复默认颜色");
}
init();
checkVersionByServer(mMainActivity, false, (BookcaseFragment) mFragments.get(0));
mMainActivity.getIvSearch().setOnClickListener(view -> {
Intent intent = new Intent(mMainActivity, SearchBookActivity.class);
mMainActivity.startActivity(intent);
});
mMainActivity.getCivAvatar().setOnClickListener(v -> {
final File file = MyApplication.getApplication().getFileStreamPath("userConfig.fy");
if (file.exists()) {
DialogCreator.createCommonDialog(mMainActivity, "退出登录", "确定要退出登录吗?"
, true, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if (file.delete()) {
ToastUtils.showSuccess("退出成功");
Intent intent = new Intent(mMainActivity, LoginActivity.class);
mMainActivity.startActivity(intent);
} else {
ToastUtils.showError("退出失败(Error:file.delete())");
}
}
}, (dialog, which) -> dialog.dismiss());
} else {
Intent intent = new Intent(mMainActivity, LoginActivity.class);
mMainActivity.startActivity(intent);
}
});
}
/**
* 初始化
*/
private void init() {
mBookcaseFragment = new BookcaseFragment();
mFragments.add(mBookcaseFragment);
mMainActivity.getVpContent().setAdapter(new FragmentPagerAdapter(mMainActivity.getSupportFragmentManager(), BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {
@Override
public Fragment getItem(int position) {
return mFragments.get(position);
}
@Override
public int getCount() {
return mFragments.size();
}
@Override
public CharSequence getPageTitle(int position) {
return tabTitle[position];
}
});
mMainActivity.getTlTabMenu().setupWithViewPager(mMainActivity.getVpContent());
mMainActivity.getVpContent().setCurrentItem(0);
}
/**
* 添加本地书籍
* @param path
*/
public void addLocalBook(String path){
mBookcaseFragment.getmBookcasePresenter().addLocalBook(path);
}
/**
* 取消编辑状态
*/
public void cancelEdit(){
mBookcaseFragment.getmBookcasePresenter().cancelEdit();
}
/**
* 判断是否处于编辑状态
* @return
*/
public boolean ismEditState(){
if (mBookcaseFragment.getmBookcasePresenter() == null) {
return false;
}
return mBookcaseFragment.getmBookcasePresenter().ismEditState();
}
}

@ -17,8 +17,6 @@ import android.view.WindowManager;
import android.widget.SeekBar;
import android.widget.TextView;
import androidx.appcompat.app.AlertDialog;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
@ -30,8 +28,10 @@ import xyz.fycz.myreader.base.BasePresenter;
import xyz.fycz.myreader.callback.ResultCallback;
import xyz.fycz.myreader.common.APPCONST;
import xyz.fycz.myreader.common.URLCONST;
import xyz.fycz.myreader.ui.activity.MoreSettingActivity;
import xyz.fycz.myreader.creator.MyAlertDialog;
import xyz.fycz.myreader.ui.activity.*;
import xyz.fycz.myreader.util.*;
import xyz.fycz.myreader.util.utils.ColorUtil;
import xyz.fycz.myreader.webapi.crawler.ReadCrawler;
import xyz.fycz.myreader.webapi.crawler.ReadCrawlerUtil;
import xyz.fycz.myreader.creator.DialogCreator;
@ -45,9 +45,6 @@ import xyz.fycz.myreader.greendao.entity.Chapter;
import xyz.fycz.myreader.greendao.service.BookMarkService;
import xyz.fycz.myreader.greendao.service.BookService;
import xyz.fycz.myreader.greendao.service.ChapterService;
import xyz.fycz.myreader.ui.activity.FontsActivity;
import xyz.fycz.myreader.ui.activity.ReadActivity;
import xyz.fycz.myreader.ui.activity.CatalogActivity;
import xyz.fycz.myreader.util.notification.NotificationClickReceiver;
import xyz.fycz.myreader.util.notification.NotificationUtil;
import xyz.fycz.myreader.util.utils.NetworkUtils;
@ -214,6 +211,9 @@ public class ReadPresenter implements BasePresenter {
@Override
public void start() {
if (SharedPreUtils.getInstance().getBoolean("isNightFS", false)) {
mSetting.setDayStyle(!ColorUtil.isColorLight(mReadActivity.getColor(R.color.textPrimary)));
}
//息屏时间
screenTimeOut = mSetting.getResetScreen() * 60;
@ -237,23 +237,19 @@ public class ReadPresenter implements BasePresenter {
BrightUtil.setBrightness(mReadActivity, BrightUtil.progressToBright(mSetting.getBrightProgress()));
}
//是否直接打开本地txt文件
String path = null;
if (Intent.ACTION_VIEW.equals(mReadActivity.getIntent().getAction())) {
Uri uri = mReadActivity.getIntent().getData();
path = getPath(mReadActivity, uri);
}
if (!StringHelper.isEmpty(path)) {
//本地txt文件路径不为空,添加书籍
addLocalBook(path);
} else {
//路径为空,说明不是直接打开txt文件
mBook = (Book) mReadActivity.getIntent().getSerializableExtra(APPCONST.BOOK);
if (!loadBook()){
mReadActivity.finish();
return;
}
isCollected = mReadActivity.getIntent().getBooleanExtra("isCollected", true);
//当书籍Collected且书籍id不为空的时候保存上次阅读信息
if (isCollected && !StringHelper.isEmpty(mBook.getId())) {
//保存上次阅读信息
SharedPreUtils.getInstance().putString("lastRead", mBook.getId());
}
mReadCrawler = ReadCrawlerUtil.getReadCrawler(mBook.getSource());
mPageLoader = mReadActivity.getSrlContent().getPageLoader(mBook, mReadCrawler, mSetting);
@ -264,6 +260,47 @@ public class ReadPresenter implements BasePresenter {
getData();
}
/**
* 进入阅读书籍有三种方式
* 1直接从书架进入这种方式书籍一定Collected
* 2从外部打开txt文件这种方式会添加进书架
* 3从快捷图标打开上次阅读书籍
* @return 是否加载成功
*/
private boolean loadBook() {
//是否直接打开本地txt文件
String path = null;
if (Intent.ACTION_VIEW.equals(mReadActivity.getIntent().getAction())) {
Uri uri = mReadActivity.getIntent().getData();
if (uri != null) {
path = getPath(mReadActivity, uri);
}
}
if (!StringHelper.isEmpty(path)) {
//本地txt文件路径不为空,添加书籍
addLocalBook(path);
} else {
//路径为空,说明不是直接打开txt文件
mBook = (Book) mReadActivity.getIntent().getSerializableExtra(APPCONST.BOOK);
//mBook为空,说明是从快捷方式启动
if (mBook == null){
String bookId = SharedPreUtils.getInstance().getString("lastRead", "");
if ("".equals(bookId)){//没有上次阅读信息
ToastUtils.showWarring("当前没有阅读任何书籍,无法加载上次阅读书籍!");
mReadActivity.finish();
return false;
}else {//有信息
mBook = mBookService.getBookById(bookId);
if (mBook == null){//上次阅读的书籍不存在
ToastUtils.showWarring("上次阅读书籍已不存在/移除书架,无法加载!");
mReadActivity.finish();
return false;
}//存在就继续执行
}
}
}
return true;
}
/**
* 保存最后阅读章节的进度
@ -342,6 +379,7 @@ public class ReadPresenter implements BasePresenter {
intent.putExtra(APPCONST.BOOK, mBook);
mReadActivity.startActivityForResult(intent, APPCONST.REQUEST_CHAPTER_PAGE);
}, (dialog, view, isDayStyle) -> {//日夜切换
dialog.dismiss();
changeNightAndDaySetting(isDayStyle);
}, view -> {//设置
showSettingDetailView();
@ -477,7 +515,7 @@ public class ReadPresenter implements BasePresenter {
default:
checkedItem = 0;
}
mPageModeDialog = new AlertDialog.Builder(mReadActivity)
mPageModeDialog = MyAlertDialog.build(mReadActivity)
.setTitle("翻页模式")
.setSingleChoiceItems(pageMode, checkedItem, (dialog, which) -> {
switch (which) {
@ -770,7 +808,7 @@ public class ReadPresenter implements BasePresenter {
return;
}
MyApplication.runOnUiThread(() -> {
new AlertDialog.Builder(mReadActivity)
MyAlertDialog.build(mReadActivity)
.setTitle("缓存书籍")
.setSingleChoiceItems(APPCONST.DIALOG_DOWNLOAD, selectedIndex, (dialog, which) -> selectedIndex = which).setNegativeButton("取消", ((dialog, which) -> dialog.dismiss())).setPositiveButton("确定",
(dialog, which) -> {
@ -957,8 +995,9 @@ public class ReadPresenter implements BasePresenter {
private void changeNightAndDaySetting(boolean isCurDayStyle) {
mSetting.setDayStyle(!isCurDayStyle);
SysManager.saveSetting(mSetting);
MyApplication.getApplication().setNightTheme(isCurDayStyle);
settingChange = true;
mPageLoader.setPageStyle(!isCurDayStyle);
//mPageLoader.setPageStyle(!isCurDayStyle);
}
/**
@ -992,11 +1031,14 @@ public class ReadPresenter implements BasePresenter {
*/
private void changeStyle(ReadStyle readStyle) {
settingChange = true;
if (!mSetting.isDayStyle()) {
mSetting.setDayStyle(true);
}
mSetting.setReadStyle(readStyle);
SysManager.saveSetting(mSetting);
if (!mSetting.isDayStyle()) {
DialogCreator.createCommonDialog(mReadActivity, "提示", "是否希望切换为日间模式?",
false, "确定", "取消", (dialog, which) -> {
changeNightAndDaySetting(false);
}, null);
}
MyApplication.runOnUiThread(() -> mPageLoader.setPageStyle(true));
}
@ -1083,7 +1125,6 @@ public class ReadPresenter implements BasePresenter {
book.setSource(BookSource.local.toString());
book.setDesc("无");
book.setIsCloseUpdate(true);
//判断书籍是否已经添加
Book existsBook = mBookService.findBookByAuthorAndName(book.getName(), book.getAuthor());
if (book.equals(existsBook)) {
@ -1220,7 +1261,9 @@ public class ReadPresenter implements BasePresenter {
for (int i = 0; i < 9; i++) {
mHandler.removeMessages(i + 1);
}
if (mPageLoader != null) {
mPageLoader.closeBook();
mPageLoader = null;
}
}
}

@ -1,244 +0,0 @@
package xyz.fycz.myreader.ui.presenter;
import android.annotation.SuppressLint;
import android.app.ProgressDialog;
import android.graphics.Bitmap;
import android.os.Handler;
import android.os.Message;
import android.text.Editable;
import android.text.TextWatcher;
import android.text.method.LinkMovementMethod;
import android.view.View;
import xyz.fycz.myreader.backup.UserService;
import xyz.fycz.myreader.base.BasePresenter;
import xyz.fycz.myreader.callback.ResultCallback;
import xyz.fycz.myreader.creator.DialogCreator;
import xyz.fycz.myreader.ui.activity.RegisterActivity;
import xyz.fycz.myreader.util.CodeUtil;
import xyz.fycz.myreader.util.ToastUtils;
import xyz.fycz.myreader.util.utils.StringUtils;
import java.util.HashMap;
import java.util.Map;
/**
* @author fengyue
* @date 2020/4/26 20:31
*/
public class RegisterPresenter implements BasePresenter {
private RegisterActivity mRegisterActivity;
private String code;
private String username = "";
private String password = "";
private String rpPassword = "";
private String inputCode = "";
public RegisterPresenter(RegisterActivity mRegisterActivity) {
this.mRegisterActivity = mRegisterActivity;
}
@SuppressLint("HandlerLeak")
private Handler mHandler = new Handler() {
@SuppressLint("HandlerLeak")
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case 1:
createCaptcha();
break;
case 2:
showTip((String) msg.obj);
break;
case 3:
mRegisterActivity.getTvRegisterTip().setVisibility(View.GONE);
break;
}
}
};
@Override
public void start() {
mHandler.sendMessage(mHandler.obtainMessage(1));
mRegisterActivity.getTvTitleText().setText("注册");
mRegisterActivity.getEtUsername().requestFocus();
mRegisterActivity.getLlTitleBack().setOnClickListener(v -> mRegisterActivity.finish());
mRegisterActivity.getEtUsername().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) {
}
@Override
public void afterTextChanged(Editable s) {
StringUtils.isNotChinese(s);
username = s.toString();
if (username.length() < 6 || username.length() >14){
mHandler.sendMessage(mHandler.obtainMessage(2, "用户名必须在6-14位之间"));
} else if(!username.substring(0, 1).matches("^[A-Za-z]$")){
mHandler.sendMessage(mHandler.obtainMessage(2,
"用户名只能以字母开头"));
}else if(!username.matches("^[A-Za-z0-9-_]+$")){
mHandler.sendMessage(mHandler.obtainMessage(2,
"用户名只能由数字、字母、下划线、减号组成"));
}else {
mHandler.sendMessage(mHandler.obtainMessage(3));
}
checkNotNone();
}
});
mRegisterActivity.getEtPassword().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) {
}
@Override
public void afterTextChanged(Editable s) {
password = s.toString();
if (password.length() < 8 || password.length() > 16){
mHandler.sendMessage(mHandler.obtainMessage(2, "密码必须在8-16位之间"));
} else if(password.matches("^\\d+$")){
mHandler.sendMessage(mHandler.obtainMessage(2, "密码不能是纯数字"));
} else {
mHandler.sendMessage(mHandler.obtainMessage(3));
}
checkNotNone();
}
});
mRegisterActivity.getEtRpPassword().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) {
}
@Override
public void afterTextChanged(Editable s) {
rpPassword = s.toString();
if (!rpPassword.equals(password)){
mHandler.sendMessage(mHandler.obtainMessage(2, "两次输入的密码不一致"));
} else {
mHandler.sendMessage(mHandler.obtainMessage(3));
}
checkNotNone();
}
});
mRegisterActivity.getEtCaptcha().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) {
}
@Override
public void afterTextChanged(Editable s) {
inputCode = s.toString().trim().toLowerCase();
if (!inputCode.equals(code.toLowerCase())){
mHandler.sendMessage(mHandler.obtainMessage(2, "验证码错误"));
} else {
mHandler.sendMessage(mHandler.obtainMessage(3));
}
checkNotNone();
}
});
mRegisterActivity.getIvCaptcha().setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mHandler.sendMessage(mHandler.obtainMessage(1));
}
});
mRegisterActivity.getBtRegister().setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (!username.matches("^[A-Za-z][A-Za-z0-9]{5,13}$")){
DialogCreator.createTipDialog(mRegisterActivity, "用户名格式错误",
"用户名必须在6-14位之间\n用户名只能以字母开头\n用户名只能由数字、字母、下划线、减号组成");
}else if(password.matches("^\\d+$") || !password.matches("^.{8,16}$")){
DialogCreator.createTipDialog(mRegisterActivity, "密码格式错误",
"密码必须在8-16位之间\n密码不能是纯数字");
}else if(!password.equals(rpPassword)){
DialogCreator.createTipDialog(mRegisterActivity, "重复密码错误",
"两次输入的密码不一致");
}else if(!inputCode.trim().toLowerCase().equals(code.toLowerCase())){
DialogCreator.createTipDialog(mRegisterActivity, "验证码错误");
}else if(!mRegisterActivity.getCbAgreement().isChecked()){
DialogCreator.createTipDialog(mRegisterActivity, "请勾选同意《用户服务协议》");
}else {
ProgressDialog dialog = DialogCreator.createProgressDialog(mRegisterActivity, null, "正在注册...");
Map<String, String> userRegisterInfo = new HashMap<>();
userRegisterInfo.put("username", username);
userRegisterInfo.put("password", password);
UserService.register(userRegisterInfo, new ResultCallback() {
@Override
public void onFinish(Object o, int code) {
String[] info = ((String) o).split(":");
int result = Integer.parseInt(info[0].trim());
if (result == 101){
UserService.writeUsername(username);
ToastUtils.showSuccess(info[1]);
mRegisterActivity.finish();
}else {
ToastUtils.showWarring(info[1]);
}
dialog.dismiss();
}
@Override
public void onError(Exception e) {
ToastUtils.showError("注册失败:\n" + e.getLocalizedMessage());
dialog.dismiss();
}
});
}
mHandler.sendMessage(mHandler.obtainMessage(1));
}
});
mRegisterActivity.getTvAgreement().setMovementMethod(LinkMovementMethod.getInstance());
}
public void createCaptcha() {
code = CodeUtil.getInstance().createCode();
Bitmap codeBitmap = CodeUtil.getInstance().createBitmap(code);
mRegisterActivity.getIvCaptcha().setImageBitmap(codeBitmap);
}
public void showTip(String tip) {
mRegisterActivity.getTvRegisterTip().setVisibility(View.VISIBLE);
mRegisterActivity.getTvRegisterTip().setText(tip);
}
public void checkNotNone(){
if ("".equals(username) || "".equals(password) || "".equals(rpPassword) || "".equals(inputCode)){
mRegisterActivity.getBtRegister().setEnabled(false);
}else {
mRegisterActivity.getBtRegister().setEnabled(true);
}
}
}

@ -1,354 +0,0 @@
package xyz.fycz.myreader.ui.presenter;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.Handler;
import android.os.Message;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.KeyEvent;
import android.view.View;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import xyz.fycz.myreader.application.MyApplication;
import xyz.fycz.myreader.webapi.crawler.*;
import xyz.fycz.myreader.entity.SearchBookBean;
import xyz.fycz.myreader.mulvalmap.ConcurrentMultiValueMap;
import xyz.fycz.myreader.ui.activity.BookDetailedActivity;
import xyz.fycz.myreader.R;
import xyz.fycz.myreader.base.BasePresenter;
import xyz.fycz.myreader.callback.ResultCallback;
import xyz.fycz.myreader.common.APPCONST;
import xyz.fycz.myreader.greendao.entity.Book;
import xyz.fycz.myreader.greendao.entity.SearchHistory;
import xyz.fycz.myreader.greendao.service.SearchHistoryService;
import xyz.fycz.myreader.ui.activity.SearchBookActivity;
import xyz.fycz.myreader.ui.adapter.SearchBookAdapter;
import xyz.fycz.myreader.ui.adapter.SearchHistoryAdapter;
import xyz.fycz.myreader.util.StringHelper;
import xyz.fycz.myreader.webapi.CommonApi;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
public class SearchBookPrensenter implements BasePresenter {
private SearchBookActivity mSearchBookActivity;
private SearchBookAdapter mSearchBookAdapter;
private String searchKey;//搜索关键字
private ArrayList<SearchBookBean> mBooksBean = new ArrayList<>();
private ConcurrentMultiValueMap<SearchBookBean, Book> mBooks = new ConcurrentMultiValueMap<>();
private ArrayList<Book> mAdapterBooks = new ArrayList<>();
private ArrayList<SearchHistory> mSearchHistories = new ArrayList<>();
private ArrayList<String> mSuggestions = new ArrayList<>();
private SearchHistoryService mSearchHistoryService;
private SearchHistoryAdapter mSearchHistoryAdapter;
private int curThreadCount;
private int allThreadCount;
private int inputConfirm = 0;//搜索输入确认
private int confirmTime = 1000;//搜索输入确认时间(毫秒)
private static String[] suggestion = {"第一序列", "大道朝天", "伏天氏", "终极斗罗", "我师兄实在太稳健了", "烂柯棋缘", "诡秘之主"};
private static String[] suggestion2 = {"不朽凡人", "圣墟", "我是至尊", "龙王传说", "太古神王", "一念永恒", "雪鹰领主", "大主宰"};
@SuppressLint("HandlerLeak")
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case 1:
search();
break;
case 2:
if (curThreadCount == 0) {
initSearchList();
mSearchBookActivity.getSrlSearchBookList().finishRefresh();
mSearchBookActivity.getPbLoading().setVisibility(View.GONE);
}/*else {
notifyDataSetChanged();
mSearchBookActivity.getSrlSearchBookList().finishRefresh();
}*/
break;
}
}
};
public SearchBookPrensenter(SearchBookActivity searchBookActivity) {
mSearchBookActivity = searchBookActivity;
mSearchHistoryService = SearchHistoryService.getInstance();
for (int i = 0; i < suggestion.length; i++) {
mSuggestions.add(suggestion[i]);
}
}
@Override
public void start() {
mSearchBookActivity.getTvTitleText().setText("搜索");
mSearchBookActivity.getEtSearchKey().requestFocus();//get the focus
//enter事件
mSearchBookActivity.getEtSearchKey().setOnEditorActionListener((textView, i, keyEvent) -> {
if (i == EditorInfo.IME_ACTION_UNSPECIFIED) {
mHandler.sendMessage(mHandler.obtainMessage(1));
return (keyEvent.getKeyCode() == KeyEvent.KEYCODE_ENTER);
}
return false;
});
//换一批点击事件
mSearchBookActivity.getRenewByImage().setOnClickListener(new RenewSuggestionBook());
//换一批点击事件
mSearchBookActivity.getRenewByText().setOnClickListener(new RenewSuggestionBook());
//返回
mSearchBookActivity.getLlTitleBack().setOnClickListener(view -> mSearchBookActivity.finish());
//搜索框改变事件
mSearchBookActivity.getEtSearchKey().addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void afterTextChanged(final Editable editable) {
searchKey = editable.toString();
if (StringHelper.isEmpty(searchKey)) {
mHandler.sendMessage(mHandler.obtainMessage(1));
}
}
});
//进入书籍详情页
mSearchBookActivity.getGvSearchBooksList().setOnItemClickListener((adapterView, view, i, l) -> {
Intent intent = new Intent(mSearchBookActivity, BookDetailedActivity.class);
intent.putExtra(APPCONST.SEARCH_BOOK_BEAN, new ArrayList<>(mBooks.getValues(mBooksBean.get(i))));
mSearchBookActivity.startActivity(intent);
});
//搜索按钮点击事件
mSearchBookActivity.getTvSearchConform().setOnClickListener(view -> mHandler.sendMessage(mHandler.obtainMessage(1)));
//suggestion搜索事件
mSearchBookActivity.getTgSuggestBook().setOnTagClickListener(tag -> {
mSearchBookActivity.getEtSearchKey().setText(tag);
mSearchBookActivity.getEtSearchKey().setSelection(tag.length());
mHandler.sendMessage(mHandler.obtainMessage(1));
});
//历史记录搜索事件
mSearchBookActivity.getLvHistoryList().setOnItemClickListener((parent, view, position, id) -> {
mSearchBookActivity.getEtSearchKey().setText(mSearchHistories.get(position).getContent());
mSearchBookActivity.getEtSearchKey().setSelection(mSearchHistories.get(position).getContent().length());
mHandler.sendMessage(mHandler.obtainMessage(1));
});
//清空历史记录
mSearchBookActivity.getLlClearHistory().setOnClickListener(v -> {
mSearchHistoryService.clearHistory();
initHistoryList();
});
//清除单个历史记录
mSearchBookActivity.getLvHistoryList().setOnItemLongClickListener((parent, view, position, id) -> {
if (mSearchHistories.get(position) != null) {
mSearchHistoryService.deleteHistory(mSearchHistories.get(position));
initHistoryList();
}
return true;
});
//上拉刷新
mSearchBookActivity.getSrlSearchBookList().setOnRefreshListener(refreshLayout -> mHandler.sendMessage(mHandler.obtainMessage(1)));
mSearchBookActivity.getSrlSearchBookList().setEnableRefresh(false);
mSearchBookActivity.getGvSearchBooksList().setNumColumns(1);
mSearchBookActivity.getGvSearchBooksList().setDragModel(-1);
initSuggestionBook();
initHistoryList();
}
/**
* 初始化建议书目
*/
private void initSuggestionBook() {
mSearchBookActivity.getTgSuggestBook().setTags(suggestion);
}
private class RenewSuggestionBook implements View.OnClickListener {
@Override
public void onClick(View v) {
String[] s = mSearchBookActivity.getTgSuggestBook().getTags();
if (Arrays.equals(s, suggestion)) {
mSearchBookActivity.getTgSuggestBook().setTags(suggestion2);
} else {
mSearchBookActivity.getTgSuggestBook().setTags(suggestion);
}
}
}
/**
* 初始化历史列表
*/
private void initHistoryList() {
mSearchHistories = mSearchHistoryService.findAllSearchHistory();
if (mSearchHistories == null || mSearchHistories.size() == 0) {
mSearchBookActivity.getLlHistoryView().setVisibility(View.GONE);
} else {
mSearchHistoryAdapter = new SearchHistoryAdapter(mSearchBookActivity, R.layout.listview_search_history_item, mSearchHistories);
mSearchBookActivity.getLvHistoryList().setAdapter(mSearchHistoryAdapter);
mSearchBookActivity.getLlHistoryView().setVisibility(View.VISIBLE);
}
}
/**
* 初始化搜索列表
*/
private void initSearchList() {
initmBooksBean();
mSearchBookAdapter = new SearchBookAdapter(mSearchBookActivity,
R.layout.listview_search_book_item, mBooksBean, mBooks);
mSearchBookActivity.getGvSearchBooksList().setAdapter(mSearchBookAdapter);
mSearchBookActivity.getGvSearchBooksList().setVisibility(View.VISIBLE);
mSearchBookActivity.getLlSuggestBooksView().setVisibility(View.GONE);
mSearchBookActivity.getLlHistoryView().setVisibility(View.GONE);
}
/**
* 更新搜索列表
*/
private void notifyDataSetChanged() {
if (curThreadCount == 0) {
mSearchBookActivity.getPbLoading().setVisibility(View.GONE);
}
initmBooksBean();
}
/**
* 初始化mBooksBean
*/
private void initmBooksBean() {
synchronized (this) {
mBooksBean.clear();
mBooksBean.addAll(mBooks.keySet());
//排序,基于最符合关键字的搜书结果应该是最短的
//TODO ;这里只做了简单的比较排序,还需要继续完善
Collections.sort(mBooksBean, (o1, o2) -> {
if (searchKey.equals(o1.getName()))
return -1;
if (searchKey.equals(o2.getName()))
return 1;
if (searchKey.equals(o1.getAuthor()))
return -1;
if (searchKey.equals(o2.getAuthor()))
return 1;
if (o1.getName().length() < o2.getName().length())
return -1;
if (o1.getName().length() == o2.getName().length())
return 0;
return 1;
});
/*MyApplication.runOnUiThread(new Runnable() {
@Override
public void run() {
mSearchBookAdapter.notifyDataSetChanged();
}
});*/
}
}
/**
* 获取搜索数据
*/
private void getData() {
mBooksBean.clear();
mBooks.clear();
allThreadCount = 4;
curThreadCount = allThreadCount;
searchBookByCrawler(new BiQuGe44ReadCrawler(), "");
searchBookByCrawler(new TianLaiReadCrawler(), "");
searchBookByCrawler(new BiQuGeReadCrawler(), "gbk");
searchBookByCrawler(new PinShuReadCrawler(), "gbk");
}
/**
* 搜索
*/
private void search() {
mSearchBookActivity.getPbLoading().setVisibility(View.VISIBLE);
if (StringHelper.isEmpty(searchKey)) {
mSearchBookActivity.getPbLoading().setVisibility(View.GONE);
mSearchBookActivity.getGvSearchBooksList().setVisibility(View.GONE);
mSearchBookActivity.getLlSuggestBooksView().setVisibility(View.VISIBLE);
initHistoryList();
mSearchBookActivity.getGvSearchBooksList().setAdapter(null);
mSearchBookActivity.getSrlSearchBookList().setEnableRefresh(false);
} else {
mSearchBookActivity.getGvSearchBooksList().setVisibility(View.VISIBLE);
mSearchBookActivity.getLlSuggestBooksView().setVisibility(View.GONE);
mSearchBookActivity.getLlHistoryView().setVisibility(View.GONE);
getData();
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (mSearchBookActivity.getGvSearchBooksList().getmScrollView().getScrollY() == 0){
mSearchBookActivity.getSrlSearchBookList().setEnableRefresh(true);
}
//滑动监听器
mSearchBookActivity.getGvSearchBooksList().getmScrollView().setOnScrollChangeListener((v, scrollX, scrollY, oldScrollX, oldScrollY) -> {
mSearchBookActivity.getSrlSearchBookList().setEnableRefresh(scrollY == 0);
});
}
mSearchHistoryService.addOrUpadteHistory(searchKey);
//收起软键盘
InputMethodManager imm = (InputMethodManager) MyApplication.getmContext().getSystemService(Context.INPUT_METHOD_SERVICE);
assert imm != null;
imm.hideSoftInputFromWindow(mSearchBookActivity.getEtSearchKey().getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
}
}
public boolean onBackPressed() {
if (StringHelper.isEmpty(searchKey)) {
return false;
} else {
mSearchBookActivity.getEtSearchKey().setText("");
return true;
}
}
private void searchBookByCrawler(ReadCrawler rc, String charset) {
String searchKey = this.searchKey;
if (charset.toLowerCase().equals("gbk")) {
try {
searchKey = URLEncoder.encode(this.searchKey, charset);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
CommonApi.search(searchKey, rc, new ResultCallback() {
@Override
public void onFinish(Object o, int code) {
ConcurrentMultiValueMap<SearchBookBean, Book> sbb =
(ConcurrentMultiValueMap<SearchBookBean, Book>) o;
mBooks.addAll(sbb);
curThreadCount--;
mHandler.sendMessage(mHandler.obtainMessage(2));
}
@Override
public void onError(Exception e) {
curThreadCount--;
mHandler.sendMessage(mHandler.obtainMessage(2));
}
});
}
}

@ -5,6 +5,7 @@ import android.util.Base64;
import android.util.Log;
import com.google.gson.Gson;
import okhttp3.*;
import xyz.fycz.myreader.application.MyApplication;
import xyz.fycz.myreader.application.TrustAllCerts;
import xyz.fycz.myreader.callback.HttpCallback;
@ -21,32 +22,18 @@ import java.net.URLConnection;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Map;
import java.util.*;
import java.util.concurrent.TimeUnit;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
import static java.lang.String.valueOf;
public class HttpUtil {
private static String sessionid;
@ -70,14 +57,9 @@ public class HttpUtil {
private static synchronized OkHttpClient getOkHttpClient() {
if (mClient == null) {
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.connectTimeout(30000, TimeUnit.SECONDS);
builder.connectTimeout(30, TimeUnit.SECONDS).readTimeout(30, TimeUnit.SECONDS);
builder.sslSocketFactory(createSSLSocketFactory());
builder.hostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
builder.hostnameVerifier((hostname, session) -> true);
mClient = builder
.build();
}
@ -85,14 +67,17 @@ public class HttpUtil {
}
/**
* 图片发送
*
* @param address
* @param callback
*/
public static void sendBitmapGetRequest(final String address, final HttpCallback callback) {
new Thread(new Runnable() {
HttpURLConnection connection = null;
@Override
public void run() {
try {
@ -131,12 +116,14 @@ public class HttpUtil {
/**
* get请求
*
* @param address
* @param callback
*/
public static void sendGetRequest(final String address, final HttpCallback callback) {
new Thread(new Runnable() {
HttpURLConnection connection = null;
@Override
public void run() {
try {
@ -175,6 +162,7 @@ public class HttpUtil {
/**
* 网络通信测试请求
*
* @param address
* @param callback
*/
@ -253,11 +241,44 @@ public class HttpUtil {
}*/
try {
OkHttpClient client = getOkHttpClient();
Request request = new Request.Builder()
.addHeader("User-Agent","Mozilla/4.0 (compatible; MSIE 7.0; Windows 7)")
.url(address)
.build();
Response response = client.newCall(request).execute();
/*HashMap<String, List<Cookie>> cookieStore = new HashMap<>();
OkHttpClient client = new OkHttpClient.Builder()
.cookieJar(new CookieJar() {
@Override
public void saveFromResponse(HttpUrl httpUrl, List<Cookie> list) {
StringBuilder sb = new StringBuilder();
for (Cookie cookie : list){
sb.append(cookie.name()).append("=").append(cookie.value()).append("; ");
}
if (list.size() > 0){
sb.deleteCharAt(sb.lastIndexOf("; "));
}
Log.i("CookieStr", sb.toString());
cookieStore.put(httpUrl.host(), list);
}
@Override
public List<Cookie> loadForRequest(HttpUrl httpUrl) {
List<Cookie> cookies = cookieStore.get(httpUrl.host());
return cookies != null ? cookies : new ArrayList<>();
}
})
.build();*/
Request.Builder requestBuilder = new Request.Builder()
.addHeader("accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9")
.addHeader("accept-language", "zh-CN,zh;q=0.9")
.addHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4168.3 Safari/537.36");
if (address.contains("qidian.com")) {
SharedPreUtils spu = SharedPreUtils.getInstance();
String cookie = spu.getString("qdCookie", "");
if (cookie.equals("")) {
requestBuilder.addHeader("cookie", "_csrfToken=eXRDlZxmRDLvFAmdgzqvwWAASrxxp2WkVlH4ZM7e; newstatisticUUID=1595991935_2026387981");
}else {
requestBuilder.addHeader("cookie", cookie);
}
}
requestBuilder.url(address);
Response response = client.newCall(requestBuilder.build()).execute();
callback.onFinish(response.body().byteStream());
} catch (Exception e) {
e.printStackTrace();
@ -268,6 +289,7 @@ public class HttpUtil {
/**
* post请求
*
* @param address
* @param output
* @param callback
@ -315,6 +337,7 @@ public class HttpUtil {
/**
* post请求 获取蓝奏云直链
*
* @param address
* @param output
* @param callback
@ -360,6 +383,7 @@ public class HttpUtil {
public static void sendPostRequest_okHttp(final String address, final String output, final HttpCallback callback) {
new Thread(new Runnable() {
HttpURLConnection connection = null;
@Override
public void run() {
try {
@ -387,6 +411,7 @@ public class HttpUtil {
/**
* 多文件上传请求
*
* @param url
* @param files
* @param params
@ -443,6 +468,7 @@ public class HttpUtil {
/**
* 生成URL
*
* @param p_url
* @param params
* @return
@ -484,6 +510,7 @@ public class HttpUtil {
/**
* 生成URL不加密
*
* @param p_url
* @param params
* @return
@ -513,6 +540,7 @@ public class HttpUtil {
/**
* 生成post输出参数串
*
* @param params
* @return
*/
@ -570,6 +598,7 @@ public class HttpUtil {
/**
* 测试URL可连接性
*
* @param url
* @param connectionCallback
*/
@ -734,7 +763,6 @@ public class HttpUtil {
}
/**
* Trust every server - dont check for any certificate
*/
@ -767,6 +795,4 @@ public class HttpUtil {
}
}

@ -17,6 +17,7 @@ import xyz.fycz.myreader.R;
import xyz.fycz.myreader.application.MyApplication;
import xyz.fycz.myreader.common.APPCONST;
import xyz.fycz.myreader.creator.DialogCreator;
import xyz.fycz.myreader.creator.MyAlertDialog;
import xyz.fycz.myreader.greendao.service.BookMarkService;
import java.lang.reflect.Field;
@ -144,7 +145,7 @@ public class NotificationUtil {
public void requestNotificationPermissionDialog(Context context){
if (!isNotificationEnabled(context)) {
new AlertDialog.Builder(context)
MyAlertDialog.build(context)
.setTitle("开启通知")
.setMessage("检测到未开启通知权限,无法在通知栏查看缓存进度,是否前往开启?")
.setCancelable(true)

@ -0,0 +1,61 @@
package xyz.fycz.myreader.util.utils;
import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Bitmap;
import android.os.Build;
import android.renderscript.Allocation;
import android.renderscript.Element;
import android.renderscript.RenderScript;
import android.renderscript.ScriptIntrinsicBlur;
import androidx.annotation.NonNull;
import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool;
import com.bumptech.glide.load.resource.bitmap.BitmapTransformation;
import java.security.MessageDigest;
public class BlurTransformation extends BitmapTransformation {
private RenderScript rs;
private int radius;
public BlurTransformation(Context context, int radius) {
super();
rs = RenderScript.create(context);
this.radius = radius;
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
@Override
protected Bitmap transform(@NonNull BitmapPool pool, @NonNull Bitmap toTransform, int outWidth, int outHeight) {
Bitmap blurredBitmap = toTransform.copy(Bitmap.Config.ARGB_8888, true);
// Allocate memory for Renderscript to work with
//分配用于渲染脚本的内存
Allocation input = Allocation.createFromBitmap(rs, blurredBitmap, Allocation.MipmapControl.MIPMAP_FULL, Allocation.USAGE_SHARED);
Allocation output = Allocation.createTyped(rs, input.getType());
// Load up an instance of the specific script that we want to use.
//加载我们想要使用的特定脚本的实例。
ScriptIntrinsicBlur script = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));
script.setInput(input);
// Set the blur radius
//设置模糊半径
script.setRadius(radius);
// Start the ScriptIntrinsicBlur
//启动 ScriptIntrinsicBlur,
script.forEach(output);
// Copy the output to the blurred bitmap
//将输出复制到模糊的位图
output.copyTo(blurredBitmap);
return blurredBitmap;
}
@Override
public void updateDiskCacheKey(@NonNull MessageDigest messageDigest) {
messageDigest.update("blur transformation".getBytes());
}
}

@ -0,0 +1,80 @@
package xyz.fycz.myreader.util.utils;
import android.graphics.Color;
import androidx.annotation.ColorInt;
import androidx.annotation.FloatRange;
@SuppressWarnings({"unused", "WeakerAccess"})
public class ColorUtil {
public static String intToString(int intColor) {
return String.format("#%06X", 0xFFFFFF & intColor);
}
public static int stripAlpha(@ColorInt int color) {
return 0xff000000 | color;
}
@ColorInt
public static int shiftColor(@ColorInt int color, @FloatRange(from = 0.0f, to = 2.0f) float by) {
if (by == 1f) return color;
int alpha = Color.alpha(color);
float[] hsv = new float[3];
Color.colorToHSV(color, hsv);
hsv[2] *= by; // value component
return (alpha << 24) + (0x00ffffff & Color.HSVToColor(hsv));
}
@ColorInt
public static int darkenColor(@ColorInt int color) {
return shiftColor(color, 0.9f);
}
@ColorInt
public static int lightenColor(@ColorInt int color) {
return shiftColor(color, 1.1f);
}
public static boolean isColorLight(@ColorInt int color) {
final double darkness = 1 - (0.299 * Color.red(color) + 0.587 * Color.green(color) + 0.114 * Color.blue(color)) / 255;
return darkness < 0.4;
}
@ColorInt
public static int invertColor(@ColorInt int color) {
final int r = 255 - Color.red(color);
final int g = 255 - Color.green(color);
final int b = 255 - Color.blue(color);
return Color.argb(Color.alpha(color), r, g, b);
}
@ColorInt
public static int adjustAlpha(@ColorInt int color, @FloatRange(from = 0.0, to = 1.0) float factor) {
int alpha = Math.round(Color.alpha(color) * factor);
int red = Color.red(color);
int green = Color.green(color);
int blue = Color.blue(color);
return Color.argb(alpha, red, green, blue);
}
@ColorInt
public static int withAlpha(@ColorInt int baseColor, @FloatRange(from = 0.0, to = 1.0) float alpha) {
int a = Math.min(255, Math.max(0, (int) (alpha * 255))) << 24;
int rgb = 0x00ffffff & baseColor;
return a + rgb;
}
/**
* Taken from CollapsingToolbarLayout's CollapsingTextHelper class.
*/
public static int blendColors(int color1, int color2, @FloatRange(from = 0.0, to = 1.0) float ratio) {
final float inverseRatio = 1f - ratio;
float a = (Color.alpha(color1) * inverseRatio) + (Color.alpha(color2) * ratio);
float r = (Color.red(color1) * inverseRatio) + (Color.red(color2) * ratio);
float g = (Color.green(color1) * inverseRatio) + (Color.green(color2) * ratio);
float b = (Color.blue(color1) * inverseRatio) + (Color.blue(color2) * ratio);
return Color.argb((int) a, (int) r, (int) g, (int) b);
}
}

@ -85,7 +85,7 @@ public class FileUtils {
public static String getFileSize(long size) {
if (size <= 0) return "0";
final String[] units = new String[]{"b", "kb", "M", "G", "T"};
final String[] units = new String[]{"b", "KB", "MB", "G", "T"};
//计算单位的,原理是利用lg,公式是 lg(1024^n) = nlg(1024),最后 nlg(1024)/lg(1024) = n。
int digitGroups = (int) (Math.log10(size) / Math.log10(1024));
//计算原理是,size/单位值。单位值指的是:比如说b = 1024,KB = 1024^2

@ -3,6 +3,8 @@ package xyz.fycz.myreader.webapi;
import xyz.fycz.myreader.callback.ResultCallback;
import xyz.fycz.myreader.webapi.crawler.BiQuGeReadCrawler;
import xyz.fycz.myreader.webapi.crawler.FindCrawler;
import xyz.fycz.myreader.webapi.crawler.QB5ReadCrawler;
/**
* Created by zhao on 2017/7/24.
@ -13,15 +15,15 @@ public class BookStoreApi extends BaseApi{
/**
* 获取书城小说分类列表
* @param url
* @param findCrawler
* @param callback
*/
public static void getBookTypeList(String url, final ResultCallback callback){
public static void getBookTypeList(FindCrawler findCrawler, final ResultCallback callback){
getCommonReturnHtmlStringApi(url, null, "GBK", new ResultCallback() {
getCommonReturnHtmlStringApi(findCrawler.getFindUrl(), null, findCrawler.getCharset(), new ResultCallback() {
@Override
public void onFinish(Object o, int code) {
callback.onFinish(BiQuGeReadCrawler.getBookTypeList((String) o),0);
callback.onFinish(findCrawler.getBookTypeList((String) o),0);
}
@Override
@ -35,15 +37,15 @@ public class BookStoreApi extends BaseApi{
/**
* 获取某一分类小说排行榜列表
* @param url
* @param findCrawler
* @param callback
*/
public static void getBookRankList(String url, final ResultCallback callback){
public static void getBookRankList(String url, FindCrawler findCrawler, final ResultCallback callback){
getCommonReturnHtmlStringApi(url, null, "GBK", new ResultCallback() {
getCommonReturnHtmlStringApi(url, null, findCrawler.getCharset(), new ResultCallback() {
@Override
public void onFinish(Object o, int code) {
callback.onFinish(BiQuGeReadCrawler.getBookRankList((String) o),0);
callback.onFinish(findCrawler.getRankBookList((String) o),0);
}
@Override

@ -85,6 +85,8 @@ public class CommonApi extends BaseApi {
params.put(rc.getSearchKey(), key);
if (rc instanceof PinShuReadCrawler) {
params.put("SearchClass", 1);
}else if (rc instanceof QB5ReadCrawler){
params.put("submit", "%CB%D1%CB%F7");
}
getCommonReturnHtmlStringApi(rc.getSearchLink(), params, charset, new ResultCallback() {
@Override

@ -20,6 +20,7 @@ public class BiQuGe44ReadCrawler implements ReadCrawler, BookInfoCrawler{
public static final String NOVEL_SEARCH = "https://www.wqge.cc/modules/article/search.php";
public static final String SEARCH_KEY = "searchkey";
public static final String CHARSET = "GBK";
public static final String SEARCH_CHARSET = "utf-8";
@Override
public String getSearchLink() {
return NOVEL_SEARCH;
@ -40,6 +41,11 @@ public class BiQuGe44ReadCrawler implements ReadCrawler, BookInfoCrawler{
return SEARCH_KEY;
}
@Override
public String getSearchCharset() {
return SEARCH_CHARSET;
}
/**
* 从html中获取章节正文
* @param html

@ -24,6 +24,8 @@ public class BiQuGeReadCrawler implements ReadCrawler, BookInfoCrawler {
private static final String NOVEL_SEARCH = "https://www.52bqg.net/modules/article/search.php";
private static final String SEARCH_KEY = "searchkey";
private static final String CHARSET = "GBK";
public static final String SEARCH_CHARSET = "GBK";
private ReadCrawler rc = new TianLaiReadCrawler();
@Override
@ -46,6 +48,11 @@ public class BiQuGeReadCrawler implements ReadCrawler, BookInfoCrawler {
return CHARSET;
}
@Override
public String getSearchCharset() {
return SEARCH_CHARSET;
}
/**
* 获取书城小说分类列表
*
@ -108,6 +115,34 @@ public class BiQuGeReadCrawler implements ReadCrawler, BookInfoCrawler {
}
public static List<Book> getLatestBookList(String html) {
List<Book> books = new ArrayList<>();
Document doc = Jsoup.parse(html);
Element div = doc.getElementById("newscontent");
Elements uls = div.getElementsByTag("ul");
if (uls.size() > 0) {
for (Element li : uls.get(0).children()) {
Book book = new Book();
Element scanS1 = li.getElementsByClass("s1").get(0);
Element scanS2 = li.getElementsByClass("s2").get(0);
Element scanS3 = li.getElementsByClass("s3").get(0);
Element scanS4 = li.getElementsByClass("s4").get(0);
Element scanS5 = li.getElementsByClass("s5").get(0);
book.setType(scanS1.text().replace("[", "").replace("]", ""));
Element a = scanS2.getElementsByTag("a").get(0);
book.setName(a.attr("title"));
book.setChapterUrl(a.attr("href"));
book.setNewestChapterTitle(scanS3.text());
book.setAuthor(scanS4.text());
book.setUpdateDate(scanS5.text());
book.setSource(BookSource.biquge.toString());
books.add(book);
}
}
return books;
}
@Override
public String getContentFormHtml(String html) {

@ -26,6 +26,7 @@ public class FYReadCrawler implements ReadCrawler{
public static final String NOVEL_SEARCH = "https://novel.fycz.xyz/search.html";
public static final String SEARCH_KEY = "keyword";
public static final String CHARSET = "utf-8";
public static final String SEARCH_CHARSET = "utf-8";
@Override
public String getSearchLink() {
return NOVEL_SEARCH;
@ -45,6 +46,11 @@ public class FYReadCrawler implements ReadCrawler{
return SEARCH_KEY;
}
@Override
public String getSearchCharset() {
return SEARCH_CHARSET;
}
/**
* 从html中获取章节正文
*

@ -0,0 +1,23 @@
package xyz.fycz.myreader.webapi.crawler;
import xyz.fycz.myreader.entity.bookstore.BookType;
import xyz.fycz.myreader.greendao.entity.Book;
import java.io.Serializable;
import java.util.List;
/**
* @author fengyue
* @date 2020/9/14 18:36
*/
public abstract class FindCrawler implements Serializable {
private static final long serialVersionUID = 1L;
public abstract String getCharset();
public abstract String getFindName();
public abstract String getFindUrl();
public abstract boolean getTypePage(BookType curType, int page);
public abstract boolean hasImg();
public abstract List<BookType> getBookTypeList(String html);
public abstract List<Book> getRankBookList(String html);
}

@ -23,6 +23,7 @@ public class PinShuReadCrawler implements ReadCrawler, BookInfoCrawler {
public static final String NOVEL_SEARCH = "https://www.vodtw.com/Book/Search.aspx";
public static final String SEARCH_KEY = "SearchKey";
public static final String CHARSET = "gbk";
public static final String SEARCH_CHARSET = "gbk";
@Override
public String getSearchLink() {
@ -43,7 +44,10 @@ public class PinShuReadCrawler implements ReadCrawler, BookInfoCrawler {
public String getSearchKey() {
return SEARCH_KEY;
}
@Override
public String getSearchCharset() {
return SEARCH_CHARSET;
}
/**
* 从html中获取章节正文
*

@ -23,6 +23,7 @@ public class PinShuReadCrawler2 implements ReadCrawler, BookInfoCrawler {
public static final String NOVEL_SEARCH = "https://www.vodtw.la/search.html";
public static final String SEARCH_KEY = "q";
public static final String CHARSET = "UTF-8";
public static final String SEARCH_CHARSET = "UTF-8";
@Override
public String getSearchLink() {
@ -44,6 +45,11 @@ public class PinShuReadCrawler2 implements ReadCrawler, BookInfoCrawler {
return SEARCH_KEY;
}
@Override
public String getSearchCharset() {
return SEARCH_CHARSET;
}
/**
* 从html中获取章节正文
*

@ -0,0 +1,287 @@
package xyz.fycz.myreader.webapi.crawler;
import android.text.Html;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import xyz.fycz.myreader.entity.SearchBookBean;
import xyz.fycz.myreader.entity.bookstore.BookType;
import xyz.fycz.myreader.enums.BookSource;
import xyz.fycz.myreader.greendao.entity.Book;
import xyz.fycz.myreader.greendao.entity.Chapter;
import xyz.fycz.myreader.mulvalmap.ConcurrentMultiValueMap;
import xyz.fycz.myreader.util.StringHelper;
import java.util.ArrayList;
import java.util.List;
public class QB5ReadCrawler extends FindCrawler implements ReadCrawler, BookInfoCrawler {
private static final String NAME_SPACE = "https://www.qb5.tw";
private static final String NOVEL_SEARCH = "https://www.qb5.tw/modules/article/search.php";
public static final String FIND_URL = "https://www.qb5.tw";
public static final String FIND_NAME = "书城[全本小说]";
private static final String SEARCH_KEY = "searchkey";
private static final String CHARSET = "GBK";
public static final String SEARCH_CHARSET = "GBK";
@Override
public String getSearchLink() {
return NOVEL_SEARCH;
}
@Override
public String getNameSpace() {
return NAME_SPACE;
}
@Override
public String getSearchKey() {
return SEARCH_KEY;
}
@Override
public String getCharset() {
return CHARSET;
}
@Override
public String getFindName() {
return FIND_NAME;
}
@Override
public String getFindUrl() {
return FIND_URL;
}
@Override
public String getSearchCharset() {
return SEARCH_CHARSET;
}
@Override
public boolean hasImg() {
return false;
}
/**
* 获取书城小说分类列表
*
* @param html
* @return
*/
public List<BookType> getBookTypeList(String html) {
List<BookType> bookTypes = new ArrayList<>();
Document doc = Jsoup.parse(html);
Elements divs = doc.getElementsByClass("nav_cont");
if (divs.size() > 0) {
Elements uls = divs.get(0).getElementsByTag("ul");
if (uls.size() > 0) {
for (Element li : uls.get(0).children()) {
Element a = li.child(0);
BookType bookType = new BookType();
bookType.setTypeName(a.attr("title"));
bookType.setUrl(a.attr("href"));
if (bookType.getTypeName().contains("首页") || bookType.getTypeName().contains("热门小说")) continue;
if (!StringHelper.isEmpty(bookType.getTypeName())) {
bookTypes.add(bookType);
}
}
}
}
return bookTypes;
}
/**
* 获取某一分类小说排行榜列表
*
* @param html
* @return
*/
public List<Book> getBookRankList(String html) {
List<Book> books = new ArrayList<>();
Document doc = Jsoup.parse(html);
Elements divs = doc.getElementsByClass("r");
if (divs.size() > 0) {
Elements uls = divs.get(0).getElementsByTag("ul");
if (uls.size() > 0) {
for (Element li : uls.get(0).children()) {
Book book = new Book();
Element scanS1 = li.getElementsByClass("s1").get(0);
Element scanS2 = li.getElementsByClass("s2").get(0);
Element scanS5 = li.getElementsByClass("s5").get(0);
book.setType(scanS1.html().replace("[", "").replace("]", ""));
Element a = scanS2.getElementsByTag("a").get(0);
book.setName(a.attr("title"));
book.setChapterUrl(a.attr("href"));
book.setAuthor(scanS5.html());
book.setSource(BookSource.biquge.toString());
books.add(book);
}
}
}
return books;
}
public List<Book> getRankBookList(String html) {
List<Book> books = new ArrayList<>();
Document doc = Jsoup.parse(html);
String type = doc.select("meta[name=keywords]").attr("content").replace(",全本小说网", "");
Element div = doc.getElementById("tlist");
Elements uls = div.getElementsByTag("ul");
if (uls.size() > 0) {
for (Element li : uls.get(0).children()) {
Book book = new Book();
Element aName = li.getElementsByClass("name").get(0);
Element divZz = li.getElementsByClass("zz").get(0);
Element divAuthor = li.getElementsByClass("author").get(0);
Element divSj = li.getElementsByClass("sj").get(0);
book.setType(type);
book.setName(aName.attr("title"));
book.setChapterUrl(aName.attr("href"));
book.setNewestChapterTitle(divZz.text());
book.setAuthor(divAuthor.text());
book.setUpdateDate(divSj.text());
book.setSource(BookSource.qb5.toString());
books.add(book);
}
}
return books;
}
@Override
public String getContentFormHtml(String html) {
Document doc = Jsoup.parse(html);
Element divBook = doc.getElementsByClass("nav-style").get(0);
String bookName = divBook.getElementsByTag("a").get(1).attr("title");
Element divContent = doc.getElementById("content");
if (divContent != null) {
String content = Html.fromHtml(divContent.html()).toString();
char c = 160;
String spaec = "" + c;
content = content.replace(spaec, " ");
content = content.replace("全本小说网 www.qb5.tw,最快更新", "")
.replace(bookName, "")
.replace("最新章节!", "");
return content;
} else {
return "";
}
}
@Override
public ArrayList<Chapter> getChaptersFromHtml(String html) {
ArrayList<Chapter> chapters = new ArrayList<>();
Document doc = Jsoup.parse(html);
String readUrl = doc.select("meta[property=og:novel:read_url]").attr("content");
int num = 0;
Element zjbox = doc.getElementsByClass("zjbox").get(0);
Elements as = zjbox.getElementsByTag("a");
for (int i = 12; i < as.size(); i++) {
Element a = as.get(i);
Chapter chapter = new Chapter();
chapter.setNumber(num++);
chapter.setTitle(a.text());
chapter.setUrl(readUrl + a.attr("href"));
chapters.add(chapter);
}
return chapters;
}
/**
* 从搜索html中得到书列表
*
* @param html
* @return
*/
public ConcurrentMultiValueMap<SearchBookBean, Book> getBooksFromSearchHtml(String html) {
final ConcurrentMultiValueMap<SearchBookBean, Book> books = new ConcurrentMultiValueMap<>();
Document doc = Jsoup.parse(html);
String urlType = doc.select("meta[property=og:type]").attr("content");
if ("novel".equals(urlType)) {
String readUrl = doc.select("meta[property=og:novel:read_url]").attr("content");
Book book = new Book();
book.setChapterUrl(readUrl);
getBookInfo(html, book);
SearchBookBean sbb = new SearchBookBean(book.getName(), book.getAuthor());
books.add(sbb, book);
} else {
Elements divs = doc.getElementsByClass("grid");
Element div = divs.get(0);
Elements elementsByTag = div.getElementsByTag("tr");
for (int i = 1; i < elementsByTag.size(); i++) {
Element element = elementsByTag.get(i);
Book book = new Book();
Elements info = element.getElementsByTag("td");
book.setName(info.get(0).text());
book.setChapterUrl(info.get(0).getElementsByTag("a").attr("href"));
book.setNewestChapterTitle(info.get(1).text());
book.setAuthor(info.get(2).text());
book.setSource(BookSource.qb5.toString());
SearchBookBean sbb = new SearchBookBean(book.getName(), book.getAuthor());
books.add(sbb, book);
}
}
return books;
}
/**
* 获取小说详细信息
*
* @param html
* @return
*/
public Book getBookInfo(String html, Book book) {
//小说源
book.setSource(BookSource.qb5.toString());
Document doc = Jsoup.parse(html);
//书名
String name = doc.select("meta[property=og:title]").attr("content");
book.setName(name);
//作者
String author = doc.select("meta[property=og:novel:author]").attr("content");
book.setAuthor(author);
//最新章节
String newestChapter = doc.select("meta[property=og:novel:latest_chapter_name]").attr("content");
book.setNewestChapterTitle(newestChapter);
//更新时间
String updateTime = doc.select("meta[property=og:novel:update_time]").attr("content");
book.setUpdateDate(updateTime);
//图片url
Element divImg = doc.getElementsByClass("img_in").get(0);
Element img = divImg.getElementsByTag("img").get(0);
book.setImgUrl(img.attr("src"));
//简介
Element divIntro = doc.getElementById("intro");
book.setDesc(divIntro.text());
//类型
String type = doc.select("meta[property=og:novel:category]").attr("content");
book.setType(type);
return book;
}
public boolean getTypePage(BookType curType, int page){
if (page > 10){
return true;
}
if (!curType.getTypeName().equals("完本小说")) {
curType.setUrl(curType.getUrl().substring(0, curType.getUrl().lastIndexOf("_") + 1) + page + "/");
}else {
if (page > 1){
return true;
}
}
return false;
}
}

@ -1,75 +0,0 @@
package xyz.fycz.myreader.webapi.crawler;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import xyz.fycz.myreader.entity.bookstore.BookType;
import xyz.fycz.myreader.greendao.entity.Book;
import java.util.ArrayList;
import java.util.List;
/**
* @author fengyue
* @date 2020/5/27 11:17
*/
public class QiDianRankList {
public static final String[] TYPE_NAME = {
"月票榜", "畅销榜", "阅读榜", "推荐榜", "收藏榜"
};
/**
* 获取书城小说分类列表
*
* @param html
* @return
*/
public static List<BookType> getBookTypeList(String html) {
List<BookType> bookTypes = new ArrayList<>();
Document doc = Jsoup.parse(html);
Elements divs = doc.getElementsByClass("more");
for (int i = 0; i < 5; i++) {
BookType bookType = new BookType();
bookType.setTypeName(TYPE_NAME[i]);
bookType.setUrl("https:" + divs.get(i).attr("href"));
bookTypes.add(bookType);
}
return bookTypes;
}
/**
* 获取某一分类小说排行榜列表
*
* @param html
* @return
*/
public static List<Book> getBookRankList(String html) {
List<Book> books = new ArrayList<>();
Document doc = Jsoup.parse(html);
Elements lis = doc.getElementsByTag("li");
if (lis.size() > 0) {
Elements bookLis = lis.select("data-rid");
if (bookLis.size() > 0) {
for (Element li : bookLis) {
Book book = new Book();
String imgSrc = li.getElementsByClass("book-img-box").get(0)
.getElementsByTag("img").attr("src");
book.setImgUrl("https:" + imgSrc);
Element bookInfo = li.getElementsByClass("book-mid-info").get(0);
Elements tagA = bookInfo.getElementsByTag("a");
book.setName(tagA.get(0).text());
book.setAuthor(tagA.get(1).text());
book.setType(tagA.get(2).text());
book.setNewestChapterTitle(tagA.get(3).text());
String desc = bookInfo.getElementsByClass("intro").get(0).text();
book.setDesc(desc);
books.add(book);
}
}
}
return books;
}
}

@ -15,6 +15,7 @@ import java.util.ArrayList;
public interface ReadCrawler {
String getSearchLink();
String getCharset();
String getSearchCharset();
String getNameSpace();
String getSearchKey();
String getContentFormHtml(String html);

@ -1,6 +1,12 @@
package xyz.fycz.myreader.webapi.crawler;
import xyz.fycz.myreader.enums.BookSource;
import xyz.fycz.myreader.util.SharedPreUtils;
import xyz.fycz.myreader.util.StringHelper;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.ResourceBundle;
/**
@ -10,8 +16,65 @@ import java.util.ResourceBundle;
public class ReadCrawlerUtil {
private ReadCrawlerUtil() {
}
public static ArrayList<ReadCrawler> getReadCrawlers() {
SharedPreUtils spu = SharedPreUtils.getInstance();
String searchSource = spu.getString("searchSource", null);
ArrayList<ReadCrawler> readCrawlers = new ArrayList<>();
if (searchSource == null) {
StringBuilder sb = new StringBuilder();
for (BookSource bookSource : BookSource.values()) {
if (bookSource.equals(BookSource.fynovel) || bookSource.equals(BookSource.local) || bookSource.equals(BookSource.biquge))
continue;
sb.append(bookSource.toString());
sb.append(",");
readCrawlers.add(getReadCrawler(bookSource.toString()));
}
sb.deleteCharAt(sb.lastIndexOf(","));
searchSource = sb.toString();
spu.putString("searchSource", searchSource);
} else if (!"".equals(searchSource)){
String[] sources = searchSource.split(",");
for (String source : sources) {
readCrawlers.add(getReadCrawler(source));
}
}
return readCrawlers;
}
public static HashMap<CharSequence, Boolean> getDisableSources() {
SharedPreUtils spu = SharedPreUtils.getInstance();
String searchSource = spu.getString("searchSource", null);
HashMap<CharSequence, Boolean> mSources = new HashMap<>();
if (searchSource == null) {
for (BookSource bookSource : BookSource.values()) {
if (bookSource.equals(BookSource.fynovel) || bookSource.equals(BookSource.local)) continue;
if (bookSource.equals(BookSource.biquge)) {
mSources.put(bookSource.text, true);
continue;
}
mSources.put(bookSource.text, false);
}
} else {
String[] ableSources = searchSource.split(",");
bookSourceFor:
for (BookSource bookSource : BookSource.values()) {
if (bookSource.equals(BookSource.fynovel) || bookSource.equals(BookSource.local)) continue;
for (String ableSource : ableSources) {
if (ableSource.equals(bookSource.toString())) {
mSources.put(bookSource.text, false);
continue bookSourceFor;
}
}
mSources.put(bookSource.text, true);
}
}
return mSources;
}
public static ReadCrawler getReadCrawler(String bookSource) {
ResourceBundle rb = ResourceBundle.getBundle("bookcrawler");
ResourceBundle rb = ResourceBundle.getBundle("crawler");
try {
String readCrawlerPath = rb.getString(bookSource);
Class clz = Class.forName(readCrawlerPath);

@ -25,6 +25,8 @@ public class TianLaiReadCrawler implements ReadCrawler{
public static final String NOVEL_SEARCH = "https://www.23txt.com/search.php";
public static final String SEARCH_KEY = "q";
public static final String CHARSET = "GBK";
public static final String SEARCH_CHARSET = "utf-8";
@Override
public String getSearchLink() {
return NOVEL_SEARCH;
@ -44,6 +46,11 @@ public class TianLaiReadCrawler implements ReadCrawler{
return SEARCH_KEY;
}
@Override
public String getSearchCharset() {
return SEARCH_CHARSET;
}
/**
* 从html中获取章节正文
*

@ -0,0 +1,117 @@
package xyz.fycz.myreader.webapi.crawler.find;
import android.content.Context;
import android.graphics.Bitmap;
import android.util.Log;
import android.webkit.*;
import okhttp3.*;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import xyz.fycz.myreader.application.MyApplication;
import xyz.fycz.myreader.callback.ResultCallback;
import xyz.fycz.myreader.creator.DialogCreator;
import xyz.fycz.myreader.entity.bookstore.BookType;
import xyz.fycz.myreader.entity.bookstore.QDBook;
import xyz.fycz.myreader.entity.bookstore.RankBook;
import xyz.fycz.myreader.entity.bookstore.SortBook;
import xyz.fycz.myreader.greendao.entity.Book;
import xyz.fycz.myreader.util.IOUtils;
import xyz.fycz.myreader.util.SharedPreUtils;
import xyz.fycz.myreader.util.StringHelper;
import xyz.fycz.myreader.webapi.CommonApi;
import xyz.fycz.myreader.webapi.crawler.FindCrawler;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.text.SimpleDateFormat;
import java.util.*;
/**
* @author fengyue
* @date 2020/9/16 22:01
*/
public class ABC extends FindCrawler {
private String rankUrl = "";
private String sortUrl = "";
private String[] sex = {"male", "female"};
private String aParam = "";
private String imgUrl = "";
private String defaultCookie = "";
private String yearmonthFormat = "";
private LinkedHashMap<String, String> rankName = new LinkedHashMap<>();
private LinkedHashMap<String, Integer> sortName = new LinkedHashMap<>();
private boolean isFemale;
private boolean isSort;
public ABC(boolean isFemale) {
this.isFemale = isFemale;
}
public ABC(boolean isFemale, boolean isSort) {
this.isFemale = isFemale;
this.isSort = isSort;
}
private void initMaleRankName() {
}
private void initSortNames() {
}
public List<BookType> getRankTypes() {
return null;
}
public void getRankBooks(BookType bookType, ResultCallback rc) {
}
private List<QDBook> getBooksFromJson(String json) {
return null;
}
@Override
public String getCharset() {
return null;
}
@Override
public String getFindName() {
return null;
}
@Override
public String getFindUrl() {
return null;
}
@Override
public boolean getTypePage(BookType curType, int page) {
return false;
}
@Override
public boolean hasImg() {
return true;
}
@Override
public List<BookType> getBookTypeList(String html) {
return null;
}
@Override
public List<Book> getRankBookList(String html) {
return null;
}
public void initCookie(Context mContext, ResultCallback rc) {
}
}

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<alpha
android:duration="1000"
android:fromAlpha="0"
android:interpolator="@android:anim/decelerate_interpolator"
android:toAlpha="1.0"/>
</set>

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<alpha
android:duration="1500"
android:fromAlpha="1.0"
android:interpolator="@android:anim/decelerate_interpolator"
android:toAlpha="0"/>
</set>

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@color/colorAccent" android:state_checked="true" />
<item android:color="@color/textSecondary" android:state_checked="false"/>
</selector>

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@color/gray" android:state_enabled="false" />
<item android:color="@color/white" android:state_pressed="true" />
<item android:color="@color/textSecondary" android:state_enabled="false" />
<item android:color="@color/textAssist" android:state_pressed="true" />
<item android:color="@color/colorAccent"/>
</selector>

@ -1,7 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="oval">
<solid android:color="@color/textSecondary"/>
</shape>
</item>
<item android:bottom="1dp" android:left="1dp" android:right="1dp" android:top="1dp">
<shape android:shape="oval">
<solid android:color="@color/sys_blue_deep_bg"/>

@ -1,6 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="oval">
<solid android:color="@color/textSecondary"/>
</shape>
</item>
<item android:bottom="1dp" android:left="1dp" android:right="1dp" android:top="1dp">
<shape android:shape="oval">

@ -1,9 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="oval">
<solid android:color="@color/textSecondary"/>
</shape>
</item>
<item android:bottom="1dp" android:left="1dp" android:right="1dp" android:top="1dp">
<shape android:shape="oval">
<solid android:color="@color/sys_common_bg"/>
<solid android:color="@color/textPrimaryInverted"/>
</shape>
</item>
</layer-list>

@ -7,7 +7,7 @@
</item>
<item android:bottom="1dp" android:left="1dp" android:right="1dp" android:top="1dp">
<shape android:shape="oval">
<solid android:color="@color/sys_common_bg"/>
<solid android:color="@color/textPrimaryInverted"/>
</shape>
</item>
</layer-list>

@ -1,6 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="oval">
<solid android:color="@color/textSecondary"/>
</shape>
</item>
<item android:bottom="1dp" android:left="1dp" android:right="1dp" android:top="1dp">
<shape android:shape="oval">
<solid android:color="#e6dbbf"/>

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

Loading…
Cancel
Save