新增设置界面

pull/5/head
fengyuecanzhu 5 years ago
parent a216411b09
commit 31c16a6004
  1. BIN
      .idea/caches/build_file_checksums.ser
  2. 11
      app/build.gradle
  3. 32
      app/src/main/AndroidManifest.xml
  4. 8
      app/src/main/assets/updatelog.fy
  5. 17
      app/src/main/java/xyz/fycz/myreader/application/MyApplication.java
  6. 18
      app/src/main/java/xyz/fycz/myreader/application/SysManager.java
  7. 10
      app/src/main/java/xyz/fycz/myreader/backup/BackupAndRestore.java
  8. 40
      app/src/main/java/xyz/fycz/myreader/base/BaseActivity.java
  9. 66
      app/src/main/java/xyz/fycz/myreader/base/BaseActivity2.java
  10. 16
      app/src/main/java/xyz/fycz/myreader/common/APPCONST.java
  11. 111
      app/src/main/java/xyz/fycz/myreader/creator/APPDownloadTip.java
  12. 99
      app/src/main/java/xyz/fycz/myreader/creator/DialogCreator.java
  13. 74
      app/src/main/java/xyz/fycz/myreader/creator/MultiChoiceDialog.java
  14. 74
      app/src/main/java/xyz/fycz/myreader/entity/Setting.java
  15. 44
      app/src/main/java/xyz/fycz/myreader/greendao/entity/Book.java
  16. 26
      app/src/main/java/xyz/fycz/myreader/greendao/entity/Chapter.java
  17. 2
      app/src/main/java/xyz/fycz/myreader/greendao/service/BookMarkService.java
  18. 248
      app/src/main/java/xyz/fycz/myreader/greendao/service/BookService.java
  19. 36
      app/src/main/java/xyz/fycz/myreader/greendao/service/ChapterService.java
  20. 164
      app/src/main/java/xyz/fycz/myreader/greendao/util/GreenDaoUpgrade.java
  21. 18
      app/src/main/java/xyz/fycz/myreader/greendao/util/MySQLiteOpenHelper.java
  22. 2
      app/src/main/java/xyz/fycz/myreader/ui/activity/AboutActivity.java
  23. 164
      app/src/main/java/xyz/fycz/myreader/ui/activity/BookDetailedActivity.java
  24. 2
      app/src/main/java/xyz/fycz/myreader/ui/activity/CatalogActivity.java
  25. 11
      app/src/main/java/xyz/fycz/myreader/ui/activity/FileSystemActivity.java
  26. 2
      app/src/main/java/xyz/fycz/myreader/ui/activity/FontsActivity.java
  27. 2
      app/src/main/java/xyz/fycz/myreader/ui/activity/LoginActivity.java
  28. 8
      app/src/main/java/xyz/fycz/myreader/ui/activity/MainActivity.java
  29. 411
      app/src/main/java/xyz/fycz/myreader/ui/activity/MoreSettingActivity.java
  30. 10
      app/src/main/java/xyz/fycz/myreader/ui/activity/ReadActivity.java
  31. 2
      app/src/main/java/xyz/fycz/myreader/ui/activity/RegisterActivity.java
  32. 2
      app/src/main/java/xyz/fycz/myreader/ui/activity/SearchBookActivity.java
  33. 5
      app/src/main/java/xyz/fycz/myreader/ui/activity/SplashActivity.java
  34. 8
      app/src/main/java/xyz/fycz/myreader/ui/adapter/BookMarkAdapter.java
  35. 11
      app/src/main/java/xyz/fycz/myreader/ui/adapter/BookStoreBookTypeAdapter.java
  36. 9
      app/src/main/java/xyz/fycz/myreader/ui/adapter/BookcaseAdapter.java
  37. 10
      app/src/main/java/xyz/fycz/myreader/ui/adapter/BookcaseDetailedAdapter.java
  38. 164
      app/src/main/java/xyz/fycz/myreader/ui/adapter/BookcaseDragAdapter.java
  39. 6
      app/src/main/java/xyz/fycz/myreader/ui/adapter/ChapterTitleAdapter.java
  40. 150
      app/src/main/java/xyz/fycz/myreader/ui/adapter/FontsAdapter.java
  41. 18
      app/src/main/java/xyz/fycz/myreader/ui/adapter/SearchBookAdapter.java
  42. 6
      app/src/main/java/xyz/fycz/myreader/ui/presenter/AboutPresenter.java
  43. 6
      app/src/main/java/xyz/fycz/myreader/ui/presenter/BookStorePresenter.java
  44. 142
      app/src/main/java/xyz/fycz/myreader/ui/presenter/BookcasePresenter.java
  45. 4
      app/src/main/java/xyz/fycz/myreader/ui/presenter/CatalogActivityPresenter.java
  46. 11
      app/src/main/java/xyz/fycz/myreader/ui/presenter/CatalogPresenter.java
  47. 8
      app/src/main/java/xyz/fycz/myreader/ui/presenter/FontsPresenter.java
  48. 10
      app/src/main/java/xyz/fycz/myreader/ui/presenter/LoginPresenter.java
  49. 10
      app/src/main/java/xyz/fycz/myreader/ui/presenter/MainPresenter.java
  50. 83
      app/src/main/java/xyz/fycz/myreader/ui/presenter/ReadPresenter.java
  51. 8
      app/src/main/java/xyz/fycz/myreader/ui/presenter/RegisterPresenter.java
  52. 187
      app/src/main/java/xyz/fycz/myreader/util/BadgeUtil.java
  53. 8
      app/src/main/java/xyz/fycz/myreader/util/CacheFileNameHelper.java
  54. 31
      app/src/main/java/xyz/fycz/myreader/util/ChschtUtil.java
  55. 6
      app/src/main/java/xyz/fycz/myreader/util/DownloadMangerUtils.java
  56. 150
      app/src/main/java/xyz/fycz/myreader/util/GreenDaoUpgrade.java
  57. 121
      app/src/main/java/xyz/fycz/myreader/util/OSUtils.java
  58. 2
      app/src/main/java/xyz/fycz/myreader/util/OpenFileHelper.java
  59. 20
      app/src/main/java/xyz/fycz/myreader/util/PermissionHelper.java
  60. 71
      app/src/main/java/xyz/fycz/myreader/util/StatusBarCompat.java
  61. 208
      app/src/main/java/xyz/fycz/myreader/util/StatusBarUtil.java
  62. 2
      app/src/main/java/xyz/fycz/myreader/util/TelephonyUtil.java
  63. 21
      app/src/main/java/xyz/fycz/myreader/util/TextHelper.java
  64. 65
      app/src/main/java/xyz/fycz/myreader/util/ToastUtils.java
  65. 151
      app/src/main/java/xyz/fycz/myreader/util/utils/StringUtils.java
  66. 4
      app/src/main/java/xyz/fycz/myreader/webapi/BaseApi.java
  67. 4
      app/src/main/java/xyz/fycz/myreader/webapi/crawler/BiQuGeReadCrawler.java
  68. 2
      app/src/main/java/xyz/fycz/myreader/webapi/crawler/TianLaiReadCrawler.java
  69. 147
      app/src/main/java/xyz/fycz/myreader/widget/ProgressButton.java
  70. 81
      app/src/main/java/xyz/fycz/myreader/widget/page/PageLoader.java
  71. 2
      app/src/main/res/drawable/ic_bookmark.xml
  72. 9
      app/src/main/res/drawable/ic_change_source.xml
  73. 7
      app/src/main/res/drawable/ic_cry_face.xml
  74. 9
      app/src/main/res/drawable/ic_enable.xml
  75. 4
      app/src/main/res/drawable/ic_error.xml
  76. 4
      app/src/main/res/drawable/ic_link.xml
  77. 9
      app/src/main/res/drawable/ic_question.xml
  78. 9
      app/src/main/res/drawable/ic_refresh.xml
  79. 14
      app/src/main/res/drawable/ic_settings.xml
  80. 9
      app/src/main/res/drawable/ic_smile_face.xml
  81. 9
      app/src/main/res/drawable/ic_social_github.xml
  82. 4
      app/src/main/res/drawable/ic_success.xml
  83. 334
      app/src/main/res/layout/activity_more_setting.xml
  84. 51
      app/src/main/res/layout/activity_read_more_setting.xml
  85. 17
      app/src/main/res/layout/dialog_read_setting.xml
  86. 9
      app/src/main/res/layout/dialog_read_setting_detail.xml
  87. 2
      app/src/main/res/layout/layout_about_content.xml
  88. 45
      app/src/main/res/layout/layout_book_detail_header.xml
  89. 31
      app/src/main/res/layout/listview_font_item.xml
  90. 13
      app/src/main/res/layout/toolbar.xml
  91. 7
      app/src/main/res/menu/menu_book.xml
  92. 33
      app/src/main/res/menu/menu_book_detail.xml
  93. BIN
      app/src/main/res/mipmap-xhdpi/ic_refresh.png
  94. 29
      app/src/main/res/values/attrs.xml
  95. 14
      app/src/main/res/values/colors.xml
  96. 66
      app/src/main/res/values/strings.xml
  97. 4
      app/src/main/res/values/styles.xml
  98. 4
      app/version_code.properties

@ -94,7 +94,8 @@ dependencies {
implementation 'com.journeyapps:zxing-android-embedded:3.5.0'
implementation 'org.greenrobot:greendao:3.2.2'
implementation 'org.greenrobot:greendao:3.3.0'
implementation 'com.github.yuweiguocn:GreenDaoUpgradeHelper:v2.2.1'
implementation 'org.jsoup:jsoup:1.11.3'
@ -117,10 +118,16 @@ dependencies {
implementation 'com.h6ah4i.android.widget.verticalseekbar:verticalseekbar:1.0.0'
//Scroller
implementation 'com.futuremind.recyclerfastscroll:fastscroll:0.2.5'
//Toasty
implementation 'com.github.GrenderG:Toasty:1.5.0'
//
implementation 'net.ricecode:string-similarity:1.0.0'
}
greendao {
schemaVersion 9
schemaVersion 11
daoPackage 'xyz.fycz.myreader.greendao.gen'
// targetGenDir 'src/main/java'
}

@ -4,9 +4,11 @@
<!-- ********************************permission************************************ -->
<!-- 控制振动 -->
<uses-permission android:name="android.permission.VIBRATE"/> <!-- 读取手机状态和身份 -->
<uses-permission android:name="android.permission.VIBRATE"/>
<!-- 读取手机状态和身份 -->
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="com.example.broadcast.permission"/> <!-- 拍摄照片和视频 -->
<uses-permission android:name="com.example.broadcast.permission"/>
<!-- 拍摄照片和视频 -->
<!-- <uses-permission android:name="android.permission.CAMERA" /> -->
<!-- 访问闪光灯 -->
<!-- <uses-permission android:name="android.permission.FLASHLIGHT" /> -->
@ -24,20 +26,28 @@
<!-- 添加或修改日历活动,并在所有者不知情的情况下向邀请对象发送电子邮件 -->
<!-- <uses-permission android:name="android.permission.WRITE_CALENDAR" /> -->
<!-- 拥有完全的网络访问权限 -->
<uses-permission android:name="android.permission.INTERNET"/> <!-- 查看网络连接 -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/> <!-- 查看WLAN连接 -->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/> <!-- 修改或删除您的USB存储设备中的内容 -->
<uses-permission android:name="android.permission.INTERNET"/>
<!-- 查看网络连接 -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<!-- 查看WLAN连接 -->
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<!-- 修改或删除您的USB存储设备中的内容 -->
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEM"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <!-- 读取您的USB存储设备中的内容 -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <!-- 拨打电话 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<!-- 读取您的USB存储设备中的内容 -->
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<!-- 拨打电话 -->
<!-- <uses-permission android:name="android.permission.CALL_PHONE" /> -->
<!-- 开机启动 -->
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<uses-permission android:name="android.Manifest.permission.INTERNAL_SYSTEM_WINDOW"/> <!-- 停用屏幕锁定 -->
<uses-permission android:name="android.permission.DISABLE_KEYGUARD"/> <!-- 防止手机休眠 -->
<uses-permission android:name="android.permission.WAKE_LOCK"/> <!-- 检索正在运行的应用 -->
<uses-permission android:name="android.Manifest.permission.INTERNAL_SYSTEM_WINDOW"/>
<!-- 停用屏幕锁定 -->
<uses-permission android:name="android.permission.DISABLE_KEYGUARD"/>
<!-- 防止手机休眠 -->
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<!-- 检索正在运行的应用 -->
<!-- <uses-permission android:name="android.permission.GET_TASKS" /> -->
<!-- 连接WLAN网络和断开连接 -->
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
@ -104,6 +114,8 @@
<activity android:name=".ui.activity.FileSystemActivity"/>
<activity android:name=".ui.activity.MoreSettingActivity"/>
<receiver android:name=".util.notification.NotificationClickReceiver"/>
<receiver android:name=".ui.presenter.BookcasePresenter$cancelDownloadReceiver"/>
<receiver android:name=".ui.presenter.ReadPresenter$cancelDownloadReceiver"/>

@ -1,3 +1,11 @@
2020.08.24
风月读书v1.20.082422
1、重做书籍详情界面
2、新增书籍启用\关闭更新(此功能在书籍详情页右上角菜单)
3、优化应用提示信息显示效果
4、优化字体界面
5、修复已知bug
2020.08.15
风月读书v1.20.081523
1、修复安卓10(Q)无法访问外部储存空间及其导致的一系列问题(如:无法下载字体、无法使用备份\恢复、无法添加本地书籍、无法同步书架等)

@ -256,7 +256,7 @@ public class MyApplication extends Application {
doc = Jsoup.connect(url).get();
String content = doc.getElementsByClass("ql-editor").text();
if (StringHelper.isEmpty(content)) {
TextHelper.showText("检查更新失败!");
ToastUtils.showError("检查更新失败!");
return;
}
String[] contents = content.split(";");
@ -292,11 +292,11 @@ public class MyApplication extends Application {
mBookcaseFragment);
}
} else if (isManualCheck) {
TextHelper.showText("已经是最新版本!");
ToastUtils.showSuccess("已经是最新版本!");
}
} catch (Exception e) {
e.printStackTrace();
TextHelper.showText("无网络连接!");
ToastUtils.showError("检查更新失败!");
}
});
}
@ -329,7 +329,7 @@ public class MyApplication extends Application {
}
}, (dialog, which) -> {
if (url == null || "".equals(url)) {
TextHelper.showText("获取链接失败,请前往浏览器下载!");
ToastUtils.showError("获取链接失败,请前往浏览器下载!");
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
intent.setData(Uri.parse(URLCONST.APP_DIR_UR));
@ -372,4 +372,13 @@ public class MyApplication extends Application {
}
}
/**
* 判断Activity是否Destroy
* @param mActivity
* @return
*/
public static boolean isDestroy(Activity mActivity) {
return mActivity == null || mActivity.isFinishing() || mActivity.isDestroyed();
}
}

@ -48,21 +48,24 @@ public class SysManager {
private static Setting getDefaultSetting(){
Setting setting = new Setting();
setting.setDayStyle(true);
setting.setReadBgColor(R.color.sys_protect_eye_bg);
setting.setReadStyle(ReadStyle.protectedEye);
setting.setReadStyle(ReadStyle.leather);
setting.setReadWordSize(25);
setting.setReadWordColor(R.color.sys_protect_eye_word);
setting.setBrightProgress(50);
setting.setBrightFollowSystem(true);
setting.setLanguage(Language.simplified);
setting.setFont(Font.默认字体);
setting.setAutoScrollSpeed(300);
setting.setPageMode(PageMode.SIMULATION);
setting.setVolumeTurnPage(false);
setting.setVolumeTurnPage(true);
setting.setResetScreen(3);
setting.setBookcaseStyle(BookcaseStyle.listMode);
setting.setNewestVersionCode(getVersionCode());
setting.setLocalFontName("");
setting.setAutoSyn(false);
setting.setMatchChapter(true);
setting.setMatchChapterSuitability(0.7f);
setting.setCatheGap(150);
setting.setRefreshWhenStart(false);
setting.setSettingVersion(APPCONST.SETTING_VERSION);
return setting;
}
@ -73,6 +76,11 @@ public class SysManager {
*/
public static void resetSetting(){
saveSetting(getDefaultSetting());
Setting setting = getSetting();
setting.setVolumeTurnPage(true);
setting.setMatchChapter(true);
setting.setResetScreen(3);
setting.setSettingVersion(APPCONST.SETTING_VERSION);
saveSetting(setting);
}
}

@ -81,17 +81,25 @@ public class BackupAndRestore {
sBookFields[i] = sBookFields[i].substring(sBookFields[i].indexOf("'") + 1, sBookFields[i].lastIndexOf("'"));
}
String source = "null";
boolean isCloseUpdate = false;
boolean isDownloadAll = true;
if(!sBookFields[2].contains("novel.fycz.xyz")){
source = sBookFields[17];
}
if ("本地书籍".equals(sBookFields[4])){
sBookFields[15] = "0";
}
if (sBookFields.length >= 19){
isCloseUpdate = Boolean.parseBoolean(sBookFields[18]);
}
if (sBookFields.length >= 20){
isDownloadAll = Boolean.parseBoolean(sBookFields[19]);
}
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);
, source, isCloseUpdate, isDownloadAll);
books.add(book);
}
mBookService.deleteAllBooks();

@ -14,7 +14,7 @@ import android.view.inputmethod.InputMethodManager;
import androidx.appcompat.app.AppCompatActivity;
import xyz.fycz.myreader.ActivityManage;
import xyz.fycz.myreader.util.Anti_hijackingUtils;
import xyz.fycz.myreader.util.SystemBarTintManager;
import xyz.fycz.myreader.util.StatusBarUtil;
@ -41,7 +41,7 @@ public class BaseActivity extends AppCompatActivity {
Log.d("ActivityName: ",getLocalClassName());
DisplayMetrics dm = new DisplayMetrics();
//获取屏幕宽高
if(height == 0 || height == 0){
if(height == 0 || width == 0){
getWindowManager().getDefaultDisplay().getMetrics(dm);
width = dm.widthPixels;
height = dm.heightPixels;
@ -90,18 +90,6 @@ public class BaseActivity extends AppCompatActivity {
return super.onKeyDown(keyCode, event);
}
@TargetApi(19)
protected void setTranslucentStatus(boolean on) {
Window win = getWindow();
WindowManager.LayoutParams winParams = win.getAttributes();
final int bits = WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
if (on) {
winParams.flags |= bits;
} else {
winParams.flags &= ~bits;
}
win.setAttributes(winParams);
}
public void setDisallowAntiHijacking(boolean disallowAntiHijacking) {
this.disallowAntiHijacking = disallowAntiHijacking;
@ -113,13 +101,25 @@ public class BaseActivity extends AppCompatActivity {
* 设置状态栏颜色
* @param colorId
*/
public void setStatusBar(int colorId){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
setTranslucentStatus(true);
SystemBarTintManager tintManager = new SystemBarTintManager(this);
tintManager.setStatusBarTintEnabled(true);
tintManager.setStatusBarTintResource(colorId);//通知栏所需颜色ID
public void setStatusBar(int colorId, boolean dark){
//沉浸式代码配置
//当FitsSystemWindows设置 true 时,会在屏幕最上方预留出状态栏高度的 padding
StatusBarUtil.setRootViewFitsSystemWindows(this, true);
//设置状态栏透明
StatusBarUtil.setTranslucentStatus(this);
if (colorId != 0) {
StatusBarUtil.setStatusBarColor(this, getResources().getColor(colorId));
}
//一般的手机的状态栏文字和图标都是白色的, 可如果你的应用也是纯白色的, 或导致状态栏文字看不清
//所以如果你是这种情况,请使用以下代码, 设置状态使用深色文字图标风格, 否则你可以选择性注释掉这个if内容
if (!dark) {
if (!StatusBarUtil.setStatusBarDarkTheme(this, true)) {
//如果不支持设置深色风格 为了兼容总不能让状态栏白白的看不清, 于是设置一个状态栏颜色为半透明,
//这样半透明+白=灰, 状态栏的文字能看得清
StatusBarUtil.setStatusBarColor(this, 0x55000000);
}
}
}
public InputMethodManager getmInputMethodManager() {

@ -1,21 +1,29 @@
package xyz.fycz.myreader.base;
import android.annotation.SuppressLint;
import android.content.Intent;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import androidx.annotation.LayoutRes;
import androidx.annotation.Nullable;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.core.content.ContextCompat;
import butterknife.ButterKnife;
import butterknife.Unbinder;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.disposables.Disposable;
import xyz.fycz.myreader.ActivityManage;
import xyz.fycz.myreader.R;
import xyz.fycz.myreader.util.StatusBarCompat;
import xyz.fycz.myreader.util.StatusBarUtil;
import java.lang.reflect.Method;
import java.util.ArrayList;
/**
* @author fengyue
@ -73,6 +81,7 @@ public abstract class BaseActivity2 extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityManage.addActivity(this);
setContentView(getContentId());
initData(savedInstanceState);
unbinder = ButterKnife.bind(this);
@ -95,6 +104,7 @@ public abstract class BaseActivity2 extends AppCompatActivity {
@Override
protected void onDestroy() {
super.onDestroy();
ActivityManage.removeActivity(this);
unbinder.unbind();
if (mDisposable != null){
mDisposable.dispose();
@ -104,7 +114,7 @@ public abstract class BaseActivity2 extends AppCompatActivity {
/**************************used method area*******************************************/
protected void startActivity(Class<? extends AppCompatActivity> activity){
Intent intent = new Intent(this,activity);
Intent intent = new Intent(this, activity);
startActivity(intent);
}
@ -121,7 +131,53 @@ public abstract class BaseActivity2 extends AppCompatActivity {
return actionBar;
}
protected void setStatusBarColor(int statusColor){
StatusBarCompat.compat(this, ContextCompat.getColor(this, statusColor));
protected void setStatusBarColor(int statusColor, boolean dark){
//沉浸式代码配置
//当FitsSystemWindows设置 true 时,会在屏幕最上方预留出状态栏高度的 padding
StatusBarUtil.setRootViewFitsSystemWindows(this, true);
//设置状态栏透明
StatusBarUtil.setTranslucentStatus(this);
StatusBarUtil.setStatusBarColor(this, getResources().getColor(statusColor));
//一般的手机的状态栏文字和图标都是白色的, 可如果你的应用也是纯白色的, 或导致状态栏文字看不清
//所以如果你是这种情况,请使用以下代码, 设置状态使用深色文字图标风格, 否则你可以选择性注释掉这个if内容
if (!dark) {
if (!StatusBarUtil.setStatusBarDarkTheme(this, true)) {
//如果不支持设置深色风格 为了兼容总不能让状态栏白白的看不清, 于是设置一个状态栏颜色为半透明,
//这样半透明+白=灰, 状态栏的文字能看得清
StatusBarUtil.setStatusBarColor(this, 0x55000000);
}
}
}
@SuppressLint("PrivateApi")
@SuppressWarnings("unchecked")
@Override
public boolean onMenuOpened(int featureId, Menu menu) {
if (menu != null) {
//展开菜单显示图标
if (menu.getClass().getSimpleName().equalsIgnoreCase("MenuBuilder")) {
try {
Method method = menu.getClass().getDeclaredMethod("setOptionalIconsVisible", Boolean.TYPE);
method.setAccessible(true);
method.invoke(menu, true);
method = menu.getClass().getDeclaredMethod("getNonActionItems");
ArrayList<MenuItem> menuItems = (ArrayList<MenuItem>) method.invoke(menu);
if (!menuItems.isEmpty()) {
for (MenuItem menuItem : menuItems) {
Drawable drawable = menuItem.getIcon();
if (drawable != null) {
drawable.mutate();
drawable.setColorFilter(getResources().getColor(R.color.black), PorterDuff.Mode.SRC_ATOP);
}
}
}
} catch (Exception ignored) {
}
}
}
return super.onMenuOpened(featureId, menu);
}
}

@ -10,10 +10,10 @@ import java.io.File;
public class APPCONST {
public static String publicKey = "";//服务端公钥
public static String publicKey = "fyds1.0";//服务端公钥
public static String privateKey;//app私钥
public final static String s = "11940364935628058505";
public static final String KEY = "";
public static final String KEY = "readerByFengyue";
public static final String ALARM_SCHEDULE_MSG = "alarm_schedule_msg";
@ -37,13 +37,17 @@ public class APPCONST {
public static final String SETTING = "setting";
public static final String SEARCH_BOOK_BEAN = "SearchBookBean";
public static final String FONT = "font";
public static final String RESULT_RESET_SCREEN = "result_reset_screen";
public static final String RESULT_IS_COLLECTED = "result_is_collected";
public static final String RESULT_LAST_READ_POSITION = "result_last_read_position";
public static final String RESULT_HISTORY_CHAPTER = "result_history_chapter";
public static final int[] READ_STYLE_NIGHT = {R.color.sys_night_word, R.color.sys_night_bg};//黑夜
public static final int[] READ_STYLE_PROTECTED_EYE = {R.color.sys_protect_eye_word, R.color.sys_protect_eye_bg};//护眼
public static final int[] READ_STYLE_COMMON = {R.color.sys_common_word, R.color.sys_common_bg};//普通
public static final int[] READ_STYLE_BLUE_DEEP = {R.color.sys_blue_deep_word, R.color.sys_blue_deep_bg};//深蓝
public static final int[] READ_STYLE_LEATHER = {R.color.sys_leather_word, R.mipmap.theme_leather_bg};//羊皮纸
public static final int[] READ_STYLE_LEATHER = {R.color.sys_leather_word, R.color.sys_leather_bg};//羊皮纸
public static final int[] READ_STYLE_BREEN_EYE = {R.color.sys_breen_word, R.color.sys_breen_bg};//棕绿色
@ -52,9 +56,9 @@ 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 String RESULT_IS_COLLECTED = "result_is_collected";
public static final String RESULT_LAST_READ_POSITION = "result_last_read_position";
public static final int REQUEST_READ = 1;
public static final CharSequence[] DIALOG_DOWNLOAD = {
@ -69,7 +73,7 @@ public class APPCONST {
public static final int PERMISSIONS_REQUEST_STORAGE = 10001;
//设置版本号
public static final int SETTING_VERSION = 1;
public static final int SETTING_VERSION = 3;
public static final String FORMAT_FILE_DATE = "yyyy-MM-dd";

@ -15,7 +15,7 @@ import xyz.fycz.myreader.common.APPCONST;
import xyz.fycz.myreader.ui.activity.MainActivity;
import xyz.fycz.myreader.ui.fragment.BookcaseFragment;
import xyz.fycz.myreader.util.IOUtils;
import xyz.fycz.myreader.util.TextHelper;
import xyz.fycz.myreader.util.ToastUtils;
import xyz.fycz.myreader.util.utils.FileUtils;
import xyz.fycz.myreader.webapi.CommonApi;
@ -80,69 +80,62 @@ public class APPDownloadTip {
error();
return;
}
MyApplication.getApplication().newThread(new Runnable() {
@SuppressLint("SetTextI18n")
@Override
public void run() {
HttpURLConnection con = null;
InputStream is = null;
FileOutputStream fos = null;
File appFile = null;
try {
URL webUrl = new URL(downloadUrl);
mHandler.sendMessage(mHandler.obtainMessage(2));
con = (HttpURLConnection) webUrl.openConnection();
is = con.getInputStream();
String filePath = APPCONST.UPDATE_APK_FILE_DIR + "FYReader.apk.temp";
appFile = FileUtils.getFile(filePath);
fos = new FileOutputStream(appFile);
byte[] tem = new byte[1024];
long alreadyLen = 0;
long fileLength = con.getContentLength();
int len;
double progress;
while ((len = is.read(tem)) != -1) {
fos.write(tem, 0, len);
alreadyLen += len;
progress = alreadyLen * 1.0f * 100f / fileLength;
mHandler.sendMessage(mHandler.obtainMessage(3, progress));
}
fos.flush();
if (fileLength == appFile.length()) {
String newPath = filePath.replace(".temp", "");
final File newFile = new File(newPath);
if (appFile.renameTo(newFile)){
mHandler.sendMessage(mHandler.obtainMessage(4));
DialogCreator.createCommonDialog(activity, "提示", "风月读书下载完成,安装包路径:" + newPath,
!isForceUpdate, "取消", "立即安装", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if (isForceUpdate){
activity.finish();
}
}
}, (dialog, which) -> activity.installProcess(newFile, isForceUpdate));
activity.installProcess(newFile, isForceUpdate);
}else {
appFile.delete();
error();
}
MyApplication.getApplication().newThread(() -> {
HttpURLConnection con = null;
InputStream is = null;
FileOutputStream fos = null;
File appFile = null;
try {
URL webUrl = new URL(downloadUrl);
mHandler.sendMessage(mHandler.obtainMessage(2));
con = (HttpURLConnection) webUrl.openConnection();
is = con.getInputStream();
String filePath = APPCONST.UPDATE_APK_FILE_DIR + "FYReader.apk.temp";
appFile = FileUtils.getFile(filePath);
fos = new FileOutputStream(appFile);
byte[] tem = new byte[1024];
long alreadyLen = 0;
long fileLength = con.getContentLength();
int len;
double progress;
while ((len = is.read(tem)) != -1) {
fos.write(tem, 0, len);
alreadyLen += len;
progress = alreadyLen * 1.0f * 100f / fileLength;
mHandler.sendMessage(mHandler.obtainMessage(3, progress));
}
fos.flush();
if (fileLength == appFile.length()) {
String newPath = filePath.replace(".temp", "");
final File newFile = new File(newPath);
if (appFile.renameTo(newFile)){
mHandler.sendMessage(mHandler.obtainMessage(4));
DialogCreator.createCommonDialog(activity, "提示", "风月读书下载完成,安装包路径:" + newPath,
!isForceUpdate, "取消", "立即安装", (dialog, which) -> {
if (isForceUpdate){
activity.finish();
}
}, (dialog, which) -> activity.installProcess(newFile, isForceUpdate));
activity.installProcess(newFile, isForceUpdate);
}else {
appFile.delete();
error();
}
} catch (IOException e) {
if (appFile != null) {
appFile.delete();
}
}else {
appFile.delete();
error();
e.printStackTrace();
} finally {
if (con != null) {
con.disconnect();
}
IOUtils.close(is, fos);
}
} catch (IOException e) {
if (appFile != null) {
appFile.delete();
}
error();
e.printStackTrace();
} finally {
if (con != null) {
con.disconnect();
}
IOUtils.close(is, fos);
}
});
}
@ -157,7 +150,7 @@ public class APPDownloadTip {
private void error(){
mHandler.sendMessage(mHandler.obtainMessage(1));
TextHelper.showText("获取下载链接失败,请前往浏览器下载!");
ToastUtils.showError("获取下载链接失败,请前往浏览器下载!");
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
intent.setData(Uri.parse(url));

@ -13,10 +13,7 @@ import android.view.MotionEvent;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.*;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
@ -30,6 +27,7 @@ import xyz.fycz.myreader.enums.BookSource;
import xyz.fycz.myreader.enums.ReadStyle;
import xyz.fycz.myreader.greendao.entity.Book;
import xyz.fycz.myreader.greendao.entity.Chapter;
import xyz.fycz.myreader.greendao.service.BookService;
import xyz.fycz.myreader.util.BrightUtil;
import xyz.fycz.myreader.util.IOUtils;
import xyz.fycz.myreader.util.StringHelper;
@ -69,7 +67,8 @@ public class DialogCreator {
final View.OnClickListener languageChangeListener,
final View.OnClickListener onFontClickListener,
final OnPageModeChangeListener onModeClickListener,
View.OnClickListener autoScrollListener) {
View.OnClickListener autoScrollListener,
View.OnClickListener moreSettingListener) {
final Dialog dialog = new Dialog(context, R.style.jmui_default_dialog_style);
final View view = LayoutInflater.from(context).inflate(R.layout.dialog_read_setting_detail, null);
dialog.setContentView(view);
@ -300,6 +299,8 @@ public class DialogCreator {
});
tvAutoScroll.setOnClickListener(autoScrollListener);
view.findViewById(R.id.tv_read_setting_more).setOnClickListener(moreSettingListener);
return dialog;
}
@ -329,6 +330,7 @@ public class DialogCreator {
*/
public static Dialog createReadSetting(final Context context, final boolean isDayStyle, int chapterProgress, int maxProcess, final Book mBook, Chapter mChapter,
View.OnClickListener backListener,
View.OnClickListener changeSourceListener,
View.OnClickListener refreshListener,
View.OnClickListener bookMarkListener,
final OnSkipChapterListener lastChapterListener,
@ -342,9 +344,11 @@ public class DialogCreator {
final Dialog dialog = new Dialog(context, R.style.jmui_default_dialog_style);
final View view = LayoutInflater.from(context).inflate(R.layout.dialog_read_setting, null);
dialog.setContentView(view);
LinearLayout llBack = (LinearLayout) view.findViewById(R.id.ll_title_back);
LinearLayout llBook = view.findViewById(R.id.ll_book_name);
TextView tvBookName = view.findViewById(R.id.tv_book_name_top);
ImageView ivChangeSource = view.findViewById(R.id.iv_change_source);
ImageView ivRefresh = view.findViewById(R.id.iv_refresh);
ImageView ivBookMark = view.findViewById(R.id.iv_book_mark);
ImageView ivMore = view.findViewById(R.id.iv_more);
@ -384,6 +388,9 @@ public class DialogCreator {
intent.putExtra(APPCONST.BOOK, mBook);
context.startActivity(intent);*/
});
//换源
ivChangeSource.setOnClickListener(changeSourceListener);
//刷新
ivRefresh.setOnClickListener(refreshListener);
String url = mChapter.getUrl();
@ -399,16 +406,13 @@ public class DialogCreator {
tvChapterTitle.setText(mChapter.getTitle());
tvChapterUrl.setText(StringHelper.isEmpty(url) ? mChapter.getId() : url);
//跳转对应章节
llChapter.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String url = tvChapterUrl.getText().toString();
if (!"本地书籍".equals(mBook.getType()) && !StringHelper.isEmpty(url)) {
Intent intent = new Intent(Intent.ACTION_VIEW);
Uri uri = Uri.parse(url);
intent.setData(uri);
context.startActivity(intent);
}
llChapter.setOnClickListener(v -> {
String url1 = tvChapterUrl.getText().toString();
if (!"本地书籍".equals(mBook.getType()) && !StringHelper.isEmpty(url1)) {
Intent intent = new Intent(Intent.ACTION_VIEW);
Uri uri = Uri.parse(url1);
intent.setData(uri);
context.startActivity(intent);
}
});
@ -419,20 +423,14 @@ public class DialogCreator {
}
llBack.setOnClickListener(backListener);
tvLastChapter.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (lastChapterListener != null){
lastChapterListener.onClick(tvChapterTitle, tvChapterUrl, sbChapterProgress);
}
tvLastChapter.setOnClickListener(v -> {
if (lastChapterListener != null){
lastChapterListener.onClick(tvChapterTitle, tvChapterUrl, sbChapterProgress);
}
});
tvNextChapter.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (nextChapterListener != null){
nextChapterListener.onClick(tvChapterTitle, tvChapterUrl, sbChapterProgress);
}
tvNextChapter.setOnClickListener(v -> {
if (nextChapterListener != null){
nextChapterListener.onClick(tvChapterTitle, tvChapterUrl, sbChapterProgress);
}
});
sbChapterProgress.setProgress(chapterProgress);
@ -442,34 +440,28 @@ public class DialogCreator {
sbChapterProgress.setOnSeekBarChangeListener(onSeekBarChangeListener);
ivVoice.setOnClickListener(voiceOnClickListener);
//日夜切换
llNightAndDay.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
boolean isDay;
if (tvNightAndDay.getText().toString().equals(context.getString(R.string.day))) {
isDay = false;
ivNightAndDay.setImageResource(R.mipmap.ao);
tvNightAndDay.setText(context.getString(R.string.night));
} else {
isDay = true;
ivNightAndDay.setImageResource(R.mipmap.z4);
tvNightAndDay.setText(context.getString(R.string.day));
}
if (onClickNightAndDayListener != null) {
onClickNightAndDayListener.onClick(dialog, view, isDay);
}
llNightAndDay.setOnClickListener(view1 -> {
boolean isDay;
if (tvNightAndDay.getText().toString().equals(context.getString(R.string.day))) {
isDay = false;
ivNightAndDay.setImageResource(R.mipmap.ao);
tvNightAndDay.setText(context.getString(R.string.night));
} else {
isDay = true;
ivNightAndDay.setImageResource(R.mipmap.z4);
tvNightAndDay.setText(context.getString(R.string.day));
}
if (onClickNightAndDayListener != null) {
onClickNightAndDayListener.onClick(dialog, view1, isDay);
}
});
//缓存章节
final TextView tvDownloadProgress = (TextView)view.findViewById(R.id.tv_download_progress);
LinearLayout llDonwloadCache = (LinearLayout)view.findViewById(R.id.ll_download_cache);
llDonwloadCache.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (onClickDownloadAllChapterListener != null){
onClickDownloadAllChapterListener.onClick(dialog,v,tvDownloadProgress);
}
final TextView tvDownloadProgress = view.findViewById(R.id.tv_download_progress);
LinearLayout llDonwloadCache = view.findViewById(R.id.ll_download_cache);
llDonwloadCache.setOnClickListener(v -> {
if (onClickDownloadAllChapterListener != null){
onClickDownloadAllChapterListener.onClick(dialog,v,tvDownloadProgress);
}
});
@ -774,4 +766,9 @@ public class DialogCreator {
public interface OnSkipChapterListener{
void onClick(TextView chapterTitle, TextView chapterUrl, SeekBar sbReadChapterProgress);
}
public interface OnMultiDialogListener{
void onItemClick(DialogInterface dialog,int which,boolean isChecked);
void onSelectAll(boolean isSelectAll);
}
}

@ -0,0 +1,74 @@
package xyz.fycz.myreader.creator;
import android.content.Context;
import android.content.DialogInterface;
import android.widget.Button;
import android.widget.ListView;
import androidx.appcompat.app.AlertDialog;
/**
* @author fengyue
* @date 2020/8/29 21:08
*/
public class MultiChoiceDialog {
ListView itemList = null;
Button selectAll = null;
int checkedCount;
public AlertDialog create(Context context, String title, CharSequence[] items,
boolean[] checkedItems, int checkedCount,
DialogInterface.OnClickListener positiveListener,
DialogInterface.OnClickListener negativeListener,
DialogCreator.OnMultiDialogListener onMultiDialogListener) {
this.checkedCount = checkedCount;
int itemsCount = checkedItems.length;
AlertDialog multiChoiceDialog = new AlertDialog.Builder(context)
.setTitle(title)
.setMultiChoiceItems(items, checkedItems, (dialog, which, isChecked) -> {
onMultiDialogListener.onItemClick(dialog, which, isChecked);
if(isChecked){
this.checkedCount++;
}else {
this.checkedCount--;
}
if (this.checkedCount == itemsCount) {
selectAll.setText("取消全选");
} else {
selectAll.setText("全选");
}
})
.setPositiveButton("确定", positiveListener)
.setNegativeButton("取消", negativeListener)
.setNeutralButton("全选", null).create();
multiChoiceDialog.show();
itemList = multiChoiceDialog.getListView();
selectAll = multiChoiceDialog.getButton(DialogInterface.BUTTON_NEUTRAL);
if (this.checkedCount == itemsCount) {
selectAll.setText("取消全选");
} else {
selectAll.setText("全选");
}
selectAll.setOnClickListener(v1 -> {
if (this.checkedCount == itemsCount) {
selectAll.setText("全选");
this.checkedCount = 0;
for (int i = 0; i < itemsCount; i++) {
checkedItems[i] = false;
itemList.setItemChecked(i, false);
}
onMultiDialogListener.onSelectAll(false);
} else {
this.checkedCount = itemsCount;
selectAll.setText("取消全选");
for (int i = 0; i < itemsCount; i++) {
checkedItems[i] = true;
itemList.setItemChecked(i, true);
}
onMultiDialogListener.onSelectAll(true);
}
});
return multiChoiceDialog;
}
}

@ -17,11 +17,9 @@ public class Setting implements Serializable {
private static final long serialVersionUID = 2295691810299441757L;
private int readWordColor;//阅读字体颜色
private int readBgColor;//阅读背景颜色
private float readWordSize;//阅读字体大小
private ReadStyle readStyle;//阅读模式
private ReadStyle readStyle = ReadStyle.leather;//阅读模式
private boolean dayStyle;//是否日间模式
private int brightProgress;//亮度 1- 100
@ -29,11 +27,13 @@ public class Setting implements Serializable {
private Language language;//简繁体
private Font font;//字体
private int autoScrollSpeed = 5;//自动滑屏速度
private int autoScrollSpeed = 3;//自动滑屏速度
private PageMode pageMode;//翻页模式
private boolean isVolumeTurnPage;//是否开启音量键翻页
private boolean isVolumeTurnPage = true;//是否开启音量键翻页
private int resetScreen = 3;//息屏时间(单位:min,0是不息屏)
private BookcaseStyle bookcaseStyle;//书架布局
@ -43,6 +43,14 @@ public class Setting implements Serializable {
private boolean isAutoSyn;//是否自动同步书架
private boolean isMatchChapter = true;//是否开启智能匹配历史章节
private float matchChapterSuitability;//匹配度
private int catheGap = 150;//缓存间隔
private boolean refreshWhenStart;//打开软件自动更新书籍
private int settingVersion;//设置版本号
public int getAutoScrollSpeed() {
@ -93,22 +101,6 @@ public class Setting implements Serializable {
this.dayStyle = dayStyle;
}
public int getReadWordColor() {
return readWordColor;
}
public void setReadWordColor(int readWordColor) {
this.readWordColor = readWordColor;
}
public int getReadBgColor() {
return readBgColor;
}
public void setReadBgColor(int readBgColor) {
this.readBgColor = readBgColor;
}
public float getReadWordSize() {
return readWordSize;
}
@ -180,4 +172,44 @@ public class Setting implements Serializable {
public void setSettingVersion(int settingVersion) {
this.settingVersion = settingVersion;
}
public int getResetScreen() {
return resetScreen;
}
public void setResetScreen(int resetScreen) {
this.resetScreen = resetScreen;
}
public boolean isMatchChapter() {
return isMatchChapter;
}
public void setMatchChapter(boolean matchChapter) {
isMatchChapter = matchChapter;
}
public float getMatchChapterSuitability() {
return matchChapterSuitability;
}
public void setMatchChapterSuitability(float matchChapterSuitability) {
this.matchChapterSuitability = matchChapterSuitability;
}
public int getCatheGap() {
return catheGap;
}
public void setCatheGap(int catheGap) {
this.catheGap = catheGap;
}
public boolean isRefreshWhenStart() {
return refreshWhenStart;
}
public void setRefreshWhenStart(boolean refreshWhenStart) {
this.refreshWhenStart = refreshWhenStart;
}
}

@ -6,13 +6,14 @@ import org.greenrobot.greendao.annotation.Entity;
import org.greenrobot.greendao.annotation.Generated;
import org.greenrobot.greendao.annotation.Id;
import org.greenrobot.greendao.annotation.Transient;
import xyz.fycz.myreader.greendao.service.BookService;
import java.io.Serializable;
import java.util.Objects;
/**
*
* Created by zhao on 2017/7/24.
* Created by fengyue on 2020/08/23.
*/
@Entity
@ -54,13 +55,19 @@ public class Book implements Serializable {
@Nullable
private String source;
@Generated(hash = 1392889320)
private boolean isCloseUpdate;//是否关闭更新
@Nullable
private boolean isDownLoadAll = true;//是否一键缓存
@Generated(hash = 1839780644)
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) {
int chapterTotalNum, int lastReadPosition, String source,
boolean isCloseUpdate, boolean isDownLoadAll) {
this.id = id;
this.name = name;
this.chapterUrl = chapterUrl;
@ -79,6 +86,8 @@ public class Book implements Serializable {
this.chapterTotalNum = chapterTotalNum;
this.lastReadPosition = lastReadPosition;
this.source = source;
this.isCloseUpdate = isCloseUpdate;
this.isDownLoadAll = isDownLoadAll;
}
public Book(Book book) {
@ -100,6 +109,8 @@ public class Book implements Serializable {
this.chapterTotalNum = book.chapterTotalNum;
this.lastReadPosition = book.lastReadPosition;
this.source = book.source;
this.isCloseUpdate = book.isCloseUpdate;
this.isDownLoadAll = book.isDownLoadAll;
}
@Generated(hash = 1839243756)
@ -139,7 +150,7 @@ public class Book implements Serializable {
return this.author;
}
public void setAuthor(String author) {
this.author = author;
this.author = BookService.formatAuthor(author);
}
public String getType() {
return this.type;
@ -217,6 +228,15 @@ public class Book implements Serializable {
this.source = source;
}
public boolean getIsCloseUpdate() {
return this.isCloseUpdate;
}
public void setIsCloseUpdate(boolean isCloseUpdate) {
this.isCloseUpdate = isCloseUpdate;
}
@Override
public String toString() {
return "{\n" +
@ -238,6 +258,8 @@ public class Book implements Serializable {
",\nchapterTotalNum='" + chapterTotalNum + '\'' +
",\nlastReadPosition='" + lastReadPosition + '\'' +
",\nsource='" + source + '\'' +
",\nisCloseUpdate='" + isCloseUpdate + '\'' +
",\nisDownLoadAll='" + isDownLoadAll + '\'' +
"\n}";
}
@ -256,4 +278,18 @@ public class Book implements Serializable {
public int hashCode() {
return Objects.hash(name, chapterUrl, author, source);
}
public boolean getIsDownLoadAll() {
return this.isDownLoadAll;
}
public void setIsDownLoadAll(boolean isDownLoadAll) {
this.isDownLoadAll = isDownLoadAll;
}
}

@ -27,16 +27,23 @@ public class Chapter {
@Nullable
private String content;//章节正文
//章节内容在文章中的起始位置(本地)
private long start;
//章节内容在文章中的终止位置(本地)
private long end;
@Generated(hash = 1019441369)
@Generated(hash = 763230955)
public Chapter(String id, String bookId, int number, String title, String url,
String content) {
String content, long start, long end) {
this.id = id;
this.bookId = bookId;
this.number = number;
this.title = title;
this.url = url;
this.content = content;
this.start = start;
this.end = end;
}
@Generated(hash = 393170288)
public Chapter() {
@ -86,4 +93,19 @@ public class Chapter {
this.content = content;
}
public long getStart() {
return start;
}
public void setStart(long start) {
this.start = start;
}
public long getEnd() {
return end;
}
public void setEnd(long end) {
this.end = end;
}
}

@ -72,7 +72,7 @@ public class BookMarkService extends BaseService {
BookMark bookMark = null;
String sql = "select * from book_mark where title = ?";
Cursor cursor = selectBySql(sql,new String[]{title});
if (cursor == null) return bookMark;
if (cursor == null) return null;
if (cursor.moveToNext()){
bookMark = new BookMark();
bookMark.setId(cursor.getString(0));

@ -2,34 +2,47 @@ package xyz.fycz.myreader.greendao.service;
import android.database.Cursor;
import android.text.TextUtils;
import net.ricecode.similarity.JaroWinklerStrategy;
import net.ricecode.similarity.StringSimilarityService;
import net.ricecode.similarity.StringSimilarityServiceImpl;
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.util.*;
import xyz.fycz.myreader.greendao.GreenDaoManager;
import xyz.fycz.myreader.greendao.entity.Book;
import xyz.fycz.myreader.util.utils.FileUtils;
import xyz.fycz.myreader.util.utils.StringUtils;
import java.io.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class BookService extends BaseService {
private static Pattern chapterNamePattern = Pattern.compile("^(.*?第([\\d零〇一二两三四五六七八九十百千万壹贰叁肆伍陆柒捌玖拾佰仟0-9\\s]+)[章节篇回集])[、,。 ::.\\s]*");
private ChapterService mChapterService;
private BookMarkService mBookMarkService;
private static volatile BookService sInstance;
public BookService(){
public BookService() {
mChapterService = ChapterService.getInstance();
mBookMarkService = BookMarkService.getInstance();
}
public static BookService getInstance() {
if (sInstance == null){
synchronized (BookService.class){
if (sInstance == null){
if (sInstance == null) {
synchronized (BookService.class) {
if (sInstance == null) {
sInstance = new BookService();
}
}
@ -61,6 +74,8 @@ public class BookService extends BaseService {
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) {
@ -71,6 +86,7 @@ public class BookService extends BaseService {
/**
* 通过ID查书
*
* @param id
* @return
*/
@ -81,45 +97,51 @@ public class BookService extends BaseService {
/**
* 获取所有的书
*
* @return
*/
public List<Book> getAllBooks(){
public List<Book> getAllBooks() {
String sql = "select * from book order by sort_code";
return findBooks(sql, null);
}
/**
* 新增书
*
* @param book
*/
public void addBook(Book book){
public void addBook(Book book) {
// book.setSortCode(countBookTotalNum() + 1);
book.setSortCode(0);
book.setId(StringHelper.getStringRandom(25));
if (StringHelper.isEmpty(book.getId())) {
book.setId(StringHelper.getStringRandom(25));
}
addEntity(book);
}
/**
* 批量添加书籍
*
* @param books
*/
public void addBooks(List<Book> books){
for (Book book : books){
public void addBooks(List<Book> books) {
for (Book book : books) {
addBook(book);
}
}
/**
* 查找书作者书名
*
* @param author
* @param bookName
* @return
*/
public Book findBookByAuthorAndName(String bookName, String author){
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()){
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);
}
@ -131,14 +153,15 @@ public class BookService extends BaseService {
/**
* 通过路径查书籍本地书籍
*
* @param path
* @return
*/
public Book findBookByPath(String path){
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()){
Cursor cursor = selectBySql("select id from book where CHAPTER_URL = ?", new String[]{path});
if (cursor.moveToNext()) {
String id = cursor.getString(0);
book = getBookById(id);
}
@ -150,9 +173,10 @@ public class BookService extends BaseService {
/**
* 删除书
*
* @param id
*/
public void deleteBookById(String id){
public void deleteBookById(String id) {
BookDao bookDao = GreenDaoManager.getInstance().getSession().getBookDao();
bookDao.deleteByKey(id);
mChapterService.deleteBookALLChapterById(id);
@ -161,32 +185,34 @@ public class BookService extends BaseService {
/**
* 删除书
*
* @param book
*/
public void deleteBook(Book book){
deleteEntity(book);
mChapterService.deleteBookALLChapterById(book.getId());
mBookMarkService.deleteBookALLBookMarkById(book.getId());
public void deleteBook(Book book) {
deleteEntity(book);
mChapterService.deleteBookALLChapterById(book.getId());
mBookMarkService.deleteBookALLBookMarkById(book.getId());
}
/**
* 删除所有书
*/
public void deleteAllBooks(){
for(Book book : getAllBooks()){
public void deleteAllBooks() {
for (Book book : getAllBooks()) {
deleteBook(book);
}
}
/**
* 查询书籍总数
*
* @return
*/
public int countBookTotalNum(){
public int countBookTotalNum() {
int num = 0;
try {
Cursor cursor = selectBySql("select count(*) n from book ",null);
if (cursor.moveToNext()){
Cursor cursor = selectBySql("select count(*) n from book ", null);
if (cursor.moveToNext()) {
num = cursor.getInt(0);
}
} catch (Exception e) {
@ -197,42 +223,190 @@ public class BookService extends BaseService {
/**
* 更新书
*
* @param books
*/
public void updateBooks(List<Book> books){
public void updateBooks(List<Book> books) {
BookDao bookDao = GreenDaoManager.getInstance().getSession().getBookDao();
bookDao.updateInTx(books);
}
/**
* 更新单本书
* @param book
*/
public void updateBook(Book book){
deleteBook(book);
book.setId(StringHelper.getStringRandom(25));
addEntity(book);
}
/**
* 删除旧书添加新书
*
* @param OldBook
* @param newBook
*/
public void updateBook(Book OldBook, Book newBook){
public void updateBook(Book OldBook, Book newBook) {
deleteBook(OldBook);
newBook.setId(StringHelper.getStringRandom(25));
addEntity(newBook);
}
/**
* 删除所有章节缓存
*/
public void deleteAllBookCathe(){
FileUtils.deleteFile(APPCONST.BOOK_CACHE_PATH);
}
/**
* 判断书籍是否存在
*
* @param book
* @return
*/
public boolean isBookCollected(Book book){
public boolean isBookCollected(Book book) {
return findBookByAuthorAndName(book.getName(), book.getAuthor()) != null;
}
/**
* 匹配书籍历史章节
*
* @param book
* @param mChapters
*/
/*public boolean matchHistoryChapterPos(Book book, ArrayList<Chapter> mChapters) {
assert book.getHistoryChapterId() != null;
float matchSui = SysManager.getSetting().getMatchChapterSuitability();
int oldDurChapterIndex = book.getHisttoryChapterNum();
int oldChapterListSize = book.getChapterTotalNum();
int newChapterSize = mChapters.size();
int min = Math.max(0, Math.min(oldDurChapterIndex, oldDurChapterIndex - oldChapterListSize + newChapterSize) - 10);
int max = Math.min(newChapterSize - 1, Math.max(oldDurChapterIndex, oldDurChapterIndex - oldChapterListSize + newChapterSize) + 10);
String historyChapter = StringUtils.deleteWhitespace(book.getHistoryChapterId());
String newChapter;
for (int i = min; i < max; i++) {
Chapter chapter = mChapters.get(i);
newChapter = StringUtils.deleteWhitespace(chapter.getTitle());
if (historyChapter.contains(newChapter) ||
newChapter.contains(historyChapter)) {
book.setHistoryChapterId(chapter.getTitle());
book.setHisttoryChapterNum(i);
updateEntity(book);
return true;
}
}
for (int i = min; i < max; i++) {
Chapter chapter = mChapters.get(i);
newChapter = StringUtils.deleteWhitespace(chapter.getTitle());
if (StringUtils.levenshtein(historyChapter, newChapter) > matchSui) {
book.setHistoryChapterId(chapter.getTitle());
book.setHisttoryChapterNum(i);
updateEntity(book);
return true;
}
}
return false;
}*/
public boolean matchHistoryChapterPos(Book book, ArrayList<Chapter> mChapters) {
float matchSui = SysManager.getSetting().getMatchChapterSuitability();
int index = getDurChapter(book.getHisttoryChapterNum(), book.getChapterTotalNum(), book.getHistoryChapterId(), mChapters);
assert book.getHistoryChapterId() != null;
String oldName = StringUtils.deleteWhitespace(book.getHistoryChapterId());
String newName = StringUtils.deleteWhitespace(mChapters.get(index).getTitle());
/*int i1 = getChapterNum(oldName);
int i2 = getChapterNum(newName);
String s1 = getPureChapterName(oldName);
String s2 = getPureChapterName(newName);
int i = 1;*/
if (oldName.contains(newName) || newName.contains(oldName) ||
StringUtils.levenshtein(oldName, newName) > matchSui ||
getChapterNum(oldName) == getChapterNum(newName) ||
getPureChapterName(oldName).equals(getPureChapterName(newName))){
book.setHistoryChapterId(mChapters.get(index).getTitle());
book.setHisttoryChapterNum(index);
updateEntity(book);
return true;
}
return false;
}
/**
* 根据目录名获取当前章节
*/
public int getDurChapter(int oldDurChapterIndex, int oldChapterListSize, String oldDurChapterName, List<Chapter> newChapterList) {
if (oldChapterListSize == 0)
return 0;
int oldChapterNum = getChapterNum(oldDurChapterName);
String oldName = getPureChapterName(oldDurChapterName);
int newChapterSize = newChapterList.size();
int min = Math.max(0, Math.min(oldDurChapterIndex, oldDurChapterIndex - oldChapterListSize + newChapterSize) - 10);
int max = Math.min(newChapterSize - 1, Math.max(oldDurChapterIndex, oldDurChapterIndex - oldChapterListSize + newChapterSize) + 10);
double nameSim = 0;
int newIndex = 0;
int newNum = 0;
if (!oldName.isEmpty()) {
StringSimilarityService service = new StringSimilarityServiceImpl(new JaroWinklerStrategy());
for (int i = min; i <= max; i++) {
String newName = getPureChapterName(newChapterList.get(i).getTitle());
double temp = service.score(oldName, newName);
if (temp > nameSim) {
nameSim = temp;
newIndex = i;
}
}
}
if (nameSim < 0.96 && oldChapterNum > 0) {
for (int i = min; i <= max; i++) {
int temp = getChapterNum(newChapterList.get(i).getTitle());
if (temp == oldChapterNum) {
newNum = temp;
newIndex = i;
break;
} else if (Math.abs(temp - oldChapterNum) < Math.abs(newNum - oldChapterNum)) {
newNum = temp;
newIndex = i;
}
}
}
if (nameSim > 0.96 || Math.abs(newNum - oldChapterNum) < 1) {
return newIndex;
} else {
return Math.min(Math.max(0, newChapterList.size() - 1), oldDurChapterIndex);
}
}
private int getChapterNum(String chapterName) {
if (chapterName != null) {
Matcher matcher = chapterNamePattern.matcher(chapterName);
if (matcher.find()) {
return StringUtils.stringToInt(matcher.group(2));
}
}
return -1;
}
private String getPureChapterName(String chapterName) {
return chapterName == null ? ""
: StringUtils.fullToHalf(chapterName).replaceAll("\\s", "")
.replaceAll("^第.*?章|[(\\[][^()\\[\\]]{2,}[)\\]]$", "")
.replaceAll("[^\\w\\u4E00-\\u9FEF〇\\u3400-\\u4DBF\\u20000-\\u2A6DF\\u2A700-\\u2EBEF]", "");
// 所有非字母数字中日韩文字 CJK区+扩展A-F区
}
public static String formatAuthor(String author) {
if (author == null) {
return "";
}
return author.replaceAll("作\\s*者[\\s::]*", "").replaceAll("\\s+", " ").trim();
}
public static int guessChapterNum(String name) {
if (TextUtils.isEmpty(name) || name.matches("第.*?卷.*?第.*[章节回]"))
return -1;
Matcher matcher = chapterNamePattern.matcher(name);
if (matcher.find()) {
return StringUtils.stringToInt(matcher.group(2));
}
return -1;
}
/**
* 保存全部章节名称和url
* @param book

@ -234,6 +234,42 @@ public class ChapterService extends BaseService {
}
}
/**
* 更新所有章节
*
* @param newChapters
*/
public void updateAllOldChapterData(ArrayList<Chapter> mChapters, ArrayList<Chapter> newChapters, String bookId) {
int i;
for (i = 0; i < mChapters.size() && i < newChapters.size(); i++) {
Chapter oldChapter = mChapters.get(i);
Chapter newChapter = newChapters.get(i);
if (!oldChapter.getTitle().equals(newChapter.getTitle())) {
oldChapter.setTitle(newChapter.getTitle());
oldChapter.setUrl(newChapter.getUrl());
oldChapter.setContent(null);
saveOrUpdateChapter(oldChapter, null);
}
}
if (mChapters.size() < newChapters.size()) {
int start = mChapters.size();
for (int j = mChapters.size(); j < newChapters.size(); j++) {
newChapters.get(j).setId(StringHelper.getStringRandom(25));
newChapters.get(j).setBookId(bookId);
mChapters.add(newChapters.get(j));
// mChapterService.addChapter(newChapters.get(j));
}
addChapters(mChapters.subList(start, mChapters.size()));
} else if (mChapters.size() > newChapters.size()) {
for (int j = newChapters.size(); j < mChapters.size(); j++) {
deleteEntity(mChapters.get(j));
deleteChapterCacheFile(mChapters.get(j));
}
mChapters.subList(0, newChapters.size());
}
}
/**
* 根据文件名判断是否被缓存过 (因为可能数据库显示被缓存过但是文件中却没有的情况所以需要根据文件判断是否被缓存
* )

@ -1,164 +0,0 @@
package xyz.fycz.myreader.greendao.util;
import android.database.Cursor;
import android.text.TextUtils;
import android.util.Log;
import xyz.fycz.myreader.greendao.gen.DaoMaster;
import org.greenrobot.greendao.AbstractDao;
import org.greenrobot.greendao.database.Database;
import org.greenrobot.greendao.internal.DaoConfig;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class GreenDaoUpgrade {
private static final String CONVERSION_CLASS_NOT_FOUND_EXCEPTION = "MIGRATION HELPER - CLASS DOESN'T MATCH WITH THE CURRENT PARAMETERS";
private static GreenDaoUpgrade instance;
public static GreenDaoUpgrade getInstance() {
if (instance == null) {
instance = new GreenDaoUpgrade();
}
return instance;
}
private static List<String> getColumns(Database db, String tableName) {
List<String> columns = new ArrayList<>();
Cursor cursor = null;
try {
cursor = db.rawQuery("SELECT * FROM " + tableName + " limit 1", null);
if (cursor != null) {
columns = new ArrayList<>(Arrays.asList(cursor.getColumnNames()));
}
} catch (Exception e) {
Log.v(tableName, e.getMessage(), e);
e.printStackTrace();
} finally {
if (cursor != null)
cursor.close();
}
return columns;
}
public void migrate(Database db, Class<? extends AbstractDao<?, ?>>... daoClasses) {
generateTempTables(db, daoClasses);
DaoMaster.dropAllTables(db, true);
DaoMaster.createAllTables(db, false);
restoreData(db, daoClasses);
}
private void generateTempTables(Database db, Class<? extends AbstractDao<?, ?>>... daoClasses) {
for (int i = 0; i < daoClasses.length; i++) {
DaoConfig daoConfig = new DaoConfig(db, daoClasses[i]);
String divider = "";
String tableName = daoConfig.tablename;
String tempTableName = daoConfig.tablename.concat("_TEMP");
ArrayList<String> properties = new ArrayList<>();
StringBuilder createTableStringBuilder = new StringBuilder();
createTableStringBuilder.append("CREATE TABLE ").append(tempTableName).append(" (");
for (int j = 0; j < daoConfig.properties.length; j++) {
String columnName = daoConfig.properties[j].columnName;
if (getColumns(db, tableName).contains(columnName)) {
properties.add(columnName);
String type = null;
try {
type = getTypeByClass(daoConfig.properties[j].type);
} catch (Exception exception) {
exception.printStackTrace();
}
createTableStringBuilder.append(divider).append(columnName).append(" ").append(type);
if (daoConfig.properties[j].primaryKey) {
createTableStringBuilder.append(" PRIMARY KEY");
}
divider = ",";
}
}
createTableStringBuilder.append(");");
db.execSQL(createTableStringBuilder.toString());
StringBuilder insertTableStringBuilder = new StringBuilder();
insertTableStringBuilder.append("INSERT INTO ").append(tempTableName).append(" (");
insertTableStringBuilder.append(TextUtils.join(",", properties));
insertTableStringBuilder.append(") SELECT ");
insertTableStringBuilder.append(TextUtils.join(",", properties));
insertTableStringBuilder.append(" FROM ").append(tableName).append(";");
db.execSQL(insertTableStringBuilder.toString());
}
}
private void restoreData(Database db, Class<? extends AbstractDao<?, ?>>... daoClasses) {
for (int i = 0; i < daoClasses.length; i++) {
DaoConfig daoConfig = new DaoConfig(db, daoClasses[i]);
String tableName = daoConfig.tablename;
String tempTableName = daoConfig.tablename.concat("_TEMP");
ArrayList<String> properties = new ArrayList();
ArrayList<String> propertiesQuery = new ArrayList();
for (int j = 0; j < daoConfig.properties.length; j++) {
String columnName = daoConfig.properties[j].columnName;
if (getColumns(db, tempTableName).contains(columnName)) {
properties.add(columnName);
propertiesQuery.add(columnName);
} else {
try {
if (getTypeByClass(daoConfig.properties[j].type).equals("INTEGER")) {
propertiesQuery.add("0 as " + columnName);
properties.add(columnName);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
StringBuilder insertTableStringBuilder = new StringBuilder();
insertTableStringBuilder.append("INSERT INTO ").append(tableName).append(" (");
insertTableStringBuilder.append(TextUtils.join(",", properties));
insertTableStringBuilder.append(") SELECT ");
insertTableStringBuilder.append(TextUtils.join(",", propertiesQuery));
insertTableStringBuilder.append(" FROM ").append(tempTableName).append(";");
StringBuilder dropTableStringBuilder = new StringBuilder();
dropTableStringBuilder.append("DROP TABLE ").append(tempTableName);
db.execSQL(insertTableStringBuilder.toString());
db.execSQL(dropTableStringBuilder.toString());
}
}
private String getTypeByClass(Class<?> type) throws Exception {
if (type.equals(String.class)) {
return "TEXT";
}
if (type.equals(Long.class) || type.equals(Integer.class) || type.equals(long.class) || type.equals(int.class)) {
return "INTEGER";
}
if (type.equals(Boolean.class) || type.equals(boolean.class)) {
return "BOOLEAN";
}
Exception exception = new Exception(CONVERSION_CLASS_NOT_FOUND_EXCEPTION.concat(" - Class: ").concat(type.toString()));
exception.printStackTrace();
throw exception;
}
}

@ -3,6 +3,7 @@ package xyz.fycz.myreader.greendao.util;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import com.github.yuweiguocn.library.greendao.MigrationHelper;
import xyz.fycz.myreader.greendao.gen.*;
import org.greenrobot.greendao.database.Database;
@ -20,8 +21,21 @@ public class MySQLiteOpenHelper extends DaoMaster.OpenHelper {
@Override
public void onUpgrade(Database db, int oldVersion, int newVersion) {
//加入你要新建的或者修改的表的信息
GreenDaoUpgrade.getInstance().migrate(db, BookDao.class, ChapterDao.class, SearchHistoryDao.class);
//noinspection unchecked
MigrationHelper.migrate(db,
new MigrationHelper.ReCreateAllTableListener() {
@Override
public void onCreateAllTables(Database db, boolean ifNotExists) {
DaoMaster.createAllTables(db, ifNotExists);
}
@Override
public void onDropAllTables(Database db, boolean ifExists) {
DaoMaster.dropAllTables(db, ifExists);
}
},
BookDao.class, ChapterDao.class, SearchHistoryDao.class, BookMarkDao.class
);
}

@ -42,7 +42,7 @@ public class AboutActivity extends BaseActivity {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_about);
ButterKnife.bind(this);
setStatusBar(R.color.sys_line);
setStatusBar(R.color.white, false);
mAboutPresenter = new AboutPresenter(this);
mAboutPresenter.start();
}

@ -21,9 +21,11 @@ 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.application.SysManager;
import xyz.fycz.myreader.base.BaseActivity2;
import xyz.fycz.myreader.callback.ResultCallback;
import xyz.fycz.myreader.common.APPCONST;
import xyz.fycz.myreader.util.ToastUtils;
import xyz.fycz.myreader.webapi.crawler.BookInfoCrawler;
import xyz.fycz.myreader.webapi.crawler.ReadCrawler;
import xyz.fycz.myreader.webapi.crawler.ReadCrawlerUtil;
@ -36,7 +38,6 @@ import xyz.fycz.myreader.greendao.service.BookService;
import xyz.fycz.myreader.greendao.service.ChapterService;
import xyz.fycz.myreader.ui.adapter.DetailCatalogAdapter;
import xyz.fycz.myreader.util.StringHelper;
import xyz.fycz.myreader.util.TextHelper;
import xyz.fycz.myreader.util.utils.NetworkUtils;
import xyz.fycz.myreader.webapi.CommonApi;
@ -53,8 +54,6 @@ public class BookDetailedActivity extends BaseActivity2 {
TextView mTvAuthor;
@BindView(R.id.book_detail_tv_type)
TextView mTvType;
@BindView(R.id.book_detail_newest_chapter)
TextView mTvNewestChapter;
@BindView(R.id.book_detail_source)
TextView mTvSource;
@BindView(R.id.book_detail_tv_add)
@ -97,7 +96,7 @@ public class BookDetailedActivity extends BaseActivity2 {
mChapters.clear();
mNewestChapters.clear();
initBookInfo();
initChapters();
initChapters(true);
mCatalogAdapter.notifyDataSetChanged();
}
break;
@ -140,6 +139,7 @@ public class BookDetailedActivity extends BaseActivity2 {
@Override
protected void setUpToolbar(Toolbar toolbar) {
super.setUpToolbar(toolbar);
setStatusBarColor(R.color.colorPrimary, true);
getSupportActionBar().setTitle(mBook.getName());
}
@ -153,7 +153,7 @@ public class BookDetailedActivity extends BaseActivity2 {
bookDetailRvCatalog.setLayoutManager(new LinearLayoutManager(this));
bookDetailRvCatalog.setAdapter(mCatalogAdapter);
initChapters();
initChapters(false);
mCatalogAdapter.setOnItemClickListener((view, pos) -> {
mBook.setHisttoryChapterNum(mChapters.size() - pos - 1);
@ -174,23 +174,29 @@ public class BookDetailedActivity extends BaseActivity2 {
super.initClick();
flAddBookcase.setOnClickListener(view -> {
if (!isCollected) {
mBook.setNoReadNum(mChapters.size());
mBook.setChapterTotalNum(0);
mBookService.addBook(mBook);
for (Chapter chapter : mChapters) {
chapter.setId(StringHelper.getStringRandom(25));
chapter.setBookId(mBook.getId());
}
mChapterService.addChapters(mChapters);
isCollected = true;
TextHelper.showText("成功加入书架");
ToastUtils.showSuccess("成功加入书架");
bookDetailTvAdd.setText("移除书籍");
} else {
mBookService.deleteBookById(mBook.getId());
isCollected = false;
mBook.setHisttoryChapterNum(0);
mBook.setHistoryChapterId("未开始阅读");
mBook.setLastReadPosition(0);
TextHelper.showText("成功移除书籍");
ToastUtils.showSuccess("成功移除书籍");
bookDetailTvAdd.setText("加入书架");
bookDetailTvOpen.setText("开始阅读");
}
});
flOpenBook.setOnClickListener(view -> {
goReadActivity();
});
flOpenBook.setOnClickListener(view -> goReadActivity());
}
@ -199,6 +205,11 @@ public class BookDetailedActivity extends BaseActivity2 {
super.processLogic();
}
/**
* 判断是否在书架
*
* @return
*/
private boolean isBookCollected() {
Book book = mBookService.findBookByAuthorAndName(mBook.getName(), mBook.getAuthor());
if (book == null) {
@ -209,13 +220,15 @@ public class BookDetailedActivity extends BaseActivity2 {
}
}
/**
* 初始化书籍信息
*/
private void initBookInfo() {
mTvAuthor.setText(mBook.getAuthor());
if (StringHelper.isEmpty(mBook.getImgUrl())) {
mBook.setImgUrl("");
}
assert mBook.getNewestChapterTitle() != null;
mTvNewestChapter.setText("最新章节:" + mBook.getNewestChapterTitle().replace("最近更新 ", ""));
mTvDesc.setText("");
mTvType.setText("");
if (!"null".equals(mBook.getSource())) {
@ -240,18 +253,26 @@ public class BookDetailedActivity extends BaseActivity2 {
}
}
/**
* 初始化其他书籍信息
*/
private void initOtherInfo() {
mTvDesc.setText("\t\t\t\t" + mBook.getDesc());
mTvType.setText(mBook.getType());
Glide.with(this)
.load(mBook.getImgUrl())
.error(R.mipmap.no_image)
.placeholder(R.mipmap.no_image)
//设置圆角
.apply(RequestOptions.bitmapTransform(new RoundedCorners(8)))
.into(mIvCover);
if (!MyApplication.isDestroy(this)) {
Glide.with(this)
.load(mBook.getImgUrl())
.error(R.mipmap.no_image)
.placeholder(R.mipmap.no_image)
//设置圆角
.apply(RequestOptions.bitmapTransform(new RoundedCorners(8)))
.into(mIvCover);
}
}
/**
* 创建换源对话框
*/
private void createChangeSourceDia() {
if (aBooks == null) {
mHandler.sendMessage(mHandler.obtainMessage(3));
@ -290,22 +311,48 @@ public class BookDetailedActivity extends BaseActivity2 {
mBook = bookTem;
mHandler.sendMessage(mHandler.obtainMessage(1));
if (isCollected) {
DialogCreator.createTipDialog(this,
"换源成功,由于不同书源的章节数量不一定相同,故换源后历史章节可能出错!");
String tip = null;
if (SysManager.getSetting().isMatchChapter()) {
tip = getString(R.string.change_source_tip1);
}else {
tip = getString(R.string.change_source_tip2);
}
DialogCreator.createTipDialog(this, tip);
}
dialog1.dismiss();
}).create();
dialog.show();
}
private void initChapters() {
/**
* 初始化章节目录
*/
private void initChapters(boolean isChangeSource) {
if (mChapters.size() == 0 && !"本地书籍".equals(mBook.getType())) {
mReadCrawler = ReadCrawlerUtil.getReadCrawler(mBook.getSource());
if (isCollected) {
mChapters = (ArrayList<Chapter>) mChapterService.findBookAllChapterByBookId(mBook.getId());
}
CommonApi.getBookChapters(mBook.getChapterUrl(), mReadCrawler, new ResultCallback() {
@Override
public void onFinish(Object o, int code) {
mChapters = (ArrayList<Chapter>) o;
int end = Math.max(0, mChapters.size() - 10);
ArrayList<Chapter> chapters = (ArrayList<Chapter>) o;
if (isCollected) {
int noReadNum = chapters.size() - mBook.getChapterTotalNum();
mBook.setNoReadNum(Math.max(noReadNum, 0));
mBook.setNewestChapterTitle(chapters.get(chapters.size() - 1).getTitle());
mChapterService.updateAllOldChapterData(mChapters, chapters, mBook.getId());
mBookService.updateEntity(mBook);
if (isChangeSource && SysManager.getSetting().isMatchChapter()) {
if (mBookService.matchHistoryChapterPos(mBook, chapters)) {
ToastUtils.showSuccess("历史阅读章节匹配成功!");
} else {
ToastUtils.showError("历史阅读章节匹配失败!");
}
}
}
mChapters = chapters;
int end = Math.max(0, mChapters.size() - 6);
for (int i = mChapters.size() - 1; i >= end; i--) {
mNewestChapters.add(mChapters.get(i));
}
@ -314,11 +361,11 @@ public class BookDetailedActivity extends BaseActivity2 {
@Override
public void onError(Exception e) {
ToastUtils.showError("最新章节加载失败!");
}
});
} else {
int end = Math.max(0, mChapters.size() - 10);
int end = Math.max(0, mChapters.size() - 6);
for (int i = mChapters.size() - 1; i >= end; i--) {
mNewestChapters.add(mChapters.get(i));
mCatalogAdapter.refreshItems(mNewestChapters);
@ -326,7 +373,10 @@ public class BookDetailedActivity extends BaseActivity2 {
}
}
private void goReadActivity(){
/**
* 前往阅读界面
*/
private void goReadActivity() {
if (!isCollected) {
mBookService.addBook(mBook);
}
@ -337,12 +387,33 @@ public class BookDetailedActivity extends BaseActivity2 {
}
/********************************Event***************************************/
/**
* 创建菜单
*
* @param menu
* @return
*/
@Override
public boolean onCreateOptionsMenu(Menu menu) {
if ("本地书籍".equals(mBook.getType())) {
return false;
}
getMenuInflater().inflate(R.menu.menu_book_detail, menu);
return true;
}
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
MenuItem isUpdate = menu.findItem(R.id.action_is_update);
if (isCollected) {
isUpdate.setVisible(true);
isUpdate.setChecked(!mBook.getIsCloseUpdate());
} else {
isUpdate.setVisible(false);
}
return super.onPrepareOptionsMenu(menu);
}
/**
* 导航栏菜单点击事件
*
@ -354,7 +425,7 @@ public class BookDetailedActivity extends BaseActivity2 {
switch (item.getItemId()) {
case R.id.action_change_source: //换源
if (!NetworkUtils.isNetWorkAvailable()) {
TextHelper.showText("无网络连接!");
ToastUtils.showWarring("无网络连接!");
return true;
}
pbLoading.setVisibility(View.VISIBLE);
@ -377,19 +448,19 @@ public class BookDetailedActivity extends BaseActivity2 {
}
break;
case R.id.action_reload: //重新加载
if (!"本地书籍".equals(mBook.getType())) {
mChapters.clear();
mNewestChapters.clear();
initWidget();
processLogic();
}
mChapters.clear();
mNewestChapters.clear();
initWidget();
processLogic();
break;
case R.id.action_is_update://是否更新
mBook.setIsCloseUpdate(!mBook.getIsCloseUpdate());
mBookService.updateEntity(mBook);
break;
case R.id.action_open_link: //打开链接
if (!"本地书籍".equals(mBook.getType())) {
Uri uri = Uri.parse(mBook.getChapterUrl());
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);
}
Uri uri = Uri.parse(mBook.getChapterUrl());
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);
break;
default:
break;
@ -407,6 +478,7 @@ public class BookDetailedActivity extends BaseActivity2 {
else
mTvDesc.setMaxLines(5);
}
/**
* 章节列表
*/
@ -416,6 +488,14 @@ public class BookDetailedActivity extends BaseActivity2 {
intent.putExtra(APPCONST.BOOK, mBook);
startActivityForResult(intent, APPCONST.REQUEST_CHAPTER_PAGE);
}
/**
* 阅读/章节界面反馈结果处理
*
* @param requestCode
* @param resultCode
* @param data
*/
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == RESULT_OK) {
@ -426,13 +506,19 @@ public class BookDetailedActivity extends BaseActivity2 {
}
boolean isCollected = data.getBooleanExtra(APPCONST.RESULT_IS_COLLECTED, false);
int lastReadPosition = data.getIntExtra(APPCONST.RESULT_LAST_READ_POSITION, 0);
int historyChapterPos = data.getIntExtra(APPCONST.RESULT_HISTORY_CHAPTER, 0);
if (isCollected) {
bookDetailTvAdd.setText("移除书籍");
bookDetailTvOpen.setText("继续阅读");
this.isCollected = true;
if (mChapters != null && mChapters.size() != 0) {
mBook.setHistoryChapterId(mChapters.get(historyChapterPos).getTitle());
}
mBook.setHisttoryChapterNum(historyChapterPos);
mBook.setLastReadPosition(lastReadPosition);
}else {
} else {
mBook.setHisttoryChapterNum(0);
mBook.setHistoryChapterId("未开始阅读");
mBook.setLastReadPosition(0);
}
mCatalogAdapter.notifyDataSetChanged();

@ -41,7 +41,7 @@ public class CatalogActivity extends BaseActivity {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_catalog);
ButterKnife.bind(this);
setStatusBar(R.color.sys_line);
setStatusBar(0, false);
mCatalogPresenter = new CatalogActivityPresenter(this);
mCatalogPresenter.start();
}

@ -16,7 +16,7 @@ import xyz.fycz.myreader.greendao.service.BookService;
import xyz.fycz.myreader.ui.fragment.BaseFileFragment;
import xyz.fycz.myreader.ui.fragment.FileCategoryFragment;
import xyz.fycz.myreader.ui.fragment.LocalBookFragment;
import xyz.fycz.myreader.util.TextHelper;
import xyz.fycz.myreader.util.ToastUtils;
import java.io.File;
@ -81,7 +81,7 @@ public class FileSystemActivity extends BaseTabActivity {
@Override
protected void setUpToolbar(Toolbar toolbar) {
super.setUpToolbar(toolbar);
setStatusBarColor(R.color.sys_line);
setStatusBarColor(R.color.white, false);
getSupportActionBar().setTitle("添加本地");
}
@ -139,7 +139,7 @@ public class FileSystemActivity extends BaseTabActivity {
//改变是否可以全选
changeCheckedAllStatus();
//提示加入书架成功
TextHelper.showText(getResources().getString(R.string.file_add_succeed, books.size()));
ToastUtils.showSuccess(getResources().getString(R.string.file_add_succeed, books.size()));
}
);
@ -156,7 +156,7 @@ public class FileSystemActivity extends BaseTabActivity {
//改变是否可以全选
changeCheckedAllStatus();
//提示删除文件成功
TextHelper.showText("删除文件成功");
ToastUtils.showSuccess("删除文件成功");
}, null);
}
);
@ -190,7 +190,8 @@ public class FileSystemActivity extends BaseTabActivity {
book.setNewestChapterTitle("未拆分章节");
book.setAuthor("本地书籍");
book.setSource(BookSource.local.toString());
book.setDesc("");
book.setDesc("无");
book.setIsCloseUpdate(true);
books.add(book);
}
return books;

@ -39,7 +39,7 @@ public class FontsActivity extends BaseActivity {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fonts);
ButterKnife.bind(this);
setStatusBar(R.color.sys_line);
setStatusBar(R.color.white, false);
mFontsPresenter = new FontsPresenter(this);
mFontsPresenter.start();
}

@ -46,7 +46,7 @@ public class LoginActivity extends BaseActivity implements TextWatcher {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
ButterKnife.bind(this);
setStatusBar(R.color.sys_line);
setStatusBar(R.color.white, false);
mLoginPresenter = new LoginPresenter(this);
mLoginPresenter.start();
}

@ -23,10 +23,10 @@ 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 xyz.fycz.myreader.util.TextHelper;
import butterknife.BindView;
import butterknife.ButterKnife;
import xyz.fycz.myreader.util.ToastUtils;
import java.io.File;
@ -63,7 +63,7 @@ public class MainActivity extends BaseActivity {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
setStatusBar(R.color.sys_line);
setStatusBar(R.color.white, false);
mMainPrensenter = new MainPresenter(this);
mMainPrensenter.start();
}
@ -75,7 +75,7 @@ public class MainActivity extends BaseActivity {
return;
}
if (System.currentTimeMillis() - APPCONST.exitTime > APPCONST.exitConfirmTime) {
TextHelper.showText("再按一次退出");
ToastUtils.showExit("再按一次退出");
APPCONST.exitTime = System.currentTimeMillis();
} else {
super.onBackPressed();
@ -117,7 +117,7 @@ public class MainActivity extends BaseActivity {
startActivity(intent);
} else {
TextHelper.showText("用户拒绝开启读写权限");
ToastUtils.showWarring("用户拒绝开启读写权限");
}
return;
}

@ -0,0 +1,411 @@
package xyz.fycz.myreader.ui.activity;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.*;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.SwitchCompat;
import androidx.appcompat.widget.Toolbar;
import butterknife.BindView;
import xyz.fycz.myreader.R;
import xyz.fycz.myreader.application.MyApplication;
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.creator.MultiChoiceDialog;
import xyz.fycz.myreader.entity.Setting;
import xyz.fycz.myreader.greendao.entity.Book;
import xyz.fycz.myreader.greendao.service.BookService;
import xyz.fycz.myreader.util.ToastUtils;
import java.util.ArrayList;
import java.util.Iterator;
/**
* Created by newbiechen on 17-6-6.
* 阅读界面的更多设置
*/
public class MoreSettingActivity extends BaseActivity2 {
@BindView(R.id.more_setting_rl_volume)
RelativeLayout mRlVolume;
@BindView(R.id.more_setting_sc_volume)
SwitchCompat mScVolume;
@BindView(R.id.more_setting_rl_reset_screen)
RelativeLayout mRlResetScreen;
@BindView(R.id.more_setting_sc_reset_screen)
Spinner mScResetScreen;
@BindView(R.id.more_setting_rl_auto_refresh)
RelativeLayout mRlAutoRefresh;
@BindView(R.id.more_setting_sc_auto_refresh)
SwitchCompat mScAutoRefresh;
@BindView(R.id.more_setting_ll_close_refresh)
LinearLayout mLlCloseRefresh;
@BindView(R.id.more_setting_iv_match_chapter_tip)
ImageView mIvMatchChapterTip;
@BindView(R.id.more_setting_rl_match_chapter)
RelativeLayout mRlMatchChapter;
@BindView(R.id.more_setting_sc_match_chapter)
SwitchCompat mScMatchChapter;
@BindView(R.id.more_setting_rl_match_chapter_suitability)
RelativeLayout mRlMatchChapterSuitability;
@BindView(R.id.more_setting_sc_match_chapter_suitability)
Spinner mScMatchChapterSuitability;
@BindView(R.id.more_setting_rl_cathe_gap)
RelativeLayout mRlCatheGap;
@BindView(R.id.more_setting_sc_cathe_gap)
Spinner mScCatheGap;
@BindView(R.id.more_setting_rl_delete_cathe)
RelativeLayout mRlDeleteCathe;
@BindView(R.id.more_setting_ll_download_all)
LinearLayout mLlDownloadAll;
private Setting mSetting;
private boolean isVolumeTurnPage;
private int resetScreenTime;
private boolean autoRefresh;
private boolean isMatchChapter;
private float matchChapterSuitability;
private int catheCap;
private ArrayList<Book> mBooks;
int booksCount;
CharSequence[] mBooksName;
//选择禁用更新书籍对话框
private AlertDialog mCloseRefreshDia;
//选择一键缓存书籍对话框
private AlertDialog mDownloadAllDia;
@Override
protected int getContentId() {
return R.layout.activity_more_setting;
}
@Override
protected void initData(Bundle savedInstanceState) {
super.initData(savedInstanceState);
mSetting = SysManager.getSetting();
isVolumeTurnPage = mSetting.isVolumeTurnPage();
resetScreenTime = mSetting.getResetScreen();
isMatchChapter = mSetting.isMatchChapter();
matchChapterSuitability = mSetting.getMatchChapterSuitability();
catheCap = mSetting.getCatheGap();
autoRefresh = mSetting.isRefreshWhenStart();
}
@Override
protected void setUpToolbar(Toolbar toolbar) {
super.setUpToolbar(toolbar);
setStatusBarColor(R.color.colorPrimary, true);
getSupportActionBar().setTitle("设置");
}
@Override
protected void initWidget() {
super.initWidget();
initSwitchStatus();
if (isMatchChapter) {
mRlMatchChapterSuitability.setVisibility(View.VISIBLE);
} else {
mRlMatchChapterSuitability.setVisibility(View.GONE);
}
}
private void initSwitchStatus() {
mScVolume.setChecked(isVolumeTurnPage);
mScMatchChapter.setChecked(isMatchChapter);
mScAutoRefresh.setChecked(autoRefresh);
}
@Override
protected void initClick() {
super.initClick();
mRlVolume.setOnClickListener(
(v) -> {
if (isVolumeTurnPage) {
isVolumeTurnPage = false;
} else {
isVolumeTurnPage = true;
}
mScVolume.setChecked(isVolumeTurnPage);
mSetting.setVolumeTurnPage(isVolumeTurnPage);
SysManager.saveSetting(mSetting);
}
);
mRlAutoRefresh.setOnClickListener(
(v) -> {
if (autoRefresh) {
autoRefresh = false;
} else {
autoRefresh = true;
}
mScAutoRefresh.setChecked(autoRefresh);
mSetting.setRefreshWhenStart(autoRefresh);
SysManager.saveSetting(mSetting);
}
);
mLlCloseRefresh.setOnClickListener(v -> {
MyApplication.runOnUiThread(() -> {
if (mCloseRefreshDia != null){
mCloseRefreshDia.show();
return;
}
initmBooks();
if (mBooks.size() == 0){
ToastUtils.showWarring("当前书架没有支持禁用更新的书籍!");
return;
}
boolean[] isCloseRefresh = new boolean[booksCount];
int crBookCount = 0;
for (int i = 0; i < booksCount; i++) {
Book book = mBooks.get(i);
isCloseRefresh[i] = book.getIsCloseUpdate();
if (isCloseRefresh[i]){
crBookCount++;
}
}
mCloseRefreshDia = new MultiChoiceDialog().create(this, "禁用更新的书籍",
mBooksName, isCloseRefresh, crBookCount, (dialog, which) -> {
BookService.getInstance().updateBooks(mBooks);
}, null, new DialogCreator.OnMultiDialogListener() {
@Override
public void onItemClick(DialogInterface dialog, int which, boolean isChecked) {
mBooks.get(which).setIsCloseUpdate(isChecked);
}
@Override
public void onSelectAll(boolean isSelectAll) {
for (Book book : mBooks){
book.setIsCloseUpdate(isSelectAll);
}
}
});
});
});
mRlMatchChapter.setOnClickListener(
(v) -> {
if (isMatchChapter) {
isMatchChapter = false;
mRlMatchChapterSuitability.setVisibility(View.GONE);
} else {
isMatchChapter = true;
mRlMatchChapterSuitability.setVisibility(View.VISIBLE);
}
mScMatchChapter.setChecked(isMatchChapter);
mSetting.setMatchChapter(isMatchChapter);
SysManager.saveSetting(mSetting);
}
);
mLlDownloadAll.setOnClickListener(v -> {
MyApplication.runOnUiThread(() -> {
if (mDownloadAllDia != null){
mDownloadAllDia.show();
return;
}
initmBooks();
if (mBooks.size() == 0){
ToastUtils.showWarring("当前书架没有支持缓存的书籍!");
return;
}
int booksCount = mBooks.size();
CharSequence[] mBooksName = new CharSequence[booksCount];
boolean[] isDownloadAll = new boolean[booksCount];
int daBookCount = 0;
for (int i = 0; i < booksCount; i++) {
Book book = mBooks.get(i);
mBooksName[i] = book.getName();
isDownloadAll[i] = book.getIsDownLoadAll();
if (isDownloadAll[i]){
daBookCount++;
}
}
mDownloadAllDia = new MultiChoiceDialog().create(this, "一键缓存的书籍",
mBooksName, isDownloadAll, daBookCount, (dialog, which) -> {
BookService.getInstance().updateBooks(mBooks);
}, null, new DialogCreator.OnMultiDialogListener() {
@Override
public void onItemClick(DialogInterface dialog, int which, boolean isChecked) {
mBooks.get(which).setIsDownLoadAll(isChecked);
}
@Override
public void onSelectAll(boolean isSelectAll) {
for (Book book : mBooks){
book.setIsDownLoadAll(isSelectAll);
}
}
});
});
});
mIvMatchChapterTip.setOnClickListener(v -> DialogCreator.createTipDialog(this, "智能匹配", getString(R.string.match_chapter_tip)));
mRlMatchChapterSuitability.setOnClickListener(v -> mScMatchChapterSuitability.performClick());
mRlResetScreen.setOnClickListener(v -> mScResetScreen.performClick());
mRlCatheGap.setOnClickListener(v -> mScCatheGap.performClick());
mRlDeleteCathe.setOnClickListener(v -> {
DialogCreator.createCommonDialog(this, "清除缓存", "确定要清除全部书籍缓存吗?",
true, (dialog, which) -> {
BookService.getInstance().deleteAllBookCathe();
ToastUtils.showSuccess("清除缓存成功!");
}, null);
});
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initSpinner();
}
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);
mScResetScreen.setAdapter(resetScreenAdapter);
int resetScreenSelection = 0;
switch (resetScreenTime) {
case 0:
resetScreenSelection = 0;
break;
case 1:
resetScreenSelection = 1;
break;
case 3:
resetScreenSelection = 2;
break;
case 5:
resetScreenSelection = 3;
break;
}
mScResetScreen.setSelection(resetScreenSelection);
mScResetScreen.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
switch (position) {
case 0:
resetScreenTime = 0;
break;
case 1:
resetScreenTime = 1;
break;
case 2:
resetScreenTime = 3;
break;
case 3:
resetScreenTime = 5;
break;
}
mSetting.setResetScreen(resetScreenTime);
SysManager.saveSetting(mSetting);
Intent result = new Intent();
result.putExtra(APPCONST.RESULT_RESET_SCREEN, resetScreenTime);
setResult(AppCompatActivity.RESULT_OK, result);
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
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);
mScMatchChapterSuitability.setAdapter(matchSuiAdapter);
if (matchChapterSuitability == 0.0) {
matchChapterSuitability = 0.7f;
mSetting.setMatchChapterSuitability(matchChapterSuitability);
SysManager.saveSetting(mSetting);
}
int matchSuiSelection = (int) (matchChapterSuitability * 10 - 5);
mScMatchChapterSuitability.setSelection(matchSuiSelection);
mScMatchChapterSuitability.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
matchChapterSuitability = (position + 5) * 1f / 10f;
mSetting.setMatchChapterSuitability(matchChapterSuitability);
SysManager.saveSetting(mSetting);
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
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);
mScCatheGap.setAdapter(catheGapAdapter);
if (catheCap == 0) {
catheCap = 150;
mSetting.setCatheGap(catheCap);
SysManager.saveSetting(mSetting);
}
int catheGapSelection = catheCap / 50 - 1;
mScCatheGap.setSelection(catheGapSelection);
mScCatheGap.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
catheCap = (position + 1) * 50;
mSetting.setCatheGap(catheCap);
SysManager.saveSetting(mSetting);
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
}
private void initmBooks(){
if (mBooks != null) {
return;
}
mBooks = (ArrayList<Book>) BookService.getInstance().getAllBooks();
Iterator<Book> mBooksIter = mBooks.iterator();
while (mBooksIter.hasNext()){
Book book = mBooksIter.next();
if ("本地书籍".equals(book.getType())) {
mBooksIter.remove();
}
}
booksCount = mBooks.size();
mBooksName = new CharSequence[booksCount];
for (int i = 0; i < booksCount; i++) {
Book book = mBooks.get(i);
mBooksName[i] = book.getName();
}
}
}

@ -98,12 +98,9 @@ public class ReadActivity extends BaseActivity {
exit();
}
}
, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
mReadPresenter.deleteBook();
exit();
}
, (dialog, which) -> {
mReadPresenter.deleteBook();
exit();
});
} else {
mReadPresenter.saveLastChapterReadPosition();
@ -117,6 +114,7 @@ public class ReadActivity extends BaseActivity {
result.putExtra(APPCONST.RESULT_IS_COLLECTED, mReadPresenter.isCollected());
if (mReadPresenter.getmPageLoader() != null) {
result.putExtra(APPCONST.RESULT_LAST_READ_POSITION, mReadPresenter.getmPageLoader().getPagePos());
result.putExtra(APPCONST.RESULT_HISTORY_CHAPTER, mReadPresenter.getmPageLoader().getChapterPos());
}
setResult(AppCompatActivity.RESULT_OK, result);
super.onBackPressed();

@ -46,7 +46,7 @@ public class RegisterActivity extends BaseActivity{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_register);
ButterKnife.bind(this);
setStatusBar(R.color.sys_line);
setStatusBar(R.color.white, false);
mRegisterPresenter = new RegisterPresenter(this);
mRegisterPresenter.start();
}

@ -60,7 +60,7 @@ public class SearchBookActivity extends BaseActivity {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_search_book);
ButterKnife.bind(this);
setStatusBar(R.color.sys_line);
setStatusBar(R.color.white, false);
mSearchBookPrensenter = new SearchBookPrensenter(this);
mSearchBookPrensenter.start();
}

@ -11,9 +11,8 @@ import androidx.core.app.ActivityCompat;
import android.view.Window;
import android.view.WindowManager;
import xyz.fycz.myreader.R;
import xyz.fycz.myreader.ui.activity.MainActivity;
import xyz.fycz.myreader.util.PermissionsChecker;
import xyz.fycz.myreader.util.TextHelper;
import xyz.fycz.myreader.util.ToastUtils;
public class SplashActivity extends AppCompatActivity {
/*************Constant**********/
@ -89,7 +88,7 @@ public class SplashActivity extends AppCompatActivity {
} else {
//申请权限失败
finish();
TextHelper.showText("请给予储存权限,否则程序无法正常运行!");
ToastUtils.showWarring("请给予储存权限,否则程序无法正常运行!");
}
return;
}

@ -58,18 +58,17 @@ public class BookMarkAdapter extends ArrayAdapter<BookMark> {
private void initView(int postion,final ViewHolder viewHolder){
final BookMark bookMark = getItem(postion);
// viewHolder.tvTitle.setText("【" + chapter.getTitle() + "】");
viewHolder.tvTitle.setText(bookMark.getTitle() + "[" + (bookMark.getBookMarkReadPosition() + 1) + "]");
if (ChapterService.isChapterCached(bookMark.getBookId(), bookMark.getTitle())){
viewHolder.tvTitle.setCompoundDrawablesWithIntrinsicBounds(getContext().getResources().getDrawable(R.drawable.selector_category_load),null,null,null);
} else {
viewHolder.tvTitle.setCompoundDrawablesWithIntrinsicBounds(getContext().getResources().getDrawable(R.drawable.selector_category_unload),null,null,null);
}
if (setting.isDayStyle()) {
viewHolder.tvTitle.setTextColor(getContext().getResources().getColor(setting.getReadWordColor()));
}else {
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));
}
}
@ -111,6 +110,7 @@ public class BookMarkAdapter extends ArrayAdapter<BookMark> {
}
};
}
class ViewHolder{
TextView tvTitle;

@ -64,15 +64,12 @@ public class BookStoreBookTypeAdapter extends RecyclerView.Adapter<BookStoreBook
if (onItemClickListener != null) {
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
holder.itemView.setOnClickListener(view -> {
onItemClickListener.onClick(position, view);
selectPos = position;
BookStoreBookTypeAdapter.this.notifyDataSetChanged();
onItemClickListener.onClick(position, view);
selectPos = position;
BookStoreBookTypeAdapter.this.notifyDataSetChanged();
}
});
}

@ -28,7 +28,7 @@ import xyz.fycz.myreader.greendao.entity.Chapter;
import xyz.fycz.myreader.greendao.service.BookService;
import xyz.fycz.myreader.greendao.service.ChapterService;
import xyz.fycz.myreader.ui.presenter.BookcasePresenter;
import xyz.fycz.myreader.util.TextHelper;
import xyz.fycz.myreader.util.ToastUtils;
import xyz.fycz.myreader.util.utils.FileUtils;
import xyz.fycz.myreader.util.utils.NetworkUtils;
import xyz.fycz.myreader.widget.BadgeView;
@ -47,7 +47,7 @@ public abstract class BookcaseAdapter extends DragAdapter {
protected BookService mBookService;
protected ChapterService mChapterService;
protected BookcasePresenter mBookcasePresenter;
protected final String[] menu = {
protected String[] menu = {
MyApplication.getmContext().getResources().getString(R.string.menu_book_Top),
MyApplication.getmContext().getResources().getString(R.string.menu_book_download),
MyApplication.getmContext().getResources().getString(R.string.menu_book_cache),
@ -92,6 +92,7 @@ public abstract class BookcaseAdapter extends DragAdapter {
return list.get(position).getSortCode();
}
public void remove(Book item) {
list.remove(item);
notifyDataSetChanged();
@ -171,11 +172,11 @@ public abstract class BookcaseAdapter extends DragAdapter {
protected void downloadBook(final Book book) {
if (!NetworkUtils.isNetWorkAvailable()) {
TextHelper.showText("无网络连接!");
ToastUtils.showWarring("无网络连接!");
return;
}
if ("本地书籍".equals(book.getType())){
TextHelper.showText("《" + book.getName() + "》是本地书籍,不能缓存");
ToastUtils.showWarring("《" + book.getName() + "》是本地书籍,不能缓存");
return;
}
final int[] begin = new int[1];

@ -27,7 +27,7 @@ import xyz.fycz.myreader.ui.activity.BookDetailedActivity;
import xyz.fycz.myreader.ui.activity.ReadActivity;
import xyz.fycz.myreader.ui.presenter.BookcasePresenter;
import xyz.fycz.myreader.util.StringHelper;
import xyz.fycz.myreader.util.TextHelper;
import xyz.fycz.myreader.util.ToastUtils;
/**
@ -79,8 +79,9 @@ public class BookcaseDetailedAdapter extends BookcaseAdapter {
.into(viewHolder.ivBookImg);
viewHolder.tvBookName.setText(book.getName());
viewHolder.tvBookAuthor.setText(book.getAuthor());
viewHolder.ivDelete.setOnClickListener(v -> showDeleteBookDialog(book));
viewHolder.tvBookAuthor.setText(book.getAuthor());
viewHolder.tvHistoryChapter.setText(book.getHistoryChapterId());
assert book.getNewestChapterTitle() != null;
viewHolder.tvNewestChapter.setText(book.getNewestChapterTitle().replace("最近更新 ", ""));
@ -122,7 +123,6 @@ public class BookcaseDetailedAdapter extends BookcaseAdapter {
viewHolder.llBookRead.setOnClickListener(v -> {
Intent intent = new Intent(mContext, ReadActivity.class);
intent.putExtra(APPCONST.BOOK, book);
book.setNoReadNum(0);
mBookService.updateEntity(book);
mContext.startActivity(intent);
});
@ -141,9 +141,9 @@ public class BookcaseDetailedAdapter extends BookcaseAdapter {
switch (which) {
case 0:
book.setSortCode(0);
mBookService.updateBook(book);
mBookService.updateEntity(book);
mBookcasePresenter.init();
TextHelper.showText("书籍《" + book.getName() + "》移至顶部成功!");
ToastUtils.showSuccess("书籍《" + book.getName() + "》移至顶部成功!");
break;
case 1:
downloadBook(book);

@ -22,16 +22,22 @@ import xyz.fycz.myreader.application.MyApplication;
import xyz.fycz.myreader.common.APPCONST;
import xyz.fycz.myreader.creator.DialogCreator;
import xyz.fycz.myreader.greendao.entity.Book;
import xyz.fycz.myreader.ui.activity.BookDetailedActivity;
import xyz.fycz.myreader.ui.activity.ReadActivity;
import xyz.fycz.myreader.ui.presenter.BookcasePresenter;
import xyz.fycz.myreader.util.StringHelper;
import xyz.fycz.myreader.util.TextHelper;
import xyz.fycz.myreader.util.ToastUtils;
public class BookcaseDragAdapter extends BookcaseAdapter {
ViewHolder viewHolder = null;
protected String[] menu = {
MyApplication.getmContext().getResources().getString(R.string.menu_book_detail),
MyApplication.getmContext().getResources().getString(R.string.menu_book_Top),
MyApplication.getmContext().getResources().getString(R.string.menu_book_download),
MyApplication.getmContext().getResources().getString(R.string.menu_book_cache),
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);
@ -40,7 +46,6 @@ public class BookcaseDragAdapter extends BookcaseAdapter {
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder = null;
if (convertView == null || convertView.getTag() instanceof BookcaseDetailedAdapter.ViewHolder) {
viewHolder = new ViewHolder();
convertView = LayoutInflater.from(mContext).inflate(mResourceId, null);
@ -53,11 +58,11 @@ public class BookcaseDragAdapter extends BookcaseAdapter {
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
initView(position, viewHolder);
initView(position);
return convertView;
}
private void initView(int position, ViewHolder viewHolder) {
private void initView(int position) {
final Book book = getItem(position);
if (StringHelper.isEmpty(book.getImgUrl())) {
book.setImgUrl("");
@ -72,12 +77,7 @@ public class BookcaseDragAdapter extends BookcaseAdapter {
.into(viewHolder.ivBookImg);
viewHolder.tvBookName.setText(book.getName());
viewHolder.ivDelete.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
showDeleteBookDialog(book);
}
});
viewHolder.ivDelete.setOnClickListener(v -> showDeleteBookDialog(book));
if (mEditState) {
@ -90,99 +90,95 @@ public class BookcaseDragAdapter extends BookcaseAdapter {
boolean isLoading = false;
try {
isLoading = isBookLoading(book.getId());
}catch (Exception ignored){
} catch (Exception ignored) {
}
if (isLoading){
if (isLoading) {
viewHolder.pbLoading.setVisibility(View.VISIBLE);
viewHolder.tvNoReadNum.setVisibility(View.GONE);
}else {
} else {
viewHolder.pbLoading.setVisibility(View.GONE);
int notReadNum = book.getChapterTotalNum() - book.getHisttoryChapterNum() + book.getNoReadNum() - 1;
if (notReadNum != 0){
if (notReadNum != 0) {
viewHolder.tvNoReadNum.setVisibility(View.VISIBLE);
if(book.getNoReadNum() != 0){
if (book.getNoReadNum() != 0) {
viewHolder.tvNoReadNum.setHighlight(true);
if (notReadNum == -1){
if (notReadNum == -1) {
notReadNum = book.getNoReadNum() - 1;
}
}else {
} else {
viewHolder.tvNoReadNum.setHighlight(false);
}
viewHolder.tvNoReadNum.setBadgeCount(notReadNum);
}else {
} else {
viewHolder.tvNoReadNum.setVisibility(View.GONE);
}
}
viewHolder.ivBookImg.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent( mContext, ReadActivity.class);
intent.putExtra(APPCONST.BOOK, book);
book.setNoReadNum(0);
mBookService.updateEntity(book);
mContext.startActivity(intent);
}
viewHolder.ivBookImg.setOnClickListener(v -> {
Intent intent = new Intent(mContext, ReadActivity.class);
intent.putExtra(APPCONST.BOOK, book);
mBookService.updateEntity(book);
mContext.startActivity(intent);
});
viewHolder.ivBookImg.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
if (!ismEditState()){
AlertDialog bookDialog = new AlertDialog.Builder(mContext)
.setTitle(book.getName())
.setAdapter(new ArrayAdapter<>(mContext,
android.R.layout.simple_list_item_1, menu),
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
switch (which) {
case 0:
book.setSortCode(0);
mBookService.updateBook(book);
mBookcasePresenter.init();
TextHelper.showText("书籍《" + book.getName() + "》移至顶部成功!");
break;
case 1:
downloadBook(book);
break;
case 2:
MyApplication.getApplication().newThread(new Runnable() {
@Override
public void run() {
try {
if (unionChapterCathe(book)) {
DialogCreator.createTipDialog(mContext,
"缓存导出成功,导出目录:"
+ APPCONST.TXT_BOOK_DIR);
}else {
DialogCreator.createTipDialog(mContext,
"章节目录为空或未找到缓存文件,缓存导出失败!");
}
} catch (IOException e) {
e.printStackTrace();
DialogCreator.createTipDialog(mContext,
"章节目录为空或未找到缓存文件,缓存导出失败!");
}
viewHolder.ivBookImg.setOnLongClickListener(v -> {
if (!ismEditState()) {
AlertDialog bookDialog = new AlertDialog.Builder(mContext)
.setTitle(book.getName())
.setAdapter(new ArrayAdapter<>(mContext,
android.R.layout.simple_list_item_1, menu),
(dialog, which) -> {
switch (which) {
case 0:
Intent intent = new Intent(mContext, BookDetailedActivity.class);
intent.putExtra(APPCONST.BOOK, book);
mContext.startActivity(intent);
break;
case 1:
book.setSortCode(0);
mBookService.updateEntity(book);
mBookcasePresenter.init();
ToastUtils.showSuccess("书籍《" + book.getName() + "》移至顶部成功!");
break;
case 2:
downloadBook(book);
break;
case 3:
MyApplication.getApplication().newThread(new Runnable() {
@Override
public void run() {
try {
if (unionChapterCathe(book)) {
DialogCreator.createTipDialog(mContext,
"缓存导出成功,导出目录:"
+ APPCONST.TXT_BOOK_DIR);
} else {
DialogCreator.createTipDialog(mContext,
"章节目录为空或未找到缓存文件,缓存导出失败!");
}
});
break;
case 3:
showDeleteBookDialog(book);
break;
}
}
})
.setNegativeButton(null, null)
.setPositiveButton(null, null)
.create();
bookDialog.show();
return true;
}
return false;
} catch (IOException e) {
e.printStackTrace();
DialogCreator.createTipDialog(mContext,
"章节目录为空或未找到缓存文件,缓存导出失败!");
}
}
});
break;
case 4:
showDeleteBookDialog(book);
break;
}
})
.setNegativeButton(null, null)
.setPositiveButton(null, null)
.create();
bookDialog.show();
return true;
}
return false;
});
}
}
class ViewHolder extends BookcaseAdapter.ViewHolder {
}
}

@ -71,11 +71,11 @@ 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().getResources().getColor(setting.getReadWordColor()));
} else {
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()) {

@ -34,10 +34,12 @@ import xyz.fycz.myreader.common.URLCONST;
import xyz.fycz.myreader.entity.Setting;
import xyz.fycz.myreader.enums.Font;
import xyz.fycz.myreader.ui.activity.FontsActivity;
import xyz.fycz.myreader.util.TextHelper;
import xyz.fycz.myreader.util.IOUtils;
import xyz.fycz.myreader.util.ToastUtils;
import xyz.fycz.myreader.util.utils.FileUtils;
import xyz.fycz.myreader.util.utils.NetworkUtils;
import xyz.fycz.myreader.webapi.CommonApi;
import xyz.fycz.myreader.widget.ProgressButton;
public class FontsAdapter extends ArrayAdapter<Font> {
@ -56,7 +58,7 @@ public class FontsAdapter extends ArrayAdapter<Font> {
break;
case 2:
Font font = (Font) msg.obj;
TextHelper.showText(font.toString() + "字体下载完成");
ToastUtils.showSuccess(font.toString() + "字体下载完成");
notifyDataSetChanged();
break;
case 3:
@ -92,7 +94,7 @@ public class FontsAdapter extends ArrayAdapter<Font> {
viewHolder = new ViewHolder();
convertView = LayoutInflater.from(getContext()).inflate(mResourceId, null);
viewHolder.tvFontName = (TextView) convertView.findViewById(R.id.tv_font_name);
viewHolder.btnFontUse = (Button) convertView.findViewById(R.id.btn_font_use);
viewHolder.btnFontUse = (ProgressButton) convertView.findViewById(R.id.btn_font_use);
//viewHolder.tvExample = (TextView)convertView.findViewById(R.id.tv_font_example);
convertView.setTag(viewHolder);
} else {
@ -121,8 +123,10 @@ public class FontsAdapter extends ArrayAdapter<Font> {
if (setting.getFont() == Font.本地字体) {
viewHolder.tvFontName.setText(setting.getLocalFontName());
viewHolder.btnFontUse.setText(getContext().getString(R.string.font_change));
viewHolder.btnFontUse.setButtonColor(mFontsActivity.getColor(R.color.toast_blue));
} else {
viewHolder.btnFontUse.setText(getContext().getString(R.string.font_select));
viewHolder.btnFontUse.setButtonColor(mFontsActivity.getColor(R.color.sys_blue_littler));
}
viewHolder.btnFontUse.setEnabled(true);
viewHolder.btnFontUse.setOnClickListener(new View.OnClickListener() {
@ -159,7 +163,7 @@ public class FontsAdapter extends ArrayAdapter<Font> {
}
}).create();
dialog.show();*/
TextHelper.showText("请选择一个ttf格式的字体文件");
ToastUtils.showInfo("请选择一个ttf格式的字体文件");
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("*/*");
intent.addCategory(Intent.CATEGORY_OPENABLE);
@ -171,37 +175,34 @@ public class FontsAdapter extends ArrayAdapter<Font> {
if (font != Font.默认字体 && !fontFile.exists()) {
viewHolder.btnFontUse.setEnabled(true);
viewHolder.btnFontUse.setButtonColor(mFontsActivity.getColor(R.color.sys_blue_littler));
viewHolder.btnFontUse.setText(getContext().getString(R.string.font_download));
viewHolder.btnFontUse.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
viewHolder.btnFontUse.setEnabled(false);
addDownloadFont(font, viewHolder);
}
viewHolder.btnFontUse.setOnClickListener(v -> {
viewHolder.btnFontUse.setEnabled(false);
addDownloadFont(font, viewHolder);
});
} else if (setting.getFont() == font) {
viewHolder.btnFontUse.setText(getContext().getString(R.string.font_using));
viewHolder.btnFontUse.setEnabled(false);
viewHolder.btnFontUse.setButtonColor(mFontsActivity.getColor(R.color.sys_word_very_little));
} else {
viewHolder.btnFontUse.setText(getContext().getString(R.string.font_use));
viewHolder.btnFontUse.setEnabled(true);
viewHolder.btnFontUse.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
setting.setFont(font);
SysManager.saveSetting(setting);
notifyDataSetChanged();
Intent intent = new Intent();
intent.putExtra(APPCONST.FONT, font);
((Activity) getContext()).setResult(Activity.RESULT_OK, intent);
}
viewHolder.btnFontUse.setButtonColor(mFontsActivity.getColor(R.color.toast_blue));
viewHolder.btnFontUse.setOnClickListener(v -> {
setting.setFont(font);
SysManager.saveSetting(setting);
notifyDataSetChanged();
Intent intent = new Intent();
intent.putExtra(APPCONST.FONT, font);
((Activity) getContext()).setResult(Activity.RESULT_OK, intent);
});
}
}
private void addDownloadFont(final Font font, final ViewHolder viewHolder) {
if (!NetworkUtils.isNetWorkAvailable()) {
TextHelper.showText("无网络连接!");
ToastUtils.showWarring("无网络连接!");
mHandler.sendMessage(mHandler.obtainMessage(3));
return;
}
@ -225,78 +226,63 @@ public class FontsAdapter extends ArrayAdapter<Font> {
}
private void downloadFont(final String url, final Font font, final ViewHolder viewHolder) {
MyApplication.getApplication().newThread(new Runnable() {
@Override
public void run() {
HttpURLConnection con = null;
InputStream is = null;
FileOutputStream fos = null;
File fontFile = null;
try {
URL webUrl = new URL(url);
mHandler.sendMessage(mHandler.obtainMessage(4, viewHolder));
con = (HttpURLConnection) webUrl.openConnection();
is = con.getInputStream();
int fileLength = con.getContentLength();
String filePath = APPCONST.FONT_BOOK_DIR + font.fileName + ".temp";
fontFile = FileUtils.getFile(filePath);
fos = new FileOutputStream(fontFile);
byte[] tem = new byte[1024];
int len = 0;
int alreadyLen = 0;
while ((len = is.read(tem)) != -1) {
fos.write(tem, 0, len);
alreadyLen += len;
mHandler.sendMessage(mHandler.obtainMessage(1, alreadyLen, fileLength, viewHolder));
}
fos.flush();
if (fileLength == fontFile.length()) {
String newPath = filePath.replace(".temp", "");
File newFile = new File(newPath);
if (fontFile.renameTo(newFile)) {
mHandler.sendMessage(mHandler.obtainMessage(2, font));
} else {
TextHelper.showText(font.toString() + "字体下载失败!");
fontFile.delete();
mHandler.sendMessage(mHandler.obtainMessage(3));
}
MyApplication.getApplication().newThread(() -> {
HttpURLConnection con = null;
InputStream is = null;
FileOutputStream fos = null;
File fontFile = null;
try {
URL webUrl = new URL(url);
mHandler.sendMessage(mHandler.obtainMessage(4, viewHolder));
con = (HttpURLConnection) webUrl.openConnection();
is = con.getInputStream();
int fileLength = con.getContentLength();
String filePath = APPCONST.FONT_BOOK_DIR + font.fileName + ".temp";
fontFile = FileUtils.getFile(filePath);
fos = new FileOutputStream(fontFile);
byte[] tem = new byte[1024];
int len = 0;
int alreadyLen = 0;
while ((len = is.read(tem)) != -1) {
fos.write(tem, 0, len);
alreadyLen += len;
mHandler.sendMessage(mHandler.obtainMessage(1, alreadyLen, fileLength, viewHolder));
}
fos.flush();
if (fileLength == fontFile.length()) {
String newPath = filePath.replace(".temp", "");
File newFile = new File(newPath);
if (fontFile.renameTo(newFile)) {
mHandler.sendMessage(mHandler.obtainMessage(2, font));
} else {
TextHelper.showText(font.toString() + "字体下载失败!");
ToastUtils.showError(font.toString() + "字体下载失败!(Error:fontFile.renameTo(newFile))");
fontFile.delete();
mHandler.sendMessage(mHandler.obtainMessage(3));
}
} catch (IOException e) {
TextHelper.showText(font.toString() + "字体下载失败!");
if (fontFile != null) {
fontFile.delete();
}
} else {
ToastUtils.showError(font.toString() + "字体下载失败!(Error:fileLength == fontFile.length())");
fontFile.delete();
mHandler.sendMessage(mHandler.obtainMessage(3));
e.printStackTrace();
} finally {
if (con != null) {
con.disconnect();
}
if (is != null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fos != null) {
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
} catch (IOException e) {
ToastUtils.showError(font.toString() + "字体下载失败!\n" + e.getLocalizedMessage());
if (fontFile != null) {
fontFile.delete();
}
mHandler.sendMessage(mHandler.obtainMessage(3));
e.printStackTrace();
} finally {
if (con != null) {
con.disconnect();
}
IOUtils.close(is, fos);
}
});
}
private void updateDownloadPro(int alreadyLen, int fileLen, ViewHolder viewHolder) {
int process = alreadyLen * 100 / fileLen;
viewHolder.btnFontUse.setProgress(process);
viewHolder.btnFontUse.setText(process + "%");
viewHolder.btnFontUse.setEnabled(false);
}
@ -338,7 +324,7 @@ public class FontsAdapter extends ArrayAdapter<Font> {
class ViewHolder {
//TextView tvExample;
TextView tvFontName;
Button btnFontUse;
ProgressButton btnFontUse;
}
}

@ -1,5 +1,6 @@
package xyz.fycz.myreader.ui.adapter;
import android.app.Activity;
import android.content.Context;
import android.os.Handler;
import android.view.LayoutInflater;
@ -14,6 +15,7 @@ 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.callback.ResultCallback;
import xyz.fycz.myreader.webapi.crawler.BookInfoCrawler;
import xyz.fycz.myreader.webapi.crawler.ReadCrawler;
@ -155,14 +157,16 @@ public class SearchBookAdapter extends DragAdapter {
private void initOtherInfo(final int position, final ViewHolder holder){
Book book = mBooks.getValue(getItem(position), 0);
//图片
Glide.with(mContext)
.load(book.getImgUrl())
if (!MyApplication.isDestroy((Activity) mContext)) {
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);
.error(R.mipmap.no_image)
.placeholder(R.mipmap.no_image)
//设置圆角
.apply(RequestOptions.bitmapTransform(new RoundedCorners(8)))
.into(holder.ivBookImg);
}
//简介
holder.tvDesc.setText("简介:" + book.getDesc());
holder.tvType.setText(book.getType());

@ -13,7 +13,7 @@ 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.TextHelper;
import xyz.fycz.myreader.util.ToastUtils;
/**
* @author fengyue
@ -40,7 +40,7 @@ public class AboutPresenter implements BasePresenter {
//把数据设置到剪切板上
assert mClipboardManager != null;
mClipboardManager.setPrimaryClip(mClipData);
TextHelper.showText("邮箱复制成功!");
ToastUtils.showSuccess("邮箱复制成功!");
});
mAboutActivity.getVmShare().setOnClickListener(v -> ShareUtils.share(mAboutActivity, mAboutActivity.getString(R.string.share_text) +
SharedPreUtils.getInstance().getString("downloadLink")));
@ -56,7 +56,7 @@ public class AboutPresenter implements BasePresenter {
intent.setData(Uri.parse(address));
mAboutActivity.startActivity(intent);
} catch (Exception e) {
TextHelper.showText(e.getLocalizedMessage());
ToastUtils.showError(e.getLocalizedMessage());
}
}
}

@ -20,7 +20,7 @@ import xyz.fycz.myreader.ui.activity.MainActivity;
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.TextHelper;
import xyz.fycz.myreader.util.ToastUtils;
import xyz.fycz.myreader.webapi.BookStoreApi;
@ -108,7 +108,7 @@ public class BookStorePresenter implements BasePresenter {
@Override
public void onError(Exception e) {
TextHelper.showText(e.getMessage());
ToastUtils.showError(e.getMessage());
}
});
@ -128,7 +128,7 @@ public class BookStorePresenter implements BasePresenter {
@Override
public void onError(Exception e) {
TextHelper.showText(e.getMessage());
ToastUtils.showError(e.getMessage());
}
});

@ -35,6 +35,7 @@ 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.ui.activity.*;
import xyz.fycz.myreader.webapi.crawler.ReadCrawler;
import xyz.fycz.myreader.webapi.crawler.ReadCrawlerUtil;
import xyz.fycz.myreader.creator.DialogCreator;
@ -46,11 +47,6 @@ import xyz.fycz.myreader.greendao.entity.Book;
import xyz.fycz.myreader.greendao.entity.Chapter;
import xyz.fycz.myreader.greendao.service.BookService;
import xyz.fycz.myreader.greendao.service.ChapterService;
import xyz.fycz.myreader.ui.activity.AboutActivity;
import xyz.fycz.myreader.ui.activity.FileSystemActivity;
import xyz.fycz.myreader.ui.activity.MainActivity;
import xyz.fycz.myreader.ui.activity.SearchBookActivity;
import xyz.fycz.myreader.ui.activity.LoginActivity;
import xyz.fycz.myreader.ui.adapter.BookcaseAdapter;
import xyz.fycz.myreader.ui.adapter.BookcaseDetailedAdapter;
import xyz.fycz.myreader.ui.adapter.BookcaseDragAdapter;
@ -89,11 +85,14 @@ public class BookcasePresenter implements BasePresenter {
private static boolean isStopDownload = true;//是否停止下载
private int curCacheChapterNum;//当前下载的章节数
private int needCacheChapterNum;//需要下载的章节数
private int successCathe;//成功章节数
private int errorCathe;//失败章节数
private int tempCacheChapterNum;//上次下载的章节数
private int tempCount;//下载超时时间
private int downloadInterval = 150;//下载间隔
private Runnable sendDownloadNotification;//发送通知的线程
private PopupMenu pm;//菜单
private boolean isFirstRefresh = true;//是否首次进入刷新
public static final String CANCEL_ACTION = "cancelAction";
@ -132,6 +131,10 @@ public class BookcasePresenter implements BasePresenter {
case 4:
showErrorLoadingBooks();
if (MyApplication.isApkInDebug(mMainActivity)) {
if (isFirstRefresh) {
initBook();
isFirstRefresh = false;
}
downloadAll(false);
}
break;
@ -160,7 +163,7 @@ public class BookcasePresenter implements BasePresenter {
MyApplication.runOnUiThread(() -> createMenu());
break;
case 12:
TextHelper.showText("正在后台缓存书籍,具体进度可查看通知栏!");
ToastUtils.showInfo("正在后台缓存书籍,具体进度可查看通知栏!");
notificationUtil.requestNotificationPermissionDialog(mMainActivity);
break;
}
@ -183,14 +186,16 @@ public class BookcasePresenter implements BasePresenter {
if (mSetting.getBookcaseStyle() == null) {
mSetting.setBookcaseStyle(BookcaseStyle.listMode);
}
if (mSetting.isAutoSyn() && UserService.isLogin()) {
synBookcaseToWeb(true);
}
sendDownloadNotification = this::sendNotification;
notificationUtil = NotificationUtil.getInstance();
getData();
if (mSetting.isAutoSyn() && UserService.isLogin()) {
synBookcaseToWeb(true);
}
//是否启用下拉刷新(默认启用)
if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
mBookcaseFragment.getSrlContent().setEnableRefresh(false);
@ -242,7 +247,7 @@ public class BookcasePresenter implements BasePresenter {
mMainActivity.getIvMore().setVisibility(View.GONE);
// VibratorUtil.Vibrate(mBookcaseFragment.getActivity(), 100);
} else {
TextHelper.showText("当前无任何书籍,无法编辑书架!");
ToastUtils.showWarring("当前无任何书籍,无法编辑书架!");
}
} else {
mMainActivity.getRlCommonTitle().setVisibility(View.VISIBLE);
@ -291,7 +296,9 @@ public class BookcasePresenter implements BasePresenter {
public void getData() {
init();
initNoReadNum();
if (mSetting.isRefreshWhenStart() || android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
initNoReadNum();
}
}
private void initBook() {
@ -315,7 +322,7 @@ public class BookcasePresenter implements BasePresenter {
mHandler.sendMessage(mHandler.obtainMessage(3));
}
for (final Book book : mBooks) {
if ("本地书籍".equals(book.getType())) {
if ("本地书籍".equals(book.getType()) || book.getIsCloseUpdate()) {
mBookcaseAdapter.getIsLoading().put(book.getId(), false);
mHandler.sendMessage(mHandler.obtainMessage(1));
continue;
@ -326,12 +333,12 @@ public class BookcasePresenter implements BasePresenter {
CommonApi.getBookChapters(book.getChapterUrl(), mReadCrawler, new ResultCallback() {
@Override
public void onFinish(Object o, int code) {
final ArrayList<Chapter> chapters = (ArrayList<Chapter>) o;
ArrayList<Chapter> chapters = (ArrayList<Chapter>) o;
int noReadNum = chapters.size() - book.getChapterTotalNum();
book.setNoReadNum(Math.max(noReadNum, 0));
book.setNewestChapterTitle(chapters.get(chapters.size() - 1).getTitle());
mBookcaseAdapter.getIsLoading().put(book.getId(), false);
updateAllOldChapterData(mChapters, chapters, book.getId());
mChapterService.updateAllOldChapterData(mChapters, chapters, book.getId());
mHandler.sendMessage(mHandler.obtainMessage(1));
mBookService.updateEntity(book);
}
@ -350,46 +357,13 @@ public class BookcasePresenter implements BasePresenter {
while (true) {
if (finishLoadBookCount == mBooks.size()) {
mHandler.sendMessage(mHandler.obtainMessage(4));
mHandler.sendMessage(mHandler.obtainMessage(2));
break;
}
}
});
}
/**
* 更新所有章节
*
* @param newChapters
*/
private void updateAllOldChapterData(ArrayList<Chapter> mChapters, ArrayList<Chapter> newChapters, String bookId) {
int i;
for (i = 0; i < mChapters.size() && i < newChapters.size(); i++) {
Chapter oldChapter = mChapters.get(i);
Chapter newChapter = newChapters.get(i);
if (!oldChapter.getTitle().equals(newChapter.getTitle())) {
oldChapter.setTitle(newChapter.getTitle());
oldChapter.setUrl(newChapter.getUrl());
oldChapter.setContent(null);
mChapterService.saveOrUpdateChapter(oldChapter, null);
}
}
if (mChapters.size() < newChapters.size()) {
int start = mChapters.size();
for (int j = mChapters.size(); j < newChapters.size(); j++) {
newChapters.get(j).setId(StringHelper.getStringRandom(25));
newChapters.get(j).setBookId(bookId);
mChapters.add(newChapters.get(j));
// mChapterService.addChapter(newChapters.get(j));
}
mChapterService.addChapters(mChapters.subList(start, mChapters.size()));
} else if (mChapters.size() > newChapters.size()) {
for (int j = newChapters.size(); j < mChapters.size(); j++) {
mChapterService.deleteEntity(mChapters.get(j));
mChapterService.deleteChapterCacheFile(mChapters.get(j));
}
mChapters.subList(0, newChapters.size());
}
}
private void setThemeColor(int colorPrimary, int colorPrimaryDark) {
// mToolbar.setBackgroundResource(colorPrimary);
@ -411,7 +385,7 @@ public class BookcasePresenter implements BasePresenter {
if (errorLoadingBooks.size() > 0) {
s.deleteCharAt(s.lastIndexOf("、"));
s.append(" 更新失败");
TextHelper.showText(s.toString());
ToastUtils.showError(s.toString());
}
}
@ -439,23 +413,17 @@ public class BookcasePresenter implements BasePresenter {
mBookcaseFragment.getGvBook().getmScrollView().setScrollY(0);
if (mSetting.getBookcaseStyle().equals(BookcaseStyle.listMode)) {
mSetting.setBookcaseStyle(BookcaseStyle.threePalaceMode);
TextHelper.showText("已切换为三列网格视图!");
ToastUtils.show("已切换为三列网格视图!");
} else {
mSetting.setBookcaseStyle(BookcaseStyle.listMode);
TextHelper.showText("已切换为列表视图!");
ToastUtils.show("已切换为列表视图!");
}
isBookcaseStyleChange = true;
SysManager.saveSetting(mSetting);
init();
return true;
case R.id.action_addLocalBook:
/*TextHelper.showText("请选择一个txt格式的书籍文件");
Intent addIntent = new Intent(Intent.ACTION_GET_CONTENT);
addIntent.setType("text/plain");
addIntent.addCategory(Intent.CATEGORY_OPENABLE);
mMainActivity.startActivityForResult(addIntent, APPCONST.SELECT_FILE_CODE);*/
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.M) {
if (mPermissionsChecker == null) {
mPermissionsChecker = new PermissionsChecker(mMainActivity);
}
@ -472,7 +440,7 @@ public class BookcasePresenter implements BasePresenter {
break;
case R.id.action_syn:
if (!UserService.isLogin()) {
TextHelper.showText("请先登录!");
ToastUtils.showWarring("请先登录!");
Intent loginIntent = new Intent(mMainActivity, LoginActivity.class);
mMainActivity.startActivity(loginIntent);
return true;
@ -504,7 +472,7 @@ public class BookcasePresenter implements BasePresenter {
tip = "每日自动同步已开启!";
}
SysManager.saveSetting(mSetting);
TextHelper.showText(tip);
ToastUtils.showSuccess(tip);
break;
}
})
@ -545,6 +513,10 @@ public class BookcasePresenter implements BasePresenter {
.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);
@ -577,6 +549,10 @@ public class BookcasePresenter implements BasePresenter {
* 备份
*/
private void backup() {
if (mBooks.size() == 0){
ToastUtils.showWarring("当前书架无任何书籍,无法备份!");
return;
}
DialogCreator.createCommonDialog(mMainActivity, "确认备份吗?", "新备份会替换原有备份!", true,
(dialogInterface, i) -> {
dialogInterface.dismiss();
@ -600,7 +576,7 @@ public class BookcasePresenter implements BasePresenter {
// DialogCreator.createTipDialog(mMainActivity,
// "恢复成功!\n注意:本功能属于实验功能,书架恢复后,书籍初次加载时可能加载失败,返回重新加载即可!");
mSetting = SysManager.getSetting();
TextHelper.showText("书架恢复成功!");
ToastUtils.showSuccess("书架恢复成功!");
} else {
DialogCreator.createTipDialog(mMainActivity, "未找到备份文件或未给予储存权限,恢复失败!");
}
@ -613,7 +589,7 @@ public class BookcasePresenter implements BasePresenter {
*/
private void webRestore() {
if (!NetworkUtils.isNetWorkAvailable()) {
TextHelper.showText("无网络连接!");
ToastUtils.showWarring("无网络连接!");
return;
}
DialogCreator.createCommonDialog(mMainActivity, "确认同步吗?", "将书架从网络同步至本地会覆盖原有书架!", true,
@ -625,7 +601,7 @@ public class BookcasePresenter implements BasePresenter {
// DialogCreator.createTipDialog(mMainActivity,
// "恢复成功!\n注意:本功能属于实验功能,书架恢复后,书籍初次加载时可能加载失败,返回重新加载即可!");、
mSetting = SysManager.getSetting();
TextHelper.showText("成功将书架从网络同步至本地!");
ToastUtils.showSuccess("成功将书架从网络同步至本地!");
} else {
DialogCreator.createTipDialog(mMainActivity, "未找到同步文件,同步失败!");
}
@ -639,19 +615,28 @@ public class BookcasePresenter implements BasePresenter {
*/
private void downloadAll(boolean isDownloadAllChapters) {
if (!NetworkUtils.isNetWorkAvailable()) {
TextHelper.showText("无网络连接!");
ToastUtils.showWarring("无网络连接!");
return;
}
if (isDownloadAllChapters) {
mHandler.sendEmptyMessage(12);
if (mBooks.size() == 0){
ToastUtils.showWarring("当前书架没有任何书籍,无法一键缓存!");
return;
}
MyApplication.getApplication().newThread(() -> {
ArrayList<Book> needDownloadBooks = new ArrayList<>();
for (Book book : mBooks) {
if (!BookSource.pinshu.toString().equals(book.getSource()) && !"本地书籍".equals(book.getType())) {
if (!BookSource.pinshu.toString().equals(book.getSource()) && !"本地书籍".equals(book.getType())
&& book.getIsDownLoadAll()) {
needDownloadBooks.add(book);
}
}
if(needDownloadBooks.size() == 0){
ToastUtils.showWarring("当前书架书籍不支持/已关闭(可在设置开启)一键缓存!");
return;
}
if (isDownloadAllChapters) {
mHandler.sendEmptyMessage(12);
}
downloadFor:
for (final Book book : needDownloadBooks) {
isDownloadFinish = false;
@ -708,15 +693,18 @@ public class BookcasePresenter implements BasePresenter {
*/
public void addDownload(final Book book, final ArrayList<Chapter> mChapters, int begin, int end, boolean isDownloadAll) {
if ("本地书籍".equals(book.getType())) {
TextHelper.showText("《" + book.getName() + "》是本地书籍,不能缓存");
ToastUtils.showWarring("《" + book.getName() + "》是本地书籍,不能缓存");
return;
}
if (mChapters.size() == 0) {
if (!isDownloadAll) {
TextHelper.showText("《" + book.getName() + "》章节目录为空,缓存失败,请刷新后重试");
ToastUtils.showWarring("《" + book.getName() + "》章节目录为空,缓存失败,请刷新后重试");
}
return;
}
if (SysManager.getSetting().getCatheGap() != 0){
downloadInterval = SysManager.getSetting().getCatheGap();
}
//取消之前下载
if (!isDownloadAll) {
if (!isStopDownload) {
@ -735,6 +723,8 @@ public class BookcasePresenter implements BasePresenter {
needCacheChapterNum = finalEnd - finalBegin;
curCacheChapterNum = 0;
tempCacheChapterNum = 0;
successCathe = 0;
errorCathe = 0;
isStopDownload = false;
ArrayList<Chapter> needDownloadChapters = new ArrayList<>();
for (int i = finalBegin; i < finalEnd; i++) {
@ -754,12 +744,14 @@ public class BookcasePresenter implements BasePresenter {
public void onFinish(Object o, int code) {
downloadingChapter = chapter.getTitle();
mChapterService.saveOrUpdateChapter(chapter, (String) o);
successCathe++;
curCacheChapterNum++;
}
@Override
public void onError(Exception e) {
curCacheChapterNum++;
errorCathe++;
}
});
try {
@ -779,7 +771,7 @@ public class BookcasePresenter implements BasePresenter {
}
if (!isDownloadAll) {
if (curCacheChapterNum == needCacheChapterNum) {
TextHelper.showText("《" + book.getName() + "》" + mMainActivity.getString(R.string.download_already_all_tips));
ToastUtils.showInfo("《" + book.getName() + "》" + mMainActivity.getString(R.string.download_already_all_tips));
}
}
}
@ -870,11 +862,11 @@ public class BookcasePresenter implements BasePresenter {
//判断书籍是否已经添加
Book existsBook = mBookService.findBookByAuthorAndName(book.getName(), book.getAuthor());
if (book.equals(existsBook)) {
TextHelper.showText("该书籍已存在,请勿重复添加!");
ToastUtils.showWarring("该书籍已存在,请勿重复添加!");
return;
}
mBookService.addBook(book);
TextHelper.showText("本地书籍添加成功");
ToastUtils.showSuccess("本地书籍添加成功");
init();
}
@ -884,7 +876,13 @@ public class BookcasePresenter implements BasePresenter {
private void synBookcaseToWeb(boolean isAutoSyn) {
if (!NetworkUtils.isNetWorkAvailable()) {
if (!isAutoSyn) {
TextHelper.showText("无网络连接!");
ToastUtils.showWarring("无网络连接!");
}
return;
}
if (mBooks.size() == 0){
if (!isAutoSyn) {
ToastUtils.showWarring("当前书架无任何书籍,无法同步!");
}
return;
}

@ -41,15 +41,13 @@ public class CatalogActivityPresenter implements BasePresenter {
isDayStyle = setting.isDayStyle();
//设置日夜间
if (!isDayStyle){
mCatalogActivity.setStatusBar(R.color.sys_dialog_setting_bg);
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));
}else {
mCatalogActivity.getEtSearch().setTextColor(mCatalogActivity.getResources().getColor(setting.getReadWordColor()));
}
init();

@ -9,13 +9,13 @@ 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.util.ToastUtils;
import xyz.fycz.myreader.webapi.crawler.ReadCrawlerUtil;
import xyz.fycz.myreader.greendao.entity.Book;
import xyz.fycz.myreader.greendao.entity.Chapter;
import xyz.fycz.myreader.greendao.service.ChapterService;
import xyz.fycz.myreader.ui.adapter.ChapterTitleAdapter;
import xyz.fycz.myreader.ui.fragment.CatalogFragment;
import xyz.fycz.myreader.util.TextHelper;
import xyz.fycz.myreader.webapi.CommonApi;
import java.util.ArrayList;
@ -50,9 +50,10 @@ public class CatalogPresenter implements BasePresenter {
mCatalogFragment.getFcChangeSort().setOnClickListener(view -> {
if (curSortflag == 0) {//当前正序
curSortflag = 1;
changeChapterSort();
} else {//当前倒序
curSortflag = 0;
}
if (mChapterTitleAdapter != null) {
changeChapterSort();
}
});
@ -60,6 +61,10 @@ public class CatalogPresenter implements BasePresenter {
if (mChapters.size() != 0) {
initChapterTitleList();
}else {
if ("本地书籍".equals(mBook.getType())){
ToastUtils.showWarring("本地书籍请先拆分章节!");
return;
}
mCatalogFragment.getPbLoading().setVisibility(View.VISIBLE);
CommonApi.getBookChapters(mBook.getChapterUrl(), ReadCrawlerUtil.getReadCrawler(mBook.getSource()),
new ResultCallback() {
@ -77,7 +82,7 @@ public class CatalogPresenter implements BasePresenter {
@Override
public void onError(Exception e) {
e.printStackTrace();
TextHelper.showText("章节目录加载失败!");
ToastUtils.showError("章节目录加载失败!\n" + e.getLocalizedMessage());
MyApplication.runOnUiThread(() -> mCatalogFragment.getPbLoading().setVisibility(View.GONE));
}
});

@ -12,7 +12,7 @@ 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.TextHelper;
import xyz.fycz.myreader.util.ToastUtils;
import xyz.fycz.myreader.util.utils.FileUtils;
import java.io.*;
@ -83,12 +83,12 @@ public class FontsPresenter implements BasePresenter {
public void saveLocalFont(String path){
File fontFile = new File(path);
if (!fontFile.exists()){
TextHelper.showText("未找到字体文件!");
ToastUtils.showWarring("未找到字体文件!");
return;
}
String fontName = fontFile.getName();
if (!fontName.endsWith(".ttf")){
TextHelper.showText("字体更换失败,请选择ttf格式的字体文件!");
ToastUtils.showError("字体更换失败,请选择ttf格式的字体文件!");
return;
}
String dirPath = fontFile.getParentFile().getAbsolutePath() + "/";
@ -110,7 +110,7 @@ public class FontsPresenter implements BasePresenter {
mFontsAdapter.saveLocalFontName(fontName);
} catch (IOException e) {
e.printStackTrace();
TextHelper.showText("读取字体文件出错!\n" + e.getLocalizedMessage());
ToastUtils.showError("读取字体文件出错!\n" + e.getLocalizedMessage());
}finally {
IOUtils.close(fis, fos);
}

@ -16,7 +16,7 @@ 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.TextHelper;
import xyz.fycz.myreader.util.ToastUtils;
import xyz.fycz.myreader.util.utils.NetworkUtils;
import java.util.HashMap;
@ -78,7 +78,7 @@ public class LoginPresenter implements BasePresenter {
return;
}
if (!NetworkUtils.isNetWorkAvailable()) {
TextHelper.showText("无网络连接!");
ToastUtils.showError("无网络连接!");
return;
}
ProgressDialog dialog = DialogCreator.createProgressDialog(mLoginActivity, null, "正在登陆...");
@ -101,16 +101,18 @@ public class LoginPresenter implements BasePresenter {
UserService.writeConfig(userLoginInfo);
UserService.writeUsername(loginName);
mLoginActivity.finish();
ToastUtils.showSuccess(resultName);
} else {
mHandler.sendMessage(mHandler.obtainMessage(1));
dialog.dismiss();
ToastUtils.showWarring(resultName);
}
TextHelper.showText(resultName);
}
@Override
public void onError(Exception e) {
TextHelper.showText("登录失败\n" + e.getLocalizedMessage());
ToastUtils.showError("登录失败\n" + e.getLocalizedMessage());
mHandler.sendMessage(mHandler.obtainMessage(1));
dialog.dismiss();
}

@ -15,7 +15,7 @@ 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.TextHelper;
import xyz.fycz.myreader.util.ToastUtils;
import java.io.File;
import java.util.ArrayList;
@ -44,11 +44,11 @@ public class MainPresenter implements BasePresenter {
int settingVersion = mSetting.getSettingVersion();
if (settingVersion < APPCONST.SETTING_VERSION){
SysManager.resetSetting();
DialogCreator.createTipDialog(mMainActivity, "因组件升级,已恢复默认设置!");
//DialogCreator.createTipDialog(mMainActivity, "因组件升级,阅读字体及背景颜色已恢复默认颜色!");
}
}catch (Exception e){
SysManager.resetSetting();
DialogCreator.createTipDialog(mMainActivity, "因组件升级,已恢复默认设置!");
//DialogCreator.createTipDialog(mMainActivity, "因组件升级,阅读字体及背景颜色已恢复默认颜色");
}
init();
checkVersionByServer(mMainActivity, false, (BookcaseFragment) mFragments.get(0));
@ -64,11 +64,11 @@ public class MainPresenter implements BasePresenter {
@Override
public void onClick(DialogInterface dialog, int which) {
if (file.delete()) {
TextHelper.showText("退出成功");
ToastUtils.showSuccess("退出成功");
Intent intent = new Intent(mMainActivity, LoginActivity.class);
mMainActivity.startActivity(intent);
} else {
TextHelper.showText("退出失败");
ToastUtils.showError("退出失败(Error:file.delete())");
}
}
}, (dialog, which) -> dialog.dismiss());

@ -30,6 +30,8 @@ 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.util.*;
import xyz.fycz.myreader.webapi.crawler.ReadCrawler;
import xyz.fycz.myreader.webapi.crawler.ReadCrawlerUtil;
import xyz.fycz.myreader.creator.DialogCreator;
@ -46,10 +48,6 @@ 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.BrightUtil;
import xyz.fycz.myreader.util.ScreenHelper;
import xyz.fycz.myreader.util.StringHelper;
import xyz.fycz.myreader.util.TextHelper;
import xyz.fycz.myreader.util.notification.NotificationClickReceiver;
import xyz.fycz.myreader.util.notification.NotificationUtil;
import xyz.fycz.myreader.util.utils.NetworkUtils;
@ -95,7 +93,7 @@ public class ReadPresenter implements BasePresenter {
private PageLoader mPageLoader;//页面加载器
private int screenTimeOut = 60 * 3;//息屏时间(单位:秒),小于零表示常亮
private int screenTimeOut;//息屏时间(单位:秒),dengy零表示常亮
private Runnable keepScreenRunnable;//息屏线程
private Runnable autoPageRunnable;//自动翻页
@ -163,16 +161,20 @@ public class ReadPresenter implements BasePresenter {
}
break;
case 7:
TextHelper.showText("无网络连接!");
ToastUtils.showWarring("无网络连接!");
mPageLoader.chapterError();
break;
case 8:
mReadActivity.getPbLoading().setVisibility(View.GONE);
break;
case 9:
TextHelper.showText("正在后台缓存书籍,具体进度可查看通知栏!");
ToastUtils.showInfo("正在后台缓存书籍,具体进度可查看通知栏!");
notificationUtil.requestNotificationPermissionDialog(mReadActivity);
break;
case 10:
if (mPageLoader != null) {
mPageLoader.chapterError();
}
}
}
};
@ -212,6 +214,9 @@ public class ReadPresenter implements BasePresenter {
@Override
public void start() {
//息屏时间
screenTimeOut = mSetting.getResetScreen() * 60;
//保持屏幕常亮
keepScreenRunnable = this::unKeepScreenOn;
@ -281,6 +286,7 @@ public class ReadPresenter implements BasePresenter {
view -> {//返回
mSettingDialog.dismiss();
mReadActivity.onBackPressed();
}, v -> {//换源
}, v -> {//刷新
isPrev = false;
if (!"本地书籍".equals(mBook.getType())) {
@ -408,23 +414,28 @@ public class ReadPresenter implements BasePresenter {
this::changeStyle, v -> reduceTextSize(), v -> increaseTextSize(), v -> {
if (mSetting.isVolumeTurnPage()) {
mSetting.setVolumeTurnPage(false);
TextHelper.showText("音量键翻页已关闭!");
ToastUtils.showSuccess("音量键翻页已关闭!");
} else {
mSetting.setVolumeTurnPage(true);
TextHelper.showText("音量键翻页已开启!");
ToastUtils.showSuccess("音量键翻页已开启!");
}
SysManager.saveSetting(mSetting);
}, v -> {
Intent intent = new Intent(mReadActivity, FontsActivity.class);
mReadActivity.startActivityForResult(intent, APPCONST.REQUEST_FONT);
mSettingDetailDialog.dismiss();
}, this::showPageModeDialog, v -> {
if (mSetting.getPageMode() == PageMode.SCROLL) {
TextHelper.showText("滚动暂时不支持自动翻页");
ToastUtils.showWarring("滚动暂时不支持自动翻页");
return;
}
mSettingDetailDialog.dismiss();
autoPage = !autoPage;
autoPage();
}, v -> {
Intent intent = new Intent(mReadActivity, MoreSettingActivity.class);
mReadActivity.startActivityForResult(intent, APPCONST.REQUEST_RESET_SCREEN_TIME);
mSettingDetailDialog.dismiss();
});
}
@ -516,6 +527,11 @@ public class ReadPresenter implements BasePresenter {
assert chapterAndPage != null;
skipToChapterAndPage(chapterAndPage[0], chapterAndPage[1]);
break;
case APPCONST.REQUEST_RESET_SCREEN_TIME:
int resetScreen = data.getIntExtra(APPCONST.RESULT_RESET_SCREEN, 0);
screenTimeOut = resetScreen * 60;
screenOffTimerStart();
break;
}
}
}
@ -638,7 +654,7 @@ public class ReadPresenter implements BasePresenter {
!ChapterService.isChapterCached(mBook.getId(), mChapters.get(0).getTitle()))) {
if ("本地书籍".equals(mBook.getType())) {
if (!new File(mBook.getChapterUrl()).exists()) {
TextHelper.showText("书籍缓存为空且源文件不存在,书籍加载失败!");
ToastUtils.showWarring("书籍缓存为空且源文件不存在,书籍加载失败!");
mReadActivity.finish();
return;
}
@ -689,12 +705,13 @@ public class ReadPresenter implements BasePresenter {
* 初始化章节
*/
private void initChapters() {
mBook.setNoReadNum(0);
mBook.setChapterTotalNum(mChapters.size());
if (!StringHelper.isEmpty(mBook.getId())) {
mBookService.updateEntity(mBook);
}
if (mChapters.size() == 0) {
TextHelper.showLongText("该书查询不到任何章节");
ToastUtils.showWarring("该书查询不到任何章节");
mHandler.sendMessage(mHandler.obtainMessage(8));
settingChange = false;
} else {
@ -745,14 +762,14 @@ public class ReadPresenter implements BasePresenter {
protected void downloadBook(final TextView tvDownloadProgress) {
if ("本地书籍".equals(mBook.getType())) {
TextHelper.showText("《" + mBook.getName() + "》是本地书籍,不能缓存");
ToastUtils.showWarring("《" + mBook.getName() + "》是本地书籍,不能缓存");
return;
}
if (!NetworkUtils.isNetWorkAvailable()) {
TextHelper.showText("无网络连接!");
ToastUtils.showWarring("无网络连接!");
return;
}
MyApplication.runOnUiThread(() ->{
MyApplication.runOnUiThread(() -> {
new AlertDialog.Builder(mReadActivity)
.setTitle("缓存书籍")
.setSingleChoiceItems(APPCONST.DIALOG_DOWNLOAD, selectedIndex, (dialog, which) -> selectedIndex = which).setNegativeButton("取消", ((dialog, which) -> dialog.dismiss())).setPositiveButton("确定",
@ -785,6 +802,9 @@ public class ReadPresenter implements BasePresenter {
e.printStackTrace();
}
}*/
if (SysManager.getSetting().getCatheGap() != 0){
downloadInterval = SysManager.getSetting().getCatheGap();
}
//计算断点章节
final int finalBegin = Math.max(0, begin);
final int finalEnd = Math.min(end, mChapters.size());
@ -830,7 +850,7 @@ public class ReadPresenter implements BasePresenter {
}
}
if (curCacheChapterNum == needCacheChapterNum) {
TextHelper.showText("《" + mBook.getName() + "》" + mReadActivity.getString(R.string.download_already_all_tips));
ToastUtils.showInfo("《" + mBook.getName() + "》" + mReadActivity.getString(R.string.download_already_all_tips));
}
});
}
@ -976,28 +996,6 @@ public class ReadPresenter implements BasePresenter {
mSetting.setDayStyle(true);
}
mSetting.setReadStyle(readStyle);
switch (readStyle) {
case common:
mSetting.setReadBgColor(R.color.sys_common_bg);
mSetting.setReadWordColor(R.color.sys_common_word);
break;
case leather:
mSetting.setReadBgColor(R.color.sys_leather_bg);
mSetting.setReadWordColor(R.color.sys_leather_word);
break;
case protectedEye:
mSetting.setReadBgColor(R.color.sys_protect_eye_bg);
mSetting.setReadWordColor(R.color.sys_protect_eye_word);
break;
case breen:
mSetting.setReadBgColor(R.color.sys_breen_bg);
mSetting.setReadWordColor(R.color.sys_breen_word);
break;
case blueDeep:
mSetting.setReadBgColor(R.color.sys_blue_deep_bg);
mSetting.setReadWordColor(R.color.sys_blue_deep_word);
break;
}
SysManager.saveSetting(mSetting);
MyApplication.runOnUiThread(() -> mPageLoader.setPageStyle(true));
}
@ -1025,7 +1023,7 @@ public class ReadPresenter implements BasePresenter {
* 重置黑屏时间
*/
private void screenOffTimerStart() {
if (screenTimeOut < 0) {
if (screenTimeOut <= 0) {
keepScreenOn(true);
return;
}
@ -1083,7 +1081,8 @@ public class ReadPresenter implements BasePresenter {
book.setNewestChapterTitle("未拆分章节");
book.setAuthor("本地书籍");
book.setSource(BookSource.local.toString());
book.setDesc("");
book.setDesc("无");
book.setIsCloseUpdate(true);
//判断书籍是否已经添加
Book existsBook = mBookService.findBookByAuthorAndName(book.getName(), book.getAuthor());
@ -1106,7 +1105,7 @@ public class ReadPresenter implements BasePresenter {
isPrev = false;
if (StringHelper.isEmpty(mChapters.get(chapterPos).getContent())) {
if ("本地书籍".equals(mBook.getType())) {
TextHelper.showText("该章节无内容!");
ToastUtils.showWarring("该章节无内容!");
return;
}
mReadActivity.getPbLoading().setVisibility(View.VISIBLE);
@ -1121,7 +1120,7 @@ public class ReadPresenter implements BasePresenter {
@Override
public void onError(Exception e) {
mHandler.sendMessage(mHandler.obtainMessage(2, chapterPos, pagePos));
mPageLoader.chapterError();
mHandler.sendEmptyMessage(10);
}
});
} else {

@ -15,7 +15,7 @@ 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.TextHelper;
import xyz.fycz.myreader.util.ToastUtils;
import xyz.fycz.myreader.util.utils.StringUtils;
import java.util.HashMap;
@ -200,14 +200,16 @@ public class RegisterPresenter implements BasePresenter {
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();
TextHelper.showText(info[1]);
}
@Override
public void onError(Exception e) {
TextHelper.showText("注册失败:\n" + e.getLocalizedMessage());
ToastUtils.showError("注册失败:\n" + e.getLocalizedMessage());
dialog.dismiss();
}
});

@ -1,187 +0,0 @@
package xyz.fycz.myreader.util;
import android.annotation.TargetApi;
import android.app.Notification;
import android.app.NotificationManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.Build;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class BadgeUtil {
/**
* Set badge count<br/>
* 针对 Samsung / xiaomi / sony 手机有效
* @param context The context of the application package.
* @param count Badge count to be set
*/
@TargetApi(16)
public static void setBadgeCount(Context context, int count) {
if (count <= 0) {
count = 0;
} else {
count = Math.max(0, Math.min(count, 99));
}
if (Build.MANUFACTURER.equalsIgnoreCase("Xiaomi")) {
NotificationManager mNotificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
Notification.Builder builder = new Notification.Builder(context).setContentTitle("title").setContentText("text");
Notification notification = builder.build();
try {
Field field = notification.getClass().getDeclaredField("extraNotification");
Object extraNotification = field.get(notification);
Method method = extraNotification.getClass().getDeclaredMethod("setMessageCount", int.class);
method.invoke(extraNotification, count);
mNotificationManager.notify(0,notification);
sendToXiaoMi(notification, context, count);
} catch (Exception e) {
e.printStackTrace();
}
} else if (Build.MANUFACTURER.equalsIgnoreCase("sony")) {
sendToSony(context, count);
} else if (Build.MANUFACTURER.toLowerCase().contains("samsung")) {
sendToSamsumg(context, count);
} else {
// Toast.makeText(context, "Not Support", Toast.LENGTH_LONG).show();
}
}
/**
* 向小米手机发送未读消息数广播
* @param count
*/
private static void sendToXiaoMi(Notification notification, Context context, int count) {
try {
// Class miuiNotificationClass = Class.forName("android.app.MiuiNotification");
// Object miuiNotification = miuiNotificationClass.newInstance();
// Field field = miuiNotification.getClass().getDeclaredField("messageCount");
// field.setAccessible(true);
// field.set(miuiNotification, String.valueOf(count == 0 ? "" : count)); // 设置信息数-->这种发送必须是miui 6才行
Field field = notification.getClass().getDeclaredField("extraNotification");
Object extraNotification = field.get(notification);
Method method = extraNotification.getClass().getDeclaredMethod("setMessageCount", int.class);
method.invoke(extraNotification, count);
} catch (Exception e) {
e.printStackTrace();
// miui 6之前的版本
Intent localIntent = new Intent(
"android.intent.action.APPLICATION_MESSAGE_UPDATE");
localIntent.putExtra(
"android.intent.extra.update_application_component_name",
context.getPackageName() + "/" + getLauncherClassName(context));
localIntent.putExtra(
"android.intent.extra.update_application_message_text", String.valueOf(count == 0 ? "" : count));
context.sendBroadcast(localIntent);
}
}
/**
* 向索尼手机发送未读消息数广播<br/>
* 据说需添加权限<uses-permission android:name="com.sonyericsson.home.permission.BROADCAST_BADGE" /> [未验证]
* @param count
*/
private static void sendToSony(Context context, int count){
String launcherClassName = getLauncherClassName(context);
if (launcherClassName == null) {
return;
}
boolean isShow = true;
if (count == 0) {
isShow = false;
}
Intent localIntent = new Intent();
localIntent.setAction("com.sonyericsson.home.action.UPDATE_BADGE");
localIntent.putExtra("com.sonyericsson.home.intent.extra.badge.SHOW_MESSAGE",isShow);//是否显示
localIntent.putExtra("com.sonyericsson.home.intent.extra.badge.ACTIVITY_NAME",launcherClassName );//启动页
localIntent.putExtra("com.sonyericsson.home.intent.extra.badge.MESSAGE", String.valueOf(count));//数字
localIntent.putExtra("com.sonyericsson.home.intent.extra.badge.PACKAGE_NAME", context.getPackageName());//包名
context.sendBroadcast(localIntent);
}
/**
* 向三星手机发送未读消息数广播
* @param count
*/
private static void sendToSamsumg(Context context, int count){
String launcherClassName = getLauncherClassName(context);
if (launcherClassName == null) {
return;
}
Intent intent = new Intent("android.intent.action.BADGE_COUNT_UPDATE");
intent.putExtra("badge_count", count);
intent.putExtra("badge_count_package_name", context.getPackageName());
intent.putExtra("badge_count_class_name", launcherClassName);
context.sendBroadcast(intent);
}
/**
* 重置清除Badge未读显示数<br/>
* @param context
*/
/* public static void resetBadgeCount(Notification notification,Context context) {
setBadgeCount(notification, context, 0);
}*/
/**
* Retrieve launcher activity name of the application from the context
*
* @param context The context of the application package.
* @return launcher activity name of this application. From the
* "android:name" attribute.
*/
private static String getLauncherClassName(Context context) {
PackageManager packageManager = context.getPackageManager();
Intent intent = new Intent(Intent.ACTION_MAIN);
// To limit the components this Intent will resolve to, by setting an
// explicit package name.
intent.setPackage(context.getPackageName());
intent.addCategory(Intent.CATEGORY_LAUNCHER);
// All Application must have 1 Activity at least.
// Launcher activity must be found!
ResolveInfo info = packageManager
.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY);
// get a ResolveInfo containing ACTION_MAIN, CATEGORY_LAUNCHER
// if there is no Activity which has filtered by CATEGORY_DEFAULT
if (info == null) {
info = packageManager.resolveActivity(intent, 0);
}
return info.activityInfo.name;
}
}

@ -1,8 +0,0 @@
package xyz.fycz.myreader.util;
public class CacheFileNameHelper {
}

@ -1,31 +0,0 @@
package xyz.fycz.myreader.util;
import java.io.UnsupportedEncodingException;
public class ChschtUtil {
public static String big5ToChinese(String s) {
try {
if (s == null || s.equals(""))
return ("");
String newstring = null;
newstring = new String(s.getBytes("big5"), "gb2312");
return (newstring);
} catch (UnsupportedEncodingException e) {
return (s);
}
}
public static String ChineseTobig5(String s) {
try {
if (s == null || s.equals(""))
return ("");
String newstring = null;
newstring = new String(s.getBytes("gb2312"), "big5");
return (newstring);
} catch (UnsupportedEncodingException e) {
return (s);
}
}
}

@ -126,7 +126,7 @@ public class DownloadMangerUtils {
manager.enqueue(request);
} catch (Exception e) {
e.printStackTrace();
TextHelper.showText("下载错误:" + e.toString());
ToastUtils.showError("下载错误:" + e.getLocalizedMessage());
}
}
@ -407,11 +407,11 @@ public class DownloadMangerUtils {
if (checkReadPhoneStatePermission != PackageManager.PERMISSION_GRANTED) {
// 弹出对话框接收权限
ActivityCompat.requestPermissions((AppCompatActivity) context, new String[]{android.Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
TextHelper.showText("当前应用未拥有存储设备读写权限");
ToastUtils.showWarring("当前应用未拥有存储设备读写权限");
} else if (ContextCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
// 弹出对话框接收权限
ActivityCompat.requestPermissions((AppCompatActivity) context, new String[]{android.Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
TextHelper.showText("当前应用未拥有存储设备读写权限");
ToastUtils.showWarring("当前应用未拥有存储设备读写权限");
} else {
permission = true;
}

@ -1,150 +0,0 @@
package xyz.fycz.myreader.util;
public class GreenDaoUpgrade {
/*private static final String CONVERSION_CLASS_NOT_FOUND_EXCEPTION = "MIGRATION HELPER - CLASS DOESN'T MATCH WITH THE CURRENT PARAMETERS";
private static GreenDaoUpgrade instance;
public static GreenDaoUpgrade getInstance() {
if (instance == null) {
instance = new GreenDaoUpgrade();
}
return instance;
}
private static List<String> getColumns(Database db, String tableName) {
List<String> columns = new ArrayList<>();
Cursor cursor = null;
try {
cursor = db.rawQuery("SELECT * FROM " + tableName + " limit 1", null);
if (cursor != null) {
columns = new ArrayList<>(Arrays.asList(cursor.getColumnNames()));
}
} catch (Exception e) {
Log.v(tableName, e.getMessage(), e);
e.printStackTrace();
} finally {
if (cursor != null)
cursor.close();
}
return columns;
}
public void migrate(Database db, Class<? extends AbstractDao<?, ?>>... daoClasses) {
generateTempTables(db, daoClasses);
DaoMaster.dropAllTables(db, true);
DaoMaster.createAllTables(db, false);
restoreData(db, daoClasses);
}
private void generateTempTables(Database db, Class<? extends AbstractDao<?, ?>>... daoClasses) {
for (int i = 0; i < daoClasses.length; i++) {
DaoConfig daoConfig = new DaoConfig(db, daoClasses[i]);
String divider = "";
String tableName = daoConfig.tablename;
String tempTableName = daoConfig.tablename.concat("_TEMP");
ArrayList<String> properties = new ArrayList<>();
StringBuilder createTableStringBuilder = new StringBuilder();
createTableStringBuilder.append("CREATE TABLE ").append(tempTableName).append(" (");
for (int j = 0; j < daoConfig.properties.length; j++) {
String columnName = daoConfig.properties[j].columnName;
if (getColumns(db, tableName).contains(columnName)) {
properties.add(columnName);
String type = null;
try {
type = getTypeByClass(daoConfig.properties[j].type);
} catch (Exception exception) {
exception.printStackTrace();
}
createTableStringBuilder.append(divider).append(columnName).append(" ").append(type);
if (daoConfig.properties[j].primaryKey) {
createTableStringBuilder.append(" PRIMARY KEY");
}
divider = ",";
}
}
createTableStringBuilder.append(");");
db.execSQL(createTableStringBuilder.toString());
StringBuilder insertTableStringBuilder = new StringBuilder();
insertTableStringBuilder.append("INSERT INTO ").append(tempTableName).append(" (");
insertTableStringBuilder.append(TextUtils.join(",", properties));
insertTableStringBuilder.append(") SELECT ");
insertTableStringBuilder.append(TextUtils.join(",", properties));
insertTableStringBuilder.append(" FROM ").append(tableName).append(";");
db.execSQL(insertTableStringBuilder.toString());
}
}
private void restoreData(Database db, Class<? extends AbstractDao<?, ?>>... daoClasses) {
for (int i = 0; i < daoClasses.length; i++) {
DaoConfig daoConfig = new DaoConfig(db, daoClasses[i]);
String tableName = daoConfig.tablename;
String tempTableName = daoConfig.tablename.concat("_TEMP");
ArrayList<String> properties = new ArrayList();
ArrayList<String> propertiesQuery = new ArrayList();
for (int j = 0; j < daoConfig.properties.length; j++) {
String columnName = daoConfig.properties[j].columnName;
if (getColumns(db, tempTableName).contains(columnName)) {
properties.add(columnName);
propertiesQuery.add(columnName);
} else {
try {
if (getTypeByClass(daoConfig.properties[j].type).equals("INTEGER")) {
propertiesQuery.add("0 as " + columnName);
properties.add(columnName);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
StringBuilder insertTableStringBuilder = new StringBuilder();
insertTableStringBuilder.append("INSERT INTO ").append(tableName).append(" (");
insertTableStringBuilder.append(TextUtils.join(",", properties));
insertTableStringBuilder.append(") SELECT ");
insertTableStringBuilder.append(TextUtils.join(",", propertiesQuery));
insertTableStringBuilder.append(" FROM ").append(tempTableName).append(";");
StringBuilder dropTableStringBuilder = new StringBuilder();
dropTableStringBuilder.append("DROP TABLE ").append(tempTableName);
db.execSQL(insertTableStringBuilder.toString());
db.execSQL(dropTableStringBuilder.toString());
}
}
private String getTypeByClass(Class<?> type) throws Exception {
if (type.equals(String.class)) {
return "TEXT";
}
if (type.equals(Long.class) || type.equals(Integer.class) || type.equals(long.class) || type.equals(int.class)) {
return "INTEGER";
}
if (type.equals(Boolean.class) || type.equals(boolean.class)) {
return "BOOLEAN";
}
Exception exception = new Exception(CONVERSION_CLASS_NOT_FOUND_EXCEPTION.concat(" - Class: ").concat(type.toString()));
exception.printStackTrace();
throw exception;
}*/
}

@ -0,0 +1,121 @@
package xyz.fycz.myreader.util;
import android.os.Build;
import android.text.TextUtils;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
/**
* @ClassName: OSUtils
* @Description:Rom类型判断的工具类
* @Author: dingchao
* @Date: 2018/11/8 15:25
*/
public class OSUtils {
public static final String ROM_MIUI = "MIUI";
public static final String ROM_EMUI = "EMUI";
public static final String ROM_FLYME = "FLYME";
public static final String ROM_OPPO = "OPPO";
public static final String ROM_SMARTISAN = "SMARTISAN";
public static final String ROM_VIVO = "VIVO";
public static final String ROM_QIKU = "QIKU";
private static final String KEY_VERSION_MIUI = "ro.miui.ui.version.name";
private static final String KEY_VERSION_EMUI = "ro.build.version.emui";
private static final String KEY_VERSION_OPPO = "ro.build.version.opporom";
private static final String KEY_VERSION_SMARTISAN = "ro.smartisan.version";
private static final String KEY_VERSION_VIVO = "ro.vivo.os.version";
private static String sName;
private static String sVersion;
public static boolean isEmui() {
return check(ROM_EMUI);
}
public static boolean isMiui() {
return check(ROM_MIUI);
}
public static boolean isVivo() {
return check(ROM_VIVO);
}
public static boolean isOppo() {
return check(ROM_OPPO);
}
public static boolean isFlyme() {
return check(ROM_FLYME);
}
public static boolean is360() {
return check(ROM_QIKU) || check("360");
}
public static boolean isSmartisan() {
return check(ROM_SMARTISAN);
}
public static String getName() {
if (sName == null) {
check("");
}
return sName;
}
public static String getVersion() {
if (sVersion == null) {
check("");
}
return sVersion;
}
public static boolean check(String rom) {
if (sName != null) {
return sName.equals(rom);
}
if (!TextUtils.isEmpty(sVersion = getProp(KEY_VERSION_MIUI))) {
sName = ROM_MIUI;
} else if (!TextUtils.isEmpty(sVersion = getProp(KEY_VERSION_EMUI))) {
sName = ROM_EMUI;
} else if (!TextUtils.isEmpty(sVersion = getProp(KEY_VERSION_OPPO))) {
sName = ROM_OPPO;
} else if (!TextUtils.isEmpty(sVersion = getProp(KEY_VERSION_VIVO))) {
sName = ROM_VIVO;
} else if (!TextUtils.isEmpty(sVersion = getProp(KEY_VERSION_SMARTISAN))) {
sName = ROM_SMARTISAN;
} else {
sVersion = Build.DISPLAY;
if (sVersion.toUpperCase().contains(ROM_FLYME)) {
sName = ROM_FLYME;
} else {
sVersion = Build.UNKNOWN;
sName = Build.MANUFACTURER.toUpperCase();
}
}
return sName.equals(rom);
}
public static String getProp(String name) {
String line = null;
BufferedReader input = null;
try {
Process p = Runtime.getRuntime().exec("getprop " + name);
input = new BufferedReader(new InputStreamReader(p.getInputStream()), 1024);
line = input.readLine();
input.close();
} catch (IOException ex) {
return null;
} finally {
if (input != null) {
try {
input.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return line;
}
}

@ -98,7 +98,7 @@ public class OpenFileHelper {
context.startActivity(intent); //这里最好try一下,有可能会报错。 比如说你的MIME类型是打开邮箱,但是你手机里面没装邮箱客户端,就会报错。
}catch (Exception e){
e.printStackTrace();
TextHelper.showText("没有安装相应的文件读取工具或者文件错误");
ToastUtils.showError("没有安装相应的文件读取工具或者文件错误");
}
}

@ -25,11 +25,11 @@ public class PermissionHelper {
if (checkReadPhoneStatePermission != PackageManager.PERMISSION_GRANTED) {
// 弹出对话框接收权限
ActivityCompat.requestPermissions((AppCompatActivity) context, new String[]{android.Manifest.permission.READ_PHONE_STATE}, 1);
TextHelper.showText("当前应用未拥读取设备状态权限");
ToastUtils.showWarring("当前应用未拥读取设备状态权限");
} else if (ContextCompat.checkSelfPermission(context, Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {
// 弹出对话框接收权限
ActivityCompat.requestPermissions((AppCompatActivity) context, new String[]{android.Manifest.permission.READ_PHONE_STATE}, 1);
TextHelper.showText("当前应用未拥读取设备状态权限");
ToastUtils.showWarring("当前应用未拥读取设备状态权限");
} else {
permission = true;
}
@ -51,11 +51,11 @@ public class PermissionHelper {
if (checkReadPhoneStatePermission != PackageManager.PERMISSION_GRANTED) {
// 弹出对话框接收权限
ActivityCompat.requestPermissions((AppCompatActivity) context, new String[]{android.Manifest.permission.ACCESS_COARSE_LOCATION}, 1);
TextHelper.showText("当前应用未拥有蓝牙设备使用权限");
ToastUtils.showWarring("当前应用未拥有蓝牙设备使用权限");
} else if (ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// 弹出对话框接收权限
ActivityCompat.requestPermissions((AppCompatActivity) context, new String[]{android.Manifest.permission.ACCESS_COARSE_LOCATION}, 1);
TextHelper.showText("当前应用未拥有蓝牙设备使用权限");
ToastUtils.showWarring("当前应用未拥有蓝牙设备使用权限");
} else {
permission = true;
}
@ -78,11 +78,11 @@ public class PermissionHelper {
if (checkReadPhoneStatePermission != PackageManager.PERMISSION_GRANTED) {
// 弹出对话框接收权限
ActivityCompat.requestPermissions((AppCompatActivity) context, new String[]{android.Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
TextHelper.showText("当前应用未拥有存储设备读写权限");
ToastUtils.showWarring("当前应用未拥有存储设备读写权限");
} else if (ContextCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
// 弹出对话框接收权限
ActivityCompat.requestPermissions((AppCompatActivity) context, new String[]{android.Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
TextHelper.showText("当前应用未拥有存储设备读写权限");
ToastUtils.showWarring("当前应用未拥有存储设备读写权限");
} else {
permission = true;
}
@ -104,11 +104,11 @@ public class PermissionHelper {
if (checkReadPhoneStatePermission != PackageManager.PERMISSION_GRANTED) {
// 弹出对话框接收权限
ActivityCompat.requestPermissions((AppCompatActivity) context, new String[]{android.Manifest.permission.RECORD_AUDIO}, 1);
TextHelper.showText("当前应用未拥有音频录制权限");
ToastUtils.showWarring("当前应用未拥有音频录制权限");
} else if (ContextCompat.checkSelfPermission(context, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {
// 弹出对话框接收权限
ActivityCompat.requestPermissions((AppCompatActivity) context, new String[]{android.Manifest.permission.RECORD_AUDIO}, 1);
TextHelper.showText("当前应用未拥有音频录制权限");
ToastUtils.showWarring("当前应用未拥有音频录制权限");
} else {
permission = true;
}
@ -130,11 +130,11 @@ public class PermissionHelper {
if (checkReadPhoneStatePermission != PackageManager.PERMISSION_GRANTED) {
// 弹出对话框接收权限
ActivityCompat.requestPermissions((AppCompatActivity) context, new String[]{android.Manifest.permission.CAMERA}, 1);
TextHelper.showText("当前应用未拥有调用摄像头权限");
ToastUtils.showWarring("当前应用未拥有调用摄像头权限");
} else if (ContextCompat.checkSelfPermission(context, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
// 弹出对话框接收权限
ActivityCompat.requestPermissions((AppCompatActivity) context, new String[]{android.Manifest.permission.CAMERA}, 1);
TextHelper.showText("当前应用未拥有调用摄像头权限");
ToastUtils.showWarring("当前应用未拥有调用摄像头权限");
} else {
permission = true;
}

@ -1,71 +0,0 @@
package xyz.fycz.myreader.util;
import android.app.Activity;
import android.content.Context;
import android.graphics.Color;
import android.os.Build;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import xyz.fycz.myreader.R;
/**
* Created by newbiechen on 17-4-15.
*/
public class StatusBarCompat
{
private static final int INVALID_VAL = -1;
private static final int COLOR_DEFAULT = Color.parseColor("#20000000");
public static void compat(Activity activity, int statusColor)
{
//在SDK21以上,设置StatusBar的Color
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
{
Window window = activity.getWindow();
//取消设置透明状态栏,使 ContentView 内容不再覆盖状态栏
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
//需要设置这个 flag 才能调用 setStatusBarColor 来设置状态栏颜色
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
//设置状态栏颜色
window.setStatusBarColor(statusColor);
}
else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT)
{
int color = COLOR_DEFAULT;
ViewGroup contentView = (ViewGroup) activity.findViewById(android.R.id.content);
if (statusColor != INVALID_VAL)
{
color = statusColor;
}
View statusBarView = activity.findViewById(R.id.status_bar);
if (statusBarView == null){
statusBarView = new View(activity);
statusBarView.setId(R.id.status_bar);
ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
getStatusBarHeight(activity));
contentView.addView(statusBarView, lp);
}
statusBarView.setBackgroundColor(color);
}
}
public static void compat(Activity activity)
{
compat(activity, INVALID_VAL);
}
public static int getStatusBarHeight(Context context)
{
int result = 0;
int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android");
if (resourceId > 0)
{
result = context.getResources().getDimensionPixelSize(resourceId);
}
return result;
}
}

@ -0,0 +1,208 @@
package xyz.fycz.myreader.util;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Context;
import android.graphics.Color;
import android.os.Build;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import androidx.annotation.IntDef;
import androidx.appcompat.app.AppCompatActivity;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
/**
* @ClassName: StatusBarUtil
* @Description:
* @Author: dingchao
* @Date: 2018/11/8 15:15
*/
public class StatusBarUtil {
public final static int TYPE_MIUI = 0;
public final static int TYPE_FLYME = 1;
public final static int TYPE_M = 3;//6.0
@IntDef({TYPE_MIUI, TYPE_FLYME, TYPE_M})
@Retention(RetentionPolicy.SOURCE)
@interface ViewType {
}
/**
* 修改状态栏颜色支持4.4以上版本
*
* @param colorId 颜色
*/
public static void setStatusBarColor(AppCompatActivity activity, int colorId) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
Window window = activity.getWindow();
window.setStatusBarColor(colorId);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
//使用SystemBarTintManager,需要先将状态栏设置为透明
setTranslucentStatus(activity);
SystemBarTintManager systemBarTintManager = new SystemBarTintManager(activity);
systemBarTintManager.setStatusBarTintEnabled(true);//显示状态栏
systemBarTintManager.setStatusBarTintColor(colorId);//设置状态栏颜色
}
}
/**
* 设置状态栏透明
*/
@TargetApi(19)
public static void setTranslucentStatus(Activity activity) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
//5.x开始需要把颜色设置透明,否则导航栏会呈现系统默认的浅灰色
Window window = activity.getWindow();
View decorView = window.getDecorView();
//两个 flag 要结合使用,表示让应用的主体内容占用系统状态栏的空间
int option = View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
decorView.setSystemUiVisibility(option);
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
window.setStatusBarColor(Color.TRANSPARENT);
//导航栏颜色也可以正常设置
//window.setNavigationBarColor(Color.TRANSPARENT);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
Window window = activity.getWindow();
WindowManager.LayoutParams attributes = window.getAttributes();
int flagTranslucentStatus = WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
attributes.flags |= flagTranslucentStatus;
//int flagTranslucentNavigation = WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION; //attributes.flags |= flagTranslucentNavigation;
window.setAttributes(attributes);
}
}
/**
* 代码实现android:fitsSystemWindows
*
* @param activity
*/
public static void setRootViewFitsSystemWindows(Activity activity, boolean fitSystemWindows) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
ViewGroup winContent = (ViewGroup) activity.findViewById(android.R.id.content);
if (winContent.getChildCount() > 0) {
ViewGroup rootView = (ViewGroup) winContent.getChildAt(0);
if (rootView != null) {
rootView.setFitsSystemWindows(fitSystemWindows);
}
}
}
}
/**
* 设置状态栏深色浅色切换
*/
public static boolean setStatusBarDarkTheme(Activity activity, boolean dark) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
setStatusBarFontIconDark(activity, TYPE_M, dark);
} else if (OSUtils.isMiui()) {
setStatusBarFontIconDark(activity, TYPE_MIUI, dark);
} else if (OSUtils.isFlyme()) {
setStatusBarFontIconDark(activity, TYPE_FLYME, dark);
} else {//其他情况
return false;
}
return true;
}
return false;
}
/**
* 设置 状态栏深色浅色切换
*/
public static boolean setStatusBarFontIconDark(Activity activity, @ViewType int type, boolean dark) {
switch (type) {
case TYPE_MIUI:
return setMiuiUI(activity, dark);
case TYPE_FLYME:
return setFlymeUI(activity, dark);
case TYPE_M:
default:
return setCommonUI(activity, dark);
}
}
//设置6.0 状态栏深色浅色切换
public static boolean setCommonUI(Activity activity, boolean dark) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
View decorView = activity.getWindow().getDecorView();
if (decorView != null) {
int vis = decorView.getSystemUiVisibility();
if (dark) {
vis |= View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
} else {
vis &= ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
}
if (decorView.getSystemUiVisibility() != vis) {
decorView.setSystemUiVisibility(vis);
}
return true;
}
}
return false;
}
//设置Flyme 状态栏深色浅色切换
public static boolean setFlymeUI(Activity activity, boolean dark) {
try {
Window window = activity.getWindow();
WindowManager.LayoutParams lp = window.getAttributes();
Field darkFlag = WindowManager.LayoutParams.class.getDeclaredField("MEIZU_FLAG_DARK_STATUS_BAR_ICON");
Field meizuFlags = WindowManager.LayoutParams.class.getDeclaredField("meizuFlags");
darkFlag.setAccessible(true);
meizuFlags.setAccessible(true);
int bit = darkFlag.getInt(null);
int value = meizuFlags.getInt(lp);
if (dark) {
value |= bit;
} else {
value &= ~bit;
}
meizuFlags.setInt(lp, value);
window.setAttributes(lp);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
//设置MIUI 状态栏深色浅色切换
public static boolean setMiuiUI(Activity activity, boolean dark) {
try {
Window window = activity.getWindow();
Class<?> clazz = activity.getWindow().getClass();
@SuppressLint("PrivateApi") Class<?> layoutParams = Class.forName("android.view.MiuiWindowManager$LayoutParams");
Field field = layoutParams.getField("EXTRA_FLAG_STATUS_BAR_DARK_MODE");
int darkModeFlag = field.getInt(layoutParams);
Method extraFlagField = clazz.getDeclaredMethod("setExtraFlags", int.class, int.class);
extraFlagField.setAccessible(true);
if (dark) { //状态栏亮色且黑色字体.
extraFlagField.invoke(window, darkModeFlag, darkModeFlag);
} else {
extraFlagField.invoke(window, 0, darkModeFlag);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
//获取状态栏高度
public static int getStatusBarHeight(Context context) {
int result = 0;
int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android");
if (resourceId > 0) {
result = context.getResources().getDimensionPixelSize(resourceId);
}
return result;
}
}

@ -23,7 +23,7 @@ public class TelephonyUtil {
String tel1 = (String)getPhoneNumber.invoke(tm, 1);
IMSI = tm.getSubscriberId();
TextHelper.showText(IMSI);
ToastUtils.showInfo(IMSI);
}catch (Exception e){
e.printStackTrace();
tel = "";

@ -1,21 +0,0 @@
package xyz.fycz.myreader.util;
import android.widget.Toast;
import xyz.fycz.myreader.application.MyApplication;
public class TextHelper {
public static void showText(final String text){
MyApplication.runOnUiThread(() -> Toast.makeText(MyApplication.getApplication(),text, Toast.LENGTH_SHORT).show());
}
public static void showLongText(final String text){
MyApplication.runOnUiThread(() -> Toast.makeText(MyApplication.getApplication(),text, Toast.LENGTH_LONG).show());
}
}

@ -0,0 +1,65 @@
package xyz.fycz.myreader.util;
import androidx.annotation.NonNull;
import es.dmoral.toasty.Toasty;
import xyz.fycz.myreader.R;
import xyz.fycz.myreader.application.MyApplication;
/**
* Toast工具类对Toasty的二次封装
* https://github.com/GrenderG/Toasty
*/
public class ToastUtils {
static {
Toasty.Config.getInstance().setTextSize(14).apply();
}
public static void show(@NonNull String msg) {
MyApplication.runOnUiThread(() -> Toasty.custom(MyApplication.getmContext(), msg,
MyApplication.getmContext().getDrawable(R.drawable.ic_smile_face),
MyApplication.getmContext().getColor(R.color.toast_default),
MyApplication.getmContext().getColor(R.color.white),
Toasty.LENGTH_SHORT, true, true).show());
}
//红色
public static void showError(@NonNull String msg) {
MyApplication.runOnUiThread(() -> Toasty.custom(MyApplication.getmContext(), msg,
MyApplication.getmContext().getDrawable(R.drawable.ic_error),
MyApplication.getmContext().getColor(R.color.toast_red),
MyApplication.getmContext().getColor(R.color.white),
Toasty.LENGTH_SHORT, true, true).show());
}
//绿色
public static void showSuccess(@NonNull String msg) {
MyApplication.runOnUiThread(() -> Toasty.custom(MyApplication.getmContext(), msg,
MyApplication.getmContext().getDrawable(R.drawable.ic_success),
MyApplication.getmContext().getColor(R.color.toast_green),
MyApplication.getmContext().getColor(R.color.white),
Toasty.LENGTH_SHORT, true, true).show());
}
//蓝色
public static void showInfo(@NonNull String msg) {
MyApplication.runOnUiThread(() -> Toasty.custom(MyApplication.getmContext(), msg,
MyApplication.getmContext().getDrawable(R.drawable.ic_smile_face),
MyApplication.getmContext().getColor(R.color.toast_blue),
MyApplication.getmContext().getColor(R.color.white),
Toasty.LENGTH_SHORT, true, true).show());
}
//黄色
public static void showWarring(@NonNull String msg) {
MyApplication.runOnUiThread(() -> Toasty.warning(MyApplication.getmContext(), msg, Toasty.LENGTH_SHORT, true).show());
}
public static void showExit(@NonNull String msg) {
MyApplication.runOnUiThread(() -> Toasty.custom(MyApplication.getmContext(), msg,
MyApplication.getmContext().getDrawable(R.drawable.ic_cry_face),
MyApplication.getmContext().getColor(R.color.toast_blue),
MyApplication.getmContext().getColor(R.color.white),
Toasty.LENGTH_SHORT, true, true).show());
}
}

@ -11,6 +11,7 @@ import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
/**
@ -23,6 +24,7 @@ public class StringUtils {
private static final int HOUR_OF_DAY = 24;
private static final int DAY_OF_YESTERDAY = 2;
private static final int TIME_UNIT = 60;
private final static HashMap<Character, Integer> ChnMap = getChnMap();
//将时间转换成日期
public static String dateConvert(long time, String pattern){
@ -196,4 +198,153 @@ public class StringUtils {
}
}
}
/**
* 计算两个字符串的相似度
* @param str1
* @param str2
* @return
*/
public static float levenshtein(String str1, String str2) {
//计算两个字符串的长度。
int len1 = str1.length();
int len2 = str2.length();
//建立上面说的数组,比字符长度大一个空间
int[][]dif = new int[len1 + 1][ len2 + 1];
//赋初值,步骤B。
for (int a = 0; a <= len1; a++) {
dif[a][0] =a;
}
for (int a = 0; a <= len2; a++) {
dif[0][a] =a;
}
//计算两个字符是否一样,计算左上的值
char [] ch1 = str1.toCharArray();
char [] ch2 = str2.toCharArray();
int temp;
for (int i = 1; i <= len1; i++) {
for (int j = 1; j <= len2; j++) {
if (ch1[i - 1] == ch2[j - 1]) {
temp = 0;
} else {
temp = 1;
}
//取三个值中最小的
int temp1 = dif[i - 1][j - 1]+temp;
int temp2 = dif[i][j - 1]+1;
int temp3 = dif[i - 1][j]+1;
int arr [] = new int[]{temp1,temp2, temp3};
dif[i][j] =min(arr);
}
}
//计算相似度
float similarity = 1 - (float) dif[len1][len2] /Math.max(str1.length(), str2.length());
return similarity;
}
//得到最小值
private static int min(int[]arr) {
int min = arr[0];
for( int i :arr){
if (min > i) {
min = i;
}
}
return min;
}
/**
* 去除所有空格
* @param str
* @return
*/
public static String deleteWhitespace(String str){
return str.replaceAll("\\s*", "");
}
private static HashMap<Character, Integer> getChnMap() {
HashMap<Character, Integer> map = new HashMap<>();
String cnStr = "零一二三四五六七八九十";
char[] c = cnStr.toCharArray();
for (int i = 0; i <= 10; i++) {
map.put(c[i], i);
}
cnStr = "〇壹贰叁肆伍陆柒捌玖拾";
c = cnStr.toCharArray();
for (int i = 0; i <= 10; i++) {
map.put(c[i], i);
}
map.put('两', 2);
map.put('百', 100);
map.put('佰', 100);
map.put('千', 1000);
map.put('仟', 1000);
map.put('万', 10000);
map.put('亿', 100000000);
return map;
}
@SuppressWarnings("ConstantConditions")
public static int chineseNumToInt(String chNum) {
int result = 0;
int tmp = 0;
int billion = 0;
char[] cn = chNum.toCharArray();
// "一零二五" 形式
if (cn.length > 1 && chNum.matches("^[〇零一二三四五六七八九壹贰叁肆伍陆柒捌玖]$")) {
for (int i = 0; i < cn.length; i++) {
cn[i] = (char) (48 + ChnMap.get(cn[i]));
}
return Integer.parseInt(new String(cn));
}
// "一千零二十五", "一千二" 形式
try {
for (int i = 0; i < cn.length; i++) {
int tmpNum = ChnMap.get(cn[i]);
if (tmpNum == 100000000) {
result += tmp;
result *= tmpNum;
billion = billion * 100000000 + result;
result = 0;
tmp = 0;
} else if (tmpNum == 10000) {
result += tmp;
result *= tmpNum;
tmp = 0;
} else if (tmpNum >= 10) {
if (tmp == 0)
tmp = 1;
result += tmpNum * tmp;
tmp = 0;
} else {
if (i >= 2 && i == cn.length - 1 && ChnMap.get(cn[i - 1]) > 10)
tmp = tmpNum * ChnMap.get(cn[i - 1]) / 10;
else
tmp = tmp * 10 + tmpNum;
}
}
result += tmp + billion;
return result;
} catch (Exception e) {
return -1;
}
}
public static int stringToInt(String str) {
if (str != null) {
String num = fullToHalf(str).replaceAll("\\s", "");
try {
return Integer.parseInt(num);
} catch (Exception e) {
return chineseNumToInt(num);
}
}
return -1;
}
}

@ -5,11 +5,11 @@ import xyz.fycz.myreader.common.ErrorCode;
import xyz.fycz.myreader.entity.JsonModel;
import xyz.fycz.myreader.util.HttpUtil;
import xyz.fycz.myreader.util.JsonArrayToObjectArray;
import xyz.fycz.myreader.util.TextHelper;
import com.google.gson.Gson;
import xyz.fycz.myreader.callback.JsonCallback;
import xyz.fycz.myreader.callback.ResultCallback;
import xyz.fycz.myreader.source.HttpDataSource;
import xyz.fycz.myreader.util.ToastUtils;
import java.util.Map;
@ -223,7 +223,7 @@ public class BaseApi {
private static void noSuccess(JsonModel jsonModel, ResultCallback callback){
if (!jsonModel.isSuccess()) {
if (jsonModel.getError() == ErrorCode.no_security) {
TextHelper.showText("登录过期,请重新登录");
ToastUtils.showWarring("登录过期,请重新登录");
SysManager.logout();
} else {
if (jsonModel.getError() == 0) {

@ -20,8 +20,8 @@ import java.util.regex.Pattern;
public class BiQuGeReadCrawler implements ReadCrawler, BookInfoCrawler {
private static final String NAME_SPACE = "https://www.52bqg.com";
private static final String NOVEL_SEARCH = "https://www.52bqg.com/modules/article/search.php";
private static final String NAME_SPACE = "https://www.52bqg.net";
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";
private ReadCrawler rc = new TianLaiReadCrawler();

@ -58,7 +58,7 @@ public class TianLaiReadCrawler implements ReadCrawler{
char c = 160;
String spaec = "" + c;
content = content.replace(spaec, " ");
content = content.replace("一秒记住【笔趣阁 www.52bqg.com】,精彩小说无弹窗免费阅读!", "");
content = content.replace("一秒记住【笔趣阁 www.52bqg.net】,精彩小说无弹窗免费阅读!", "");
return content;
} else {
return "";

@ -0,0 +1,147 @@
package xyz.fycz.myreader.widget;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.drawable.GradientDrawable;
import android.util.AttributeSet;
import androidx.appcompat.widget.AppCompatButton;
import xyz.fycz.myreader.R;
/**
* @author fengyue
* @date 2020/8/24 21:17
*/
public class ProgressButton extends AppCompatButton {
private float mCornerRadius = 0;
private float mProgressMargin = 0;
private boolean mFinish;
private int mProgress;
private int mMaxProgress = 100;
private int mMinProgress = 0;
private GradientDrawable mDrawableButton;
private GradientDrawable mDrawableProgressBackground;
private GradientDrawable mDrawableProgress;
public ProgressButton(Context context, AttributeSet attrs) {
super(context, attrs);
initialize(context, attrs);
}
public ProgressButton(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initialize(context, attrs);
}
private void initialize(Context context, AttributeSet attrs) {
//Progress background drawable
mDrawableProgressBackground = new GradientDrawable();
//Progress drawable
mDrawableProgress = new GradientDrawable();
//Normal drawable
mDrawableButton = new GradientDrawable();
//Get default normal color
int defaultButtonColor = getResources().getColor(R.color.toast_default);
//Get default progress color
int defaultProgressColor = getResources().getColor(R.color.colorAccent, null);
//Get default progress background color
int defaultBackColor = getResources().getColor(R.color.toast_default, null);
TypedArray attr = context.obtainStyledAttributes(attrs, R.styleable.ProgressButton);
try {
mProgressMargin = attr.getDimension(R.styleable.ProgressButton_progressMargin, mProgressMargin);
mCornerRadius = attr.getDimension(R.styleable.ProgressButton_cornerRadius, mCornerRadius);
//Get custom normal color
int buttonColor = attr.getColor(R.styleable.ProgressButton_buttonColor, defaultButtonColor);
//Set normal color
mDrawableButton.setColor(buttonColor);
//Get custom progress background color
int progressBackColor = attr.getColor(R.styleable.ProgressButton_progressBackColor, defaultBackColor);
//Set progress background drawable color
mDrawableProgressBackground.setColor(progressBackColor);
//Get custom progress color
int progressColor = attr.getColor(R.styleable.ProgressButton_progressColor, defaultProgressColor);
//Set progress drawable color
mDrawableProgress.setColor(progressColor);
//Get default progress
mProgress = attr.getInteger(R.styleable.ProgressButton_progress, mProgress);
//Get minimum progress
mMinProgress = attr.getInteger(R.styleable.ProgressButton_minProgress, mMinProgress);
//Get maximize progress
mMaxProgress = attr.getInteger(R.styleable.ProgressButton_maxProgress, mMaxProgress);
} finally {
attr.recycle();
}
//Set corner radius
mDrawableButton.setCornerRadius(mCornerRadius);
mDrawableProgressBackground.setCornerRadius(mCornerRadius);
mDrawableProgress.setCornerRadius(mCornerRadius - mProgressMargin);
setBackgroundDrawable(mDrawableButton);
mFinish = false;
}
@Override
protected void onDraw(Canvas canvas) {
if (mProgress > mMinProgress && mProgress <= mMaxProgress && !mFinish) {
//Calculate the width of progress
float progressWidth =
(float) getMeasuredWidth() * ((float) (mProgress - mMinProgress) / mMaxProgress - mMinProgress);
//If progress width less than 2x corner radius, the radius of progress will be wrong
if (progressWidth < mCornerRadius * 2) {
progressWidth = mCornerRadius * 2;
}
//Set rect of progress
mDrawableProgress.setBounds((int) mProgressMargin, (int) mProgressMargin,
(int) (progressWidth - mProgressMargin), getMeasuredHeight() - (int) mProgressMargin);
//Draw progress
mDrawableProgress.draw(canvas);
if (mProgress == mMaxProgress) {
setBackgroundDrawable(mDrawableButton);
mFinish = true;
}
}
super.onDraw(canvas);
}
/**
* Set current progress
*/
public void setProgress(int progress) {
if (!mFinish) {
mProgress = progress;
setBackgroundDrawable(mDrawableProgressBackground);
invalidate();
}
}
public void setButtonColor(int color){
mDrawableButton.setColor(color);
invalidate();
}
public void setMaxProgress(int maxProgress) {
mMaxProgress = maxProgress;
}
public void setMinProgress(int minProgress) {
mMinProgress = minProgress;
}
public void reset() {
mFinish = false;
mProgress = mMinProgress;
}
}

@ -2,6 +2,7 @@ package xyz.fycz.myreader.widget.page;
import android.content.Context;
import android.graphics.*;
import android.text.TextUtils;
import androidx.core.content.ContextCompat;
import android.text.TextPaint;
import io.reactivex.Single;
@ -9,28 +10,27 @@ import io.reactivex.SingleObserver;
import io.reactivex.SingleOnSubscribe;
import io.reactivex.disposables.Disposable;
import xyz.fycz.myreader.R;
import xyz.fycz.myreader.application.MyApplication;
import xyz.fycz.myreader.application.SysManager;
import xyz.fycz.myreader.callback.ResultCallback;
import xyz.fycz.myreader.common.APPCONST;
import xyz.fycz.myreader.enums.Font;
import xyz.fycz.myreader.enums.Language;
import xyz.fycz.myreader.greendao.entity.Book;
import xyz.fycz.myreader.entity.Setting;
import xyz.fycz.myreader.greendao.entity.Chapter;
import xyz.fycz.myreader.util.TextHelper;
import xyz.fycz.myreader.util.ToastUtils;
import xyz.fycz.myreader.util.utils.RxUtils;
import xyz.fycz.myreader.util.utils.ScreenUtils;
import xyz.fycz.myreader.util.utils.StringUtils;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
import static xyz.fycz.myreader.common.APPCONST.*;
/**
* Created by newbiechen on 17-7-1.
*/
@ -75,7 +75,7 @@ public abstract class PageLoader {
// 绘制电池的画笔
private Paint mBatteryPaint;
// 绘制提示的画笔
private Paint mTipPaint;
private TextPaint mTipPaint;
// 绘制标题的画笔
private Paint mTitlePaint;
// 绘制背景颜色的画笔(用来擦除需要重绘的部分)
@ -161,7 +161,7 @@ public abstract class PageLoader {
prepareBook();*/
}
public void init(){
public void init() {
// 初始化数据
initData();
// 初始化画笔
@ -193,6 +193,7 @@ public abstract class PageLoader {
/**
* 作用设置与文字相关的参数
*
* @param textSize
*/
private void setUpTextParams(float textSize) {
@ -209,7 +210,7 @@ public abstract class PageLoader {
private void initPaint() {
// 绘制提示的画笔
mTipPaint = new Paint();
mTipPaint = new TextPaint();
mTipPaint.setColor(mTextColor);
mTipPaint.setTextAlign(Paint.Align.LEFT); // 绘制的起始点
mTipPaint.setTextSize(ScreenUtils.spToPx(DEFAULT_TIP_SIZE)); // Tip默认的字体大小
@ -433,7 +434,6 @@ public abstract class PageLoader {
/**
* 设置页面样式
*
*/
public void setPageStyle(boolean dayMode) {
/*if (pageStyle != PageStyle.NIGHT) {
@ -445,13 +445,38 @@ public abstract class PageLoader {
return;
}
*/
int textColorId;
int bgColorId;
switch (mSettingManager.getReadStyle()) {
case common:
textColorId = READ_STYLE_COMMON[0];
bgColorId = READ_STYLE_COMMON[1];
break;
case leather:
default:
textColorId = READ_STYLE_LEATHER[0];
bgColorId = READ_STYLE_LEATHER[1];
break;
case protectedEye:
textColorId = READ_STYLE_PROTECTED_EYE[0];
bgColorId = READ_STYLE_PROTECTED_EYE[1];
break;
case breen:
textColorId = READ_STYLE_BREEN_EYE[0];
bgColorId = READ_STYLE_BREEN_EYE[1];
break;
case blueDeep:
textColorId = READ_STYLE_BLUE_DEEP[0];
bgColorId = READ_STYLE_BLUE_DEEP[1];
break;
}
if (!dayMode) {
mTextColor = ContextCompat.getColor(mContext, R.color.sys_night_word);
mBgColor = ContextCompat.getColor(mContext, R.color.sys_night_bg);
mTextColor = ContextCompat.getColor(mContext, READ_STYLE_NIGHT[0]);
mBgColor = ContextCompat.getColor(mContext, READ_STYLE_NIGHT[1]);
mBatteryPaint.setColor(mTextColor);
} else {
mTextColor = ContextCompat.getColor(mContext, mSettingManager.getReadWordColor());
mBgColor = ContextCompat.getColor(mContext, mSettingManager.getReadBgColor());
mTextColor = ContextCompat.getColor(mContext, textColorId);
mBgColor = ContextCompat.getColor(mContext, bgColorId);
mBatteryPaint.setColor(Color.BLACK);
}
// 设置当前颜色样式
@ -485,9 +510,10 @@ public abstract class PageLoader {
/**
* 设置字体
*
* @param font
*/
public void setFont(Font font){
public void setFont(Font font) {
mSettingManager = SysManager.getSetting();
//获取字体
getFont(font);
@ -517,39 +543,43 @@ public abstract class PageLoader {
/**
* 获取字体
*
* @param font
*/
public void getFont(Font font){
public void getFont(Font font) {
String fontFileName = mSettingManager.getFont().fileName;
if (font == Font.本地字体){
if (font == Font.本地字体) {
fontFileName = mSettingManager.getLocalFontName();
}
File fontFile = new File(APPCONST.FONT_BOOK_DIR + fontFileName);
if (font == Font.默认字体 || !fontFile.exists()) {
mTypeFace = null;
if (!fontFile.exists()){
if (!fontFile.exists()) {
mSettingManager.setFont(Font.默认字体);
SysManager.saveSetting(mSettingManager);
}
} else {
try {
mTypeFace = Typeface.createFromFile(fontFile);
}catch (Exception e){
TextHelper.showText(e.getLocalizedMessage());
} catch (Exception e) {
ToastUtils.showError(e.getLocalizedMessage());
mSettingManager.setFont(Font.默认字体);
SysManager.saveSetting(mSettingManager);
}
}
}
/**
* 刷新章节
*
* @param chapter
*/
public void refreshChapter(Chapter chapter){
public void refreshChapter(Chapter chapter) {
chapter.setContent(null);
getChapterContent(chapter);
openChapter();
}
/**
* 设置内容与屏幕的间距
*
@ -819,6 +849,7 @@ public abstract class PageLoader {
*
*/
public abstract void getChapterContent(Chapter chapter);
/***********************************default method***********************************************/
void drawPage(Bitmap bitmap, boolean isUpdate) {
@ -850,7 +881,8 @@ public abstract class PageLoader {
, mMarginWidth, tipTop, mTipPaint);
}
} else {
canvas.drawText(mCurPage.title, mMarginWidth, tipTop, mTipPaint);
String title = TextUtils.ellipsize(mCurPage.title, mTipPaint, mDisplayWidth - 2 * mMarginWidth - mTipPaint.measureText(progress), TextUtils.TruncateAt.END).toString();
canvas.drawText(title, mMarginWidth, tipTop, mTipPaint);
}
@ -972,10 +1004,10 @@ public abstract class PageLoader {
}
//设置总距离
float interval = mTextInterval + mTextPaint.getTextSize();
float para = mTextPara + mTextPaint.getTextSize();
float titleInterval = mTitleInterval + mTitlePaint.getTextSize();
float titlePara = mTitlePara + mTextPaint.getTextSize();
float interval = mTextInterval + mTextPaint.getTextSize();
float para = mTextPara + mTextPaint.getTextSize();
float titleInterval = mTitleInterval + mTitlePaint.getTextSize();
float titlePara = mTitlePara + mTextPaint.getTextSize();
String str = null;
//对标题进行绘制
@ -1521,6 +1553,7 @@ public abstract class PageLoader {
/**
* 获取书籍进度
*
* @param durChapterIndex
* @param chapterAll
* @param durPageIndex

@ -6,6 +6,6 @@
android:viewportHeight="24">
<path
android:fillColor="@color/little_black_white"
android:fillColor="@color/white"
android:pathData="M5.938,4v16h1.414l4.648-2.789L16.649,20h1.411V4H5.938z M16.606,18.278l-4.605-2.763l-4.609,2.764 V5.454h9.215V18.278z" />
</vector>

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="1024"
android:viewportHeight="1024">
<path
android:fillColor="#FFFFFF"
android:pathData="M514,114.3c-219.9,0 -398.9,178.9 -398.9,398.8 0.1,220 179,398.9 398.9,398.9 219.9,0 398.8,-178.9 398.8,-398.8S733.9,114.3 514,114.3zM732.3,603.3v1.7c0,0.5 -0.1,1 -0.1,1.6 0,0.3 0,0.6 -0.1,0.9 0,0.5 -0.1,1 -0.2,1.5 0,0.3 -0.1,0.7 -0.1,1 -0.1,0.4 -0.1,0.8 -0.2,1.2 -0.1,0.4 -0.2,0.9 -0.2,1.3 -0.1,0.3 -0.1,0.6 -0.2,0.8 -0.1,0.6 -0.3,1.2 -0.4,1.8 0,0.1 -0.1,0.2 -0.1,0.3 -2.2,8.5 -6.6,16.6 -13.3,23.3L600.7,755.4c-20,20 -52.7,20 -72.6,0 -20,-20 -20,-52.7 0,-72.6l28.9,-28.9L347,653.9c-28.3,0 -51.4,-23.1 -51.4,-51.4 0,-28.3 23.1,-51.4 51.4,-51.4h334c13.2,0 26.4,5 36.4,15s15,23.2 15,36.4c0,0.3 -0.1,0.6 -0.1,0.8zM732.4,423.8c0,28.3 -23.1,51.4 -51.4,51.4L347,475.2c-13.2,0 -26.4,-5 -36.4,-15s-15,-23.2 -15,-36.4v-0.8,-1.6c0,-0.5 0.1,-1.1 0.1,-1.6 0,-0.3 0,-0.6 0.1,-0.9 0,-0.5 0.1,-1 0.2,-1.5 0,-0.3 0.1,-0.7 0.1,-1 0.1,-0.4 0.1,-0.8 0.2,-1.2 0.1,-0.4 0.2,-0.9 0.2,-1.3 0.1,-0.3 0.1,-0.6 0.2,-0.8 0.1,-0.6 0.3,-1.2 0.4,-1.8 0,-0.1 0.1,-0.2 0.1,-0.3 2.2,-8.5 6.6,-16.6 13.3,-23.3l116.6,-116.6c20,-20 52.7,-20 72.6,0 20,20 20,52.7 0,72.6L471,372.5h210c28.2,0 51.4,23.1 51.4,51.3z"/>
</vector>

@ -0,0 +1,7 @@
<vector android:height="24dp" android:viewportHeight="1024"
android:viewportWidth="1024" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#ffffff" android:pathData="M512,953.82c244.02,0 441.82,-197.8 441.82,-441.82C953.82,267.98 756.02,70.18 512,70.18 267.98,70.18 70.18,267.98 70.18,512c0,244.02 197.8,441.82 441.82,441.82zM512,888.36a376.36,376.36 0,1 1,0 -752.73,376.36 376.36,0 0,1 0,752.73z"/>
<path android:fillColor="#ffffff" android:pathData="M730.54,699.53c-121.95,-121.95 -317.66,-124.49 -437.07,-5.07a32.73,32.73 0,1 0,46.31 46.27c93.56,-93.56 247.83,-91.55 344.45,5.07a32.73,32.73 0,1 0,46.31 -46.23z"/>
<path android:fillColor="#ffffff" android:pathData="M358.59,433.95m-51.14,0a51.14,51.14 0,1 0,102.27 0,51.14 51.14,0 1,0 -102.27,0Z"/>
<path android:fillColor="#ffffff" android:pathData="M665.41,433.95m-51.14,0a51.14,51.14 0,1 0,102.27 0,51.14 51.14,0 1,0 -102.27,0Z"/>
</vector>

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="1024"
android:viewportHeight="1024">
<path
android:pathData="M696.6,257.2L326.1,257.2c-145.1,0 -262.8,114.7 -262.8,256s117.7,256 262.8,256h370.5c145.1,0 262.8,-114.7 262.8,-256 -0.1,-141.4 -117.7,-256 -262.8,-256zM703.3,705.2c-106,0 -192,-86 -192,-192s86,-192 192,-192 192,86 192,192 -85.9,192 -192,192z"
android:fillColor="#FFFFFF"/>
</vector>

@ -0,0 +1,4 @@
<vector android:height="24dp" android:viewportHeight="1024"
android:viewportWidth="1024" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FFFFFF" android:pathData="M512,64c247.42,0 448,200.58 448,448s-200.58,448 -448,448S64,759.42 64,512 264.58,64 512,64zM512,128C299.93,128 128,299.93 128,512s171.93,384 384,384 384,-171.93 384,-384S724.07,128 512,128zM684.42,299.31l45.27,45.25L562.24,512l167.45,167.45 -45.27,45.25 -167.45,-167.45 -167.42,167.47 -45.27,-45.27L471.72,512l-167.45,-167.45 45.27,-45.25 167.42,167.42 167.47,-167.42z"/>
</vector>

@ -6,9 +6,9 @@
android:viewportHeight="24">
<path
android:fillColor="#595757"
android:fillColor="#FFFFFF"
android:pathData="M18.545,18.304c0,0.131-0.11,0.242-0.241,0.242H5.696c-0.131,0-0.242-0.111-0.242-0.242V5.697 c0-0.131,0.111-0.243,0.242-0.243H12V4H5.696C4.76,4,4,4.762,4,5.697v12.606C4,19.239,4.76,20,5.696,20h12.607 C19.239,20,20,19.239,20,18.304v-6.303h-1.455V18.304z" />
<path
android:fillColor="#595757"
android:fillColor="#FFFFFF"
android:pathData="M 19.272 4 L 13.843 4 L 13.843 5.454 L 17.517 5.454 L 7.464 15.508 L 8.491 16.536 L 18.545 6.482 L 18.545 10.157 L 20 10.157 L 20 4.727 L 20 4 Z" />
</vector>

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="1024"
android:viewportHeight="1024">
<path
android:fillColor="#FF000000"
android:pathData="M512,77C271.8,77 77,271.8 77,512c0,240.2 194.8,435 435,435 240.2,0 435,-194.8 435,-435C947,271.8 752.2,77 512,77L512,77zM509.2,816.4c-35.4,0 -64.2,-28.2 -64.2,-62.9s28.7,-62.9 64.2,-62.9c35.4,0 64.2,28.2 64.2,62.9S544.7,816.4 509.2,816.4L509.2,816.4zM681.6,460.5c-12.6,19.8 -39.3,46.7 -80.3,80.8 -21.2,17.6 -34.4,31.8 -39.5,42.6 -5.1,10.7 -7.5,29.9 -7,57.6l-91.4,0c-0.2,-13.1 -0.4,-21.1 -0.4,-24 0,-29.6 4.9,-53.9 14.7,-73 9.8,-19.1 29.4,-40.6 58.7,-64.4 29.3,-23.9 46.9,-39.5 52.6,-46.9 8.8,-11.7 13.3,-24.6 13.3,-38.6 0,-19.5 -7.9,-36.2 -23.5,-50.2 -15.6,-13.9 -36.8,-20.9 -63.3,-20.9 -25.6,0 -47,7.3 -64.2,21.8 -17.2,14.5 -32,46.5 -35.5,66.3 -3.3,18.7 -93.4,26.6 -92.3,-11.3 1.1,-37.9 20.8,-79 54.6,-108.8 33.8,-29.8 78.2,-44.7 133.1,-44.7 57.8,0 103.7,15.1 137.9,45.3 34.2,30.2 51.2,65.3 51.2,105.4C700.4,419.7 694.1,440.7 681.6,460.5L681.6,460.5z"/>
</vector>

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="1024"
android:viewportHeight="1024">
<path
android:pathData="M816.51,368.19l-55.36,32A285.63,285.63 0,0 1,800 544c0,158.82 -129.18,288 -288,288 -106.37,0 -199.26,-58.14 -249.12,-144.16A285.86,285.86 0,0 1,224 544c0,-158.82 129.22,-288 288,-288v96l192,-128 -192,-128v96C317.92,192 160,349.89 160,544c0,64.06 17.5,124 47.52,175.81C268.48,824.96 381.98,896 512,896c194.11,0 352,-157.92 352,-352 0,-64.06 -17.47,-124 -47.49,-175.81"
android:fillColor="#FFFFFF"/>
</vector>

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#595757"
android:pathData="M12,15.43 C10.109,15.43,8.572,13.891,8.572,12 S10.109,8.57,12,8.57 S15.428,10.109,15.428,12 S13.891,15.43,12,15.43 Z M12,10.096 C10.949,10.096,10.096,10.95,10.096,12 S10.95,13.904,12,13.904 S13.904,13.05,13.904,12 S13.051,10.096,12,10.096 Z" />
<path
android:fillColor="#595757"
android:pathData="M13.735,20 L10.261,20 L10.12,18.065 C10.102,17.807,9.944,17.585,9.721,17.492 C9.472,17.387,9.214,17.429,9.024,17.592 L7.568,18.848 L5.113,16.391 L6.369,14.937 C6.531,14.749,6.573,14.49,6.477,14.258 C6.376,14.013,6.166,13.857,5.913,13.836 L4,13.697 L4,10.226 L5.916,10.085 C6.164,10.066,6.378,9.913,6.473,9.683 C6.574,9.438,6.536,9.185,6.371,8.992 L5.113,7.539 L7.573,5.094 L9.026,6.376 C9.222,6.544,9.495,6.605,9.703,6.522 L9.844,6.461 C10.026,6.273,10.107,6.141,10.119,5.974 L10.262,4 L13.734,4 L13.877,5.894 C13.895,6.139,14.041,6.335,14.277,6.43 C14.527,6.537,14.786,6.494,14.975,6.332 L16.427,5.073 L18.886,7.531 L17.629,8.984 C17.467,9.172,17.426,9.431,17.521,9.664 C17.622,9.909,17.833,10.066,18.085,10.085 L20,10.227 L20,13.698 L18.085,13.837 C17.837,13.858,17.623,14.011,17.528,14.242 C17.426,14.487,17.465,14.747,17.63,14.94 L18.886,16.391 L16.429,18.85 L14.975,17.594 C14.799,17.444,14.544,17.398,14.322,17.479 L14.295,17.493 C14.051,17.594,13.894,17.816,13.876,18.068 L13.735,20 Z M11.561,18.604 L12.437,18.604 L12.482,17.963 C12.538,17.216,13.011,16.538,13.691,16.232 L13.737,16.211 C14.526,15.883,15.308,16.04,15.886,16.54 L16.358,16.945 L16.98,16.321 L16.574,15.852 C16.064,15.26,15.933,14.446,16.231,13.725 C16.535,12.993,17.206,12.502,17.982,12.446 L18.604,12.399 L18.604,11.524 L17.984,11.477 C17.207,11.421,16.536,10.938,16.239,10.215 C15.935,9.485,16.065,8.664,16.574,8.07 L16.98,7.601 L16.358,6.979 L15.886,7.386 C15.308,7.885,14.472,8.022,13.761,7.729 C13.029,7.428,12.54,6.763,12.482,5.996 L12.438,5.397 L11.558,5.397 L11.514,6 C11.457,6.773,10.973,7.438,10.252,7.733 L10.091,7.789 C9.416,8.008,8.652,7.856,8.112,7.392 L7.639,6.982 L7.02,7.602 L7.426,8.075 C7.936,8.665,8.067,9.479,7.77,10.202 C7.467,10.931,6.796,11.422,6.02,11.477 L5.397,11.524 L5.397,12.399 L6.019,12.446 C6.796,12.503,7.465,12.987,7.762,13.71 C8.066,14.44,7.935,15.261,7.426,15.852 L7.02,16.32 L7.64,16.941 L8.112,16.535 C8.692,16.035,9.528,15.898,10.239,16.194 C10.958,16.488,11.458,17.181,11.515,17.961 L11.561,18.604 Z" />
</vector>

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24.046875dp"
android:height="24dp"
android:viewportWidth="1026"
android:viewportHeight="1024">
<path
android:fillColor="#FFFFFF"
android:pathData="M495.46,830.66c-187.14,0 -264.95,-168.22 -268.19,-175.4l62.97,-28.31c2.49,5.49 62.21,134.67 205.19,134.67 153.07,-1.79 211.3,-129.21 213.68,-134.63l63.1,28c-3.14,7.08 -79.05,173.36 -273.13,175.64l-3.63,0.03zM500.16,991.22c-256.97,0 -466.03,-209.06 -466.03,-466.03s209.06,-466.03 466.03,-466.03 466.03,209.06 466.03,466.03 -209.06,466.03 -466.03,466.03zM500.16,128.2c-218.9,0 -396.99,178.09 -396.99,396.99s178.09,396.99 396.99,396.99 396.99,-178.09 396.99,-396.99 -178.06,-396.99 -396.99,-396.99zM311.09,444.27c0,29.69 24.06,53.82 53.82,53.82s53.82,-24.1 53.82,-53.82 -24.06,-53.82 -53.82,-53.82 -53.82,24.1 -53.82,53.82zM580.77,444.27c0,29.69 24.06,53.82 53.82,53.82s53.82,-24.1 53.82,-53.82 -24.06,-53.82 -53.82,-53.82 -53.82,24.1 -53.82,53.82z"/>
</vector>

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="1024"
android:viewportHeight="1024">
<path
android:pathData="M960,512c0,97.76 -28.7,185.22 -85.66,263.26 -56.96,78.02 -130.5,131.84 -220.64,161.86 -10.3,1.82 -18.37,0.45 -22.85,-4.03a22.4,22.4 0,0 1,-7.2 -17.5v-122.88c0,-37.63 -10.3,-65.44 -30.46,-82.91a409.86,409.86 0,0 0,59.62 -10.37,222.75 222.75,0 0,0 54.72,-22.82c18.85,-10.78 34.53,-23.36 47.1,-38.59 12.54,-15.23 22.85,-35.9 30.91,-61.44 8.1,-25.57 12.13,-54.69 12.13,-87.9 0,-47.07 -15.23,-86.98 -46.21,-120.16 14.37,-35.46 13.02,-74.91 -4.48,-118.85 -10.75,-3.62 -26.43,-1.34 -47.07,6.27a301.44,301.44 0,0 0,-53.82 25.57l-21.98,13.89A407.78,407.78 0,0 0,512 280.16c-38.56,0 -75.78,4.93 -112.1,15.23a444.48,444.48 0,0 0,-24.67 -15.68c-10.34,-6.27 -26.46,-13.89 -48.9,-22.43 -21.95,-8.96 -39.01,-11.23 -50.24,-8.06 -17.02,43.94 -18.37,83.42 -4.03,118.85 -30.5,33.63 -46.18,73.54 -46.18,120.61 0,33.22 4.03,62.34 12.13,87.46 8.03,25.12 18.37,45.76 30.5,61.44 12.54,15.68 28.22,28.7 47.07,39.04 18.85,10.3 37.22,17.92 54.72,22.82a409.6,409.6 0,0 0,59.65 10.37c-15.71,13.86 -25.12,34.05 -28.7,60.06a99.74,99.74 0,0 1,-26.46 8.51,178.21 178.21,0 0,1 -33.18,2.69c-13.02,0 -25.57,-4.03 -38.14,-12.54 -12.54,-8.51 -23.3,-20.64 -32.26,-36.32a97.47,97.47 0,0 0,-28.26 -30.5c-11.23,-8.06 -21.09,-12.58 -28.7,-13.92l-11.65,-1.79c-8.1,0 -13.92,0.93 -17.06,2.69 -3.14,1.79 -4.03,4.03 -2.69,6.72 1.34,2.69 3.14,5.41 5.38,8.1 2.24,2.69 4.93,4.93 7.62,7.17l4.03,2.69c8.54,4.03 17.06,11.23 25.57,21.98 8.54,10.75 14.37,20.64 18.4,29.6l5.82,13.44c4.93,14.82 13.44,26.91 25.57,35.87 12.1,8.99 25.09,14.82 39.01,17.5 13.89,2.69 27.36,4.03 40.35,4.03 12.99,0 23.78,-0.45 32.29,-2.24l13.47,-2.24c0,14.78 0,32.29 0.42,52.03 0,19.74 0.48,30.5 0.48,31.39a22.62,22.62 0,0 1,-7.65 17.47c-4.93,4.48 -12.99,5.82 -23.3,4.03 -90.14,-30.05 -163.68,-83.84 -220.64,-161.89C92.26,697.22 64,609.31 64,512c0,-81.15 20.19,-156.06 60.1,-224.67a445.18,445.18 0,0 1,163.23 -163.23C355.94,84.19 430.82,64 512,64s156.06,20.19 224.67,60.1a445.18,445.18 0,0 1,163.23 163.23C939.81,355.49 960,430.85 960,512"
android:fillColor="#000000"/>
</vector>

@ -0,0 +1,4 @@
<vector android:height="24dp" android:viewportHeight="1024"
android:viewportWidth="1024" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FFFFFF" android:pathData="M512,1015.34c-277.91,0 -503.2,-225.29 -503.2,-503.2s225.29,-503.2 503.2,-503.2c277.91,0 503.2,225.29 503.2,503.2s-225.29,503.2 -503.2,503.2zM512,71.85c-243.16,0 -440.3,197.13 -440.3,440.3s197.13,440.3 440.3,440.3 440.3,-197.13 440.3,-440.3 -197.13,-440.3 -440.3,-440.3zM713.04,337.11c8.68,-15.05 3.54,-34.27 -11.51,-42.96s-34.27,-3.54 -42.96,11.51l-201.15,348.36 -112.53,-103.77c-11.86,-12.67 -31.76,-13.33 -44.45,-1.45 -12.68,11.88 -13.31,31.78 -1.43,44.45l143.78,132.62c11.88,12.67 31.78,13.31 44.45,1.43 3.83,-3.58 225.79,-390.19 225.79,-390.19z"/>
</vector>

@ -0,0 +1,334 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include layout="@layout/toolbar"/>
<ScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="25dp"
android:paddingLeft="5dp"
android:paddingRight="5dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_centerInParent="true"
android:textColor="@color/btn_black"
android:text="@string/read_setting"/>
</RelativeLayout>
<RelativeLayout
android:id="@+id/more_setting_rl_volume"
android:layout_width="match_parent"
android:layout_height="60dp"
android:gravity="center"
android:paddingLeft="20dp"
android:paddingRight="20dp"
android:background="@drawable/selector_common_bg">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:textColor="@color/title_black"
android:textSize="@dimen/text_normal_size"
android:text="@string/volume_turn_page"/>
<androidx.appcompat.widget.SwitchCompat
android:id="@+id/more_setting_sc_volume"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_alignParentEnd="true"
android:clickable="false"
android:longClickable="false"/>
</RelativeLayout>
<RelativeLayout
android:id="@+id/more_setting_rl_reset_screen"
android:layout_width="match_parent"
android:layout_height="60dp"
android:gravity="center"
android:paddingLeft="20dp"
android:paddingRight="20dp"
android:background="@drawable/selector_common_bg">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/title_black"
android:layout_centerVertical="true"
android:textSize="@dimen/text_normal_size"
android:text="@string/reset_screen_time"/>
<androidx.appcompat.widget.AppCompatSpinner
android:id="@+id/more_setting_sc_reset_screen"
android:layout_width="115dp"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_alignParentEnd="true"
android:gravity="center"
android:dropDownWidth="75dp"
android:clickable="false"
android:longClickable="false"/>
</RelativeLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="25dp"
android:paddingLeft="5dp"
android:paddingRight="5dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_centerInParent="true"
android:textColor="@color/btn_black"
android:text="@string/bookcase_setting"/>
</RelativeLayout>
<RelativeLayout
android:id="@+id/more_setting_rl_auto_refresh"
android:layout_width="match_parent"
android:layout_height="60dp"
android:gravity="center"
android:paddingLeft="20dp"
android:paddingRight="20dp"
android:background="@drawable/selector_common_bg">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_centerVertical="true"
android:background="@drawable/selector_common_bg">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="@dimen/text_normal_size"
android:textColor="@color/title_black"
android:text="@string/auto_refresh"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop="5dp"
android:textColor="@color/gray"
android:text="@string/auto_refresh_tip"/>
</LinearLayout>
<androidx.appcompat.widget.SwitchCompat
android:id="@+id/more_setting_sc_auto_refresh"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_alignParentEnd="true"
android:clickable="false"
android:longClickable="false"/>
</RelativeLayout>
<LinearLayout
android:id="@+id/more_setting_ll_close_refresh"
android:layout_width="match_parent"
android:layout_height="60dp"
android:paddingTop="8dp"
android:paddingLeft="20dp"
android:paddingRight="20dp"
android:orientation="vertical"
android:background="@drawable/selector_common_bg">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="@dimen/text_normal_size"
android:textColor="@color/title_black"
android:text="@string/close_refresh"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop="5dp"
android:textColor="@color/gray"
android:text="@string/close_refresh_tip"/>
</LinearLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="25dp"
android:paddingLeft="5dp"
android:paddingRight="5dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_centerInParent="true"
android:textColor="@color/btn_black"
android:text="@string/change_source_setting"/>
<ImageView
android:id="@+id/more_setting_iv_match_chapter_tip"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:src="@drawable/ic_question"
android:tint="@color/grey"/>
</RelativeLayout>
<RelativeLayout
android:id="@+id/more_setting_rl_match_chapter"
android:layout_width="match_parent"
android:layout_height="60dp"
android:gravity="center"
android:paddingLeft="20dp"
android:paddingRight="20dp"
android:background="@drawable/selector_common_bg">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:textColor="@color/title_black"
android:textSize="@dimen/text_normal_size"
android:text="@string/match_chapters"/>
<androidx.appcompat.widget.SwitchCompat
android:id="@+id/more_setting_sc_match_chapter"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_alignParentEnd="true"
android:clickable="false"
android:longClickable="false"/>
</RelativeLayout>
<RelativeLayout
android:id="@+id/more_setting_rl_match_chapter_suitability"
android:layout_width="match_parent"
android:layout_height="60dp"
android:gravity="center"
android:paddingLeft="20dp"
android:paddingRight="20dp"
android:background="@drawable/selector_common_bg">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:textSize="@dimen/text_normal_size"
android:textColor="@color/title_black"
android:text="@string/match_chapters_sui"/>
<androidx.appcompat.widget.AppCompatSpinner
android:id="@+id/more_setting_sc_match_chapter_suitability"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_alignParentEnd="true"
android:gravity="center"
android:dropDownWidth="60dp"
android:textColor="@color/title_black"
android:clickable="false"
android:longClickable="false"/>
</RelativeLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="25dp"
android:paddingLeft="5dp"
android:paddingRight="5dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_centerInParent="true"
android:textColor="@color/btn_black"
android:text="@string/cathe_setting"/>
</RelativeLayout>
<RelativeLayout
android:id="@+id/more_setting_rl_cathe_gap"
android:layout_width="match_parent"
android:layout_height="60dp"
android:gravity="center"
android:paddingLeft="20dp"
android:paddingRight="20dp"
android:background="@drawable/selector_common_bg">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:textColor="@color/title_black"
android:textSize="@dimen/text_normal_size"
android:text="@string/cathe_gap"/>
<androidx.appcompat.widget.AppCompatSpinner
android:id="@+id/more_setting_sc_cathe_gap"
android:layout_width="115dp"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_alignParentEnd="true"
android:gravity="center"
android:dropDownWidth="75dp"
android:textColor="@color/title_black"
android:clickable="false"
android:longClickable="false"/>
</RelativeLayout>
<LinearLayout
android:id="@+id/more_setting_ll_download_all"
android:layout_width="match_parent"
android:layout_height="60dp"
android:paddingTop="8dp"
android:paddingLeft="20dp"
android:paddingRight="20dp"
android:orientation="vertical"
android:background="@drawable/selector_common_bg">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="@dimen/text_normal_size"
android:textColor="@color/title_black"
android:text="@string/download_all"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop="5dp"
android:textColor="@color/gray"
android:text="@string/download_all_tip"/>
</LinearLayout>
<RelativeLayout
android:id="@+id/more_setting_rl_delete_cathe"
android:layout_width="match_parent"
android:layout_height="50dp"
android:paddingLeft="20dp"
android:paddingRight="20dp"
android:background="@drawable/selector_common_bg">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:textColor="@color/title_black"
android:textSize="@dimen/text_normal_size"
android:text="@string/clear_cathe"/>
</RelativeLayout>
</LinearLayout>
</ScrollView>
</LinearLayout>

@ -1,51 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:fitsSystemWindows="true"
android:background="@color/sys_bg2"
tools:context="xyz.fycz.myreader.ui.activity.FontsActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<include layout="@layout/title_base">
</include>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="50dp"
android:padding="8dp"
android:orientation="horizontal">
<TextView
android:layout_width="0dp"
android:layout_weight="8"
android:layout_height="match_parent"
android:gravity="center_vertical"
android:text="音量键翻页"
/>
<Switch
android:id="@+id/switch_hide_status"
android:layout_width="0dp"
android:layout_weight="2"
android:layout_height="match_parent" />
</LinearLayout>
</LinearLayout>
<ProgressBar
android:id="@+id/pb_loading"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:visibility="gone"/>
</RelativeLayout>

@ -61,18 +61,27 @@
android:gravity="center"
android:orientation="horizontal"
android:paddingRight="10dp">
<ImageView
android:id="@+id/iv_change_source"
android:layout_width="33dp"
android:layout_height="match_parent"
android:tint="@color/little_black_white"
android:src="@drawable/ic_change_source"
android:visibility="gone"/>
<ImageView
android:id="@+id/iv_refresh"
android:layout_width="25dp"
android:layout_marginLeft="15dp"
android:layout_width="30dp"
android:layout_height="match_parent"
app:srcCompat="@mipmap/ic_refresh"/>
android:tint="@color/little_black_white"
android:src="@drawable/ic_refresh"/>
<ImageView
android:id="@+id/iv_book_mark"
android:layout_marginLeft="12dp"
android:layout_width="33dp"
android:layout_height="match_parent"
app:srcCompat="@drawable/ic_bookmark"/>
android:tint="@color/little_black_white"
android:src="@drawable/ic_bookmark"/>
<ImageView
android:id="@+id/iv_voice_read"
android:layout_width="25dp"

@ -258,7 +258,14 @@
</LinearLayout>
<TextView
android:id="@+id/tv_read_setting_more"
android:padding="2dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="更多设置 >>"
android:textColor="@color/sys_dialog_setting_word_bright"
android:gravity="center_horizontal"/>
</LinearLayout>

@ -227,7 +227,7 @@
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_gravity="center_vertical"
android:src="@drawable/ic_launch"
android:src="@drawable/ic_social_github"
app:tint="@color/title_black"/>
<TextView

@ -29,55 +29,38 @@
</androidx.cardview.widget.CardView>
<LinearLayout
android:id="@+id/book_detail_author_type"
<TextView
android:id="@+id/book_detail_tv_author"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignTop="@+id/cover"
android:layout_marginLeft="14dp"
android:layout_marginTop="30dp"
android:layout_toRightOf="@+id/cover">
<TextView
android:id="@+id/book_detail_tv_author"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="1"
android:textColor="@color/white"
tools:text=" 茶叶蛋" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=" | "
android:textColor="@color/little_black_white"/>
<TextView
android:id="@+id/book_detail_tv_type"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="1"
android:textColor="@color/white"
tools:text="仙侠" />
</LinearLayout>
android:layout_toRightOf="@+id/cover"
android:ellipsize="end"
android:maxLines="1"
android:textColor="@color/md_orange_800"
tools:text=" 茶叶蛋" />
<TextView
android:id="@+id/book_detail_newest_chapter"
android:id="@+id/book_detail_tv_type"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/book_detail_author_type"
android:layout_alignLeft="@id/book_detail_author_type"
android:layout_below="@+id/book_detail_tv_author"
android:layout_alignLeft="@id/book_detail_tv_author"
android:layout_marginTop="6dp"
android:ellipsize="end"
android:maxLines="1"
android:textColor="@color/white"
tools:text="最新章节" />
tools:text="仙侠" />
<TextView
android:id="@+id/book_detail_source"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/book_detail_newest_chapter"
android:layout_alignLeft="@id/book_detail_newest_chapter"
android:layout_below="@id/book_detail_tv_type"
android:layout_alignLeft="@id/book_detail_tv_type"
android:layout_marginTop="6dp"
android:textColor="@color/white"
tools:text="书源" />

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
android:layout_width="match_parent"
android:layout_height="wrap_content" xmlns:app="http://schemas.android.com/apk/res-auto">
<LinearLayout
android:layout_width="match_parent"
@ -35,14 +35,25 @@
android:textColor="#313031"
android:textSize="18sp" />
<Button
android:id="@+id/btn_font_use"
android:layout_width="80dp"
android:layout_height="40dp"
android:background="@drawable/font_btn_selector"
android:text="@string/font_use"
android:textColor="@drawable/font_btn_selector"
android:textSize="14sp" />
<RelativeLayout
android:layout_width="80dp"
android:layout_height="40dp">
<xyz.fycz.myreader.widget.ProgressButton
android:id="@+id/btn_font_use"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="@string/font_use"
android:textAllCaps="false"
app:progressColor="@color/colorAccent"
android:textColor="@color/white"
app:buttonColor="@color/sys_blue_littler"
app:minProgress="0"
android:textSize="14sp" />
</RelativeLayout>
</LinearLayout>

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.Toolbar
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/colorPrimary"
android:minHeight="?attr/actionBarSize"
android:fitsSystemWindows="true"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
>
<!-- android:theme="@style/Theme.ToolBar.Menu"-->
</androidx.appcompat.widget.Toolbar>

@ -39,6 +39,13 @@
android:title="@string/menu_bookcase_download_all"
app:showAsAction="never"
android:visible="true"/>
<item
android:id="@+id/action_setting"
android:icon="@drawable/ic_settings"
android:title="@string/menu_settings"
app:showAsAction="never"
android:visible="true"/>
<item
android:id="@+id/action_about"
android:icon="@drawable/ic_about"

@ -1,19 +1,30 @@
<?xml version ="1.0" encoding ="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<menu xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<item
android:id="@+id/action_change_source"
android:icon="@mipmap/ic_menu_exchange"
android:title="更换书源"
app:showAsAction="always" />
android:id="@+id/action_change_source"
android:icon="@drawable/ic_change_source"
android:title="@string/menu_change_source"
app:showAsAction="ifRoom"/>
<item
android:id="@+id/action_reload"
android:icon="@mipmap/ic_menu_refresh"
android:title="重新加载"/>
android:id="@+id/action_reload"
android:icon="@drawable/ic_refresh"
android:title="@string/menu_reload"
app:showAsAction="never"/>
<item
android:id="@+id/action_open_link"
android:title="打开链接" />
android:id="@+id/action_open_link"
android:icon="@drawable/ic_link"
android:title="@string/menu_open_link"
app:showAsAction="never"/>
<item
android:id="@+id/action_is_update"
android:title="@string/menu_is_update"
android:icon="@drawable/ic_enable"
android:checkable="true"
android:checked="true"
app:showAsAction="never"/>
</menu>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

@ -8,18 +8,35 @@
</declare-styleable>
<declare-styleable name="Animation_emerge">
<attr name="windowEnterAnimation" format="integer" />
<attr name="windowExitAnimation" format="integer" />
<attr name="windowEnterAnimation" format="integer"/>
<attr name="windowExitAnimation" format="integer"/>
</declare-styleable>
<declare-styleable name="CircleImageView">
<attr name="civ_border_width" format="dimension" />
<attr name="civ_border_color" format="color" />
<attr name="civ_border_overlay" format="boolean" />
<attr name="civ_fill_color" format="color" />
<attr name="civ_border_width" format="dimension"/>
<attr name="civ_border_color" format="color"/>
<attr name="civ_border_overlay" format="boolean"/>
<attr name="civ_fill_color" format="color"/>
</declare-styleable>
<attr name="progressColor" format="color"/>
<attr name="progressBackColor" format="color"/>
<attr name="progress" format="integer"/>
<attr name="minProgress" format="integer"/>
<attr name="maxProgress" format="integer"/>
<declare-styleable name="ProgressButton">
<attr name="progressColor"/>
<attr name="progressBackColor"/>
<attr name="buttonColor" format="color"/>
<attr name="cornerRadius" format="dimension"/>
<attr name="progress"/>
<attr name="minProgress"/>
<attr name="maxProgress"/>
<attr name="progressMargin" format="dimension"/>
</declare-styleable>
</resources>

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#3F51B5</color>
<color name="colorPrimaryDark">#303F9F</color>
<color name="colorPrimary">#FF2196F3</color>
<color name="colorPrimaryDark">#3F51B5</color>
<color name="colorAccent">#90cbf6</color>
@ -49,6 +49,7 @@
<color name="little_grey">#f1f1f1</color>
<color name="origin">#ff9602</color>
<color name="md_orange_800">#EF6C00</color>
<!-- 透明 -->
<color name="nothing">#00000000</color>
@ -80,6 +81,7 @@
<color name="sys_blue_little"> #338fcf</color>
<color name="sys_blue_little_deep">#0062ff</color>
<color name="sys_blue_very_little">#80c0ec</color>
<color name="sys_blue_littler">#FFABD3EC</color>
<color name="sys_blue_very_little_translucent">#883571a4</color>
<color name="sys_origin">#ef9903</color>
<color name="sys_word_email_receive">#338ccf</color>
@ -160,4 +162,12 @@
<color name="divider_common">#727272</color>
<color name="translucent_text">#96ffffff</color>
<!-- Toast颜色 -->
<color name="toast_default">#FFABD3EC</color>
<color name="toast_green">#FFAFE3B2</color>
<color name="toast_blue">#FF87CEFA</color>
<color name="toast_yellow">#FFFFE284</color>
<color name="toast_red">#FFE75B76</color>
</resources>

@ -38,10 +38,23 @@
<string name="disclaimer">免责声明</string>
<string name="statement">声明:小说数据全部从网络获取,软件不提供或保存任何小说,详情请参考免责声明:</string>
<string name="all_cathe_tip">"说明:1、书籍缓存的章节是从历史阅读章节到最新章节!\n\n2、书源为品书网的书籍因网站原因无法一键缓存!\n\n确定要一键缓存?"</string>
<string name="all_cathe_tip">说明:1、书籍缓存的章节是从历史阅读章节到最新章节!\n\n2、书源为品书网的书籍因网站原因无法一键缓存!\n\n确定要一键缓存?"</string>
<string name="match_chapter_tip">功能背景:由于不同书源的章节数量不一定相同,换源后历史阅读章节可能出错!
\n\n功能介绍:软件采用智能匹配历史章节的算法,可在书籍换源后为您自动匹配历史阅读章节!
\n\n功能设置:您可在设置界面开启/关闭此功能(默认关闭),并可更改智能匹配度。
\n\n智能匹配度:智能匹配度是将历史阅读章节标题与换源后章节目录各个章节标题进行相似度比较的阈值,默认为0.7,智能匹配度越高,匹配越精确,但匹配成功率越低。
\n\n注:匹配算法不能保证100%匹配正确
</string>
<string name="change_source_tip1">换源成功,由于不同书源的章节数量不一定相同,换源后历史阅读章节可能出错!
\n\n注:您已开启历史章节智能匹配功能,将为您自动匹配历史阅读章节(匹配算法不能保证100%匹配正确),是否匹配成功请查看提示!
</string>
<string name="change_source_tip2">换源成功,由于不同书源的章节数量不一定相同,换源后历史阅读章节可能出错!
\n\n注:软件提供了智能匹配历史章节功能,您可在设置界面开启!
</string>
<!--menu-->
<string name="menu_book_Top">移至顶部</string>
<string name="menu_book_detail">书籍详情</string>
<string name="menu_book_download">缓存书籍</string>
<string name="menu_book_cache">导出缓存</string>
<string name="menu_book_delete">删除书籍</string>
@ -51,8 +64,9 @@
<string name="menu_bookcase_add">添加本地</string>
<string name="menu_bookcase_syn">同步书架</string>
<string name="menu_bookcase_download_all">一键缓存</string>
<string name="menu_settings">应用设置</string>
<string name="menu_bookcase_backup">备份/恢复</string>
<string name="menu_bookcase_about">关于软件</string>
<string name="menu_bookcase_about">关于应用</string>
<string name="menu_backup_backup">备份</string>
<string name="menu_backup_restore">恢复</string>
@ -77,7 +91,9 @@
<string name="et_account_tip">请输入用户名</string>
<string name="text_register">注册</string>
<string name="text_agreement_tip">我已阅读并同意《</string>
<string name="link_agreement"><a href="https://shimo.im/docs/RgkDpd3D3Gp6t3rD">用户服务协议</a></string>
<string name="link_agreement">
<a href="https://shimo.im/docs/RgkDpd3D3Gp6t3rD">用户服务协议</a>
</string>
<string name="add_book_mark">添加书签</string>
<string name="share_app">分享软件</string>
<string name="update_log">更新日志</string>
@ -93,4 +109,48 @@
<string name="file_add_shelf">加入书架</string>
<string name="file_add_shelves">加入书架(%1$d)</string>
<string name="file_add_succeed">成功添加%1$d本书</string>
<string name="menu_change_source">更换书源</string>
<string name="menu_reload">重新加载</string>
<string name="menu_open_link">打开链接</string>
<string name="menu_is_update">启用更新</string>
<string name="volume_turn_page">音量键翻页</string>
<string name="reset_screen_time">息屏时间</string>
<string name="read_setting">阅读设置</string>
<string name="bookcase_setting">书架设置</string>
<string name="change_source_setting">换源设置</string>
<string name="auto_refresh">自动刷新</string>
<string name="auto_refresh_tip">打开软件时自动更新书籍</string>
<string name="match_chapters">历史章节智能匹配</string>
<string name="match_chapters_sui">智能匹配度</string>
<string name="cathe_setting">缓存设置</string>
<string name="cathe_gap">章节缓存间隔</string>
<string name="clear_cathe">清除缓存</string>
<string name="download_all_tip">选择一键缓存的书籍</string>
<string name="download_all">一键缓存</string>
<string name="close_refresh">禁用更新</string>
<string name="close_refresh_tip">选择禁用更新的书籍</string>
<string-array name="reset_screen_time">
<item>常亮</item>
<item>1分钟</item>
<item>3分钟</item>
<item>5分钟</item>
</string-array>
<string-array name="match_chapter_suitability">
<item>0.5</item>
<item>0.6</item>
<item>0.7</item>
<item>0.8</item>
<item>0.9</item>
</string-array>
<string-array name="cathe_chapter_gap">
<item>50ms</item>
<item>100ms</item>
<item>150ms</item>
<item>200ms</item>
<item>250ms</item>
</string-array>
</resources>

@ -88,8 +88,8 @@
<!--用于修改popmenu的分割线-->
<style name="dropDownStyle" parent="android:style/Widget.Holo.ListView.DropDown">
<item name="android:listSelector">@drawable/selector_common_bg</item>
<item name="android:divider">@color/divider_common</item>
<item name="android:dividerHeight">0.5dp</item>
<!-- <item name="android:divider">@color/divider_common</item>-->
<!-- <item name="android:dividerHeight">0.5dp</item>-->
</style>
<!--BookDetail-->
<style name="BottomNavigationViewTheme" />

@ -1,2 +1,2 @@
#Mon Aug 17 18:44:13 CST 2020
VERSION_CODE=142
#Sat Aug 29 22:36:36 CST 2020
VERSION_CODE=143

Loading…
Cancel
Save