| @ -1,6 +1,7 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <project version="4"> | ||||
|   <component name="SqlDialectMappings"> | ||||
|     <file url="file://$PROJECT_DIR$/app/src/main/java/xyz/fycz/myreader/model/backup/UserService.java" dialect="GenericSQL" /> | ||||
|     <file url="PROJECT" dialect="MySQL" /> | ||||
|   </component> | ||||
| </project> | ||||
| After Width: | Height: | Size: 88 KiB | 
| After Width: | Height: | Size: 30 KiB | 
| After Width: | Height: | Size: 7.9 KiB | 
| After Width: | Height: | Size: 144 KiB | 
| After Width: | Height: | Size: 20 KiB | 
| After Width: | Height: | Size: 40 KiB | 
| After Width: | Height: | Size: 48 KiB | 
| After Width: | Height: | Size: 12 KiB | 
| After Width: | Height: | Size: 4.0 KiB | 
| After Width: | Height: | Size: 112 KiB | 
| After Width: | Height: | Size: 272 B | 
| After Width: | Height: | Size: 269 B | 
| After Width: | Height: | Size: 82 KiB | 
| After Width: | Height: | Size: 10 KiB | 
| After Width: | Height: | Size: 3.8 KiB | 
| After Width: | Height: | Size: 4.0 KiB | 
| After Width: | Height: | Size: 148 B | 
| After Width: | Height: | Size: 168 B | 
| After Width: | Height: | Size: 2.8 KiB | 
| After Width: | Height: | Size: 399 B | 
| After Width: | Height: | Size: 453 B | 
| After Width: | Height: | Size: 647 B | 
| After Width: | Height: | Size: 295 B | 
| After Width: | Height: | Size: 741 B | 
| After Width: | Height: | Size: 707 B | 
| After Width: | Height: | Size: 581 B | 
| After Width: | Height: | Size: 718 B | 
| After Width: | Height: | Size: 533 B | 
| After Width: | Height: | Size: 633 B | 
| After Width: | Height: | Size: 682 B | 
| After Width: | Height: | Size: 702 B | 
| After Width: | Height: | Size: 693 B | 
| After Width: | Height: | Size: 602 B | 
| After Width: | Height: | Size: 501 B | 
| After Width: | Height: | Size: 634 B | 
| After Width: | Height: | Size: 588 B | 
| After Width: | Height: | Size: 514 B | 
| After Width: | Height: | Size: 561 B | 
| After Width: | Height: | Size: 612 B | 
| After Width: | Height: | Size: 505 B | 
| After Width: | Height: | Size: 475 B | 
| After Width: | Height: | Size: 579 B | 
| After Width: | Height: | Size: 678 KiB | 
| @ -0,0 +1,813 @@ | ||||
| //Copyright (c) 2017. 章钦豪. All rights reserved.
 | ||||
| package xyz.fycz.myreader.entity; | ||||
| 
 | ||||
| import android.content.ContentResolver; | ||||
| import android.content.Context; | ||||
| import android.content.SharedPreferences; | ||||
| import android.content.res.Resources; | ||||
| import android.graphics.Bitmap; | ||||
| import android.graphics.Color; | ||||
| import android.graphics.drawable.BitmapDrawable; | ||||
| import android.graphics.drawable.ColorDrawable; | ||||
| import android.graphics.drawable.Drawable; | ||||
| import android.provider.Settings; | ||||
| import android.util.DisplayMetrics; | ||||
| 
 | ||||
| 
 | ||||
| import java.util.ArrayList; | ||||
| import java.util.HashMap; | ||||
| import java.util.List; | ||||
| import java.util.Map; | ||||
| 
 | ||||
| import xyz.fycz.myreader.application.MyApplication; | ||||
| import xyz.fycz.myreader.util.SharedPreUtils; | ||||
| import xyz.fycz.myreader.util.utils.BitmapUtil; | ||||
| import xyz.fycz.myreader.util.utils.MeUtils; | ||||
| 
 | ||||
| import static xyz.fycz.myreader.widget.page2.PageLoader.DEFAULT_MARGIN_WIDTH; | ||||
| 
 | ||||
| 
 | ||||
| public class ReadBookControl { | ||||
|     private static final int DEFAULT_BG = 1; | ||||
|     private int textDrawableIndex = DEFAULT_BG; | ||||
|     private List<Map<String, Integer>> textDrawable; | ||||
|     private Bitmap bgBitmap; | ||||
|     private int screenDirection; | ||||
|     private int speechRate; | ||||
|     private boolean speechRateFollowSys; | ||||
|     private int textSize; | ||||
|     private int textColor; | ||||
|     private boolean bgIsColor; | ||||
|     private int bgColor; | ||||
|     private float lineMultiplier; | ||||
|     private float paragraphSize; | ||||
|     private int pageMode; | ||||
|     private Boolean hideStatusBar; | ||||
|     private Boolean hideNavigationBar; | ||||
|     private String fontPath; | ||||
|     private int textConvert; | ||||
|     private int navBarColor; | ||||
|     private Boolean textBold; | ||||
|     private Boolean canClickTurn; | ||||
|     private Boolean canKeyTurn; | ||||
|     private Boolean readAloudCanKeyTurn; | ||||
|     private int CPM; | ||||
|     private Boolean clickAllNext; | ||||
|     private Boolean showTitle; | ||||
|     private Boolean showTimeBattery; | ||||
|     private Boolean showLine; | ||||
|     private Boolean darkStatusIcon; | ||||
|     private int indent; | ||||
|     private int screenTimeOut; | ||||
|     private int paddingLeft; | ||||
|     private int paddingTop; | ||||
|     private int paddingRight; | ||||
|     private int paddingBottom; | ||||
|     private int tipPaddingLeft; | ||||
|     private int tipPaddingTop; | ||||
|     private int tipPaddingRight; | ||||
|     private int tipPaddingBottom; | ||||
|     private float textLetterSpacing; | ||||
|     private boolean canSelectText; | ||||
|     public int minCPM = 200; | ||||
|     public int maxCPM = 2000; | ||||
|     private int defaultCPM = 500; | ||||
| 
 | ||||
|     private SharedPreferences preferences; | ||||
| 
 | ||||
|     private static ReadBookControl readBookControl; | ||||
| 
 | ||||
|     public static ReadBookControl getInstance() { | ||||
|         if (readBookControl == null) { | ||||
|             synchronized (ReadBookControl.class) { | ||||
|                 if (readBookControl == null) { | ||||
|                     readBookControl = new ReadBookControl(); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         return readBookControl; | ||||
|     } | ||||
| 
 | ||||
|     private ReadBookControl() { | ||||
|         preferences = SharedPreUtils.getInstance().getSharedReadable(); | ||||
|         initTextDrawable(); | ||||
|         updateReaderSettings(); | ||||
|     } | ||||
| 
 | ||||
|     public void updateReaderSettings() { | ||||
|         this.hideStatusBar = preferences.getBoolean("hide_status_bar", false); | ||||
|         this.hideNavigationBar = preferences.getBoolean("hide_navigation_bar", false); | ||||
|         this.indent = preferences.getInt("indent", 2); | ||||
|         this.textSize = preferences.getInt("textSize", 20); | ||||
|         this.canClickTurn = preferences.getBoolean("canClickTurn", true); | ||||
|         this.canKeyTurn = preferences.getBoolean("canKeyTurn", true); | ||||
|         this.readAloudCanKeyTurn = preferences.getBoolean("readAloudCanKeyTurn", false); | ||||
|         this.lineMultiplier = preferences.getFloat("lineMultiplier", 1); | ||||
|         this.paragraphSize = preferences.getFloat("paragraphSize", 1); | ||||
|         this.CPM = preferences.getInt("CPM", defaultCPM) > maxCPM | ||||
|                 ? minCPM : preferences.getInt("CPM", defaultCPM); | ||||
|         this.clickAllNext = preferences.getBoolean("clickAllNext", false); | ||||
|         this.fontPath = preferences.getString("fontPath", null); | ||||
|         this.textConvert = preferences.getInt("textConvertInt", 0); | ||||
|         this.textBold = preferences.getBoolean("textBold", false); | ||||
|         this.speechRate = preferences.getInt("speechRate", 10); | ||||
|         this.speechRateFollowSys = preferences.getBoolean("speechRateFollowSys", true); | ||||
|         this.showTitle = preferences.getBoolean("showTitle", true); | ||||
|         this.showTimeBattery = preferences.getBoolean("showTimeBattery", true); | ||||
|         this.showLine = preferences.getBoolean("showLine", true); | ||||
|         this.screenTimeOut = preferences.getInt("screenTimeOut", 0); | ||||
|         this.paddingLeft = preferences.getInt("paddingLeft", DEFAULT_MARGIN_WIDTH); | ||||
|         this.paddingTop = preferences.getInt("paddingTop", 0); | ||||
|         this.paddingRight = preferences.getInt("paddingRight", DEFAULT_MARGIN_WIDTH); | ||||
|         this.paddingBottom = preferences.getInt("paddingBottom", 0); | ||||
|         this.tipPaddingLeft = preferences.getInt("tipPaddingLeft", DEFAULT_MARGIN_WIDTH); | ||||
|         this.tipPaddingTop = preferences.getInt("tipPaddingTop", 0); | ||||
|         this.tipPaddingRight = preferences.getInt("tipPaddingRight", DEFAULT_MARGIN_WIDTH); | ||||
|         this.tipPaddingBottom = preferences.getInt("tipPaddingBottom", 0); | ||||
|         this.pageMode = preferences.getInt("pageMode", 0); | ||||
|         this.screenDirection = preferences.getInt("screenDirection", 0); | ||||
|         this.navBarColor = preferences.getInt("navBarColorInt", 0); | ||||
|         this.textLetterSpacing = preferences.getFloat("textLetterSpacing", 0); | ||||
|         this.canSelectText = preferences.getBoolean("canSelectText", false); | ||||
|         initTextDrawableIndex(); | ||||
|     } | ||||
| 
 | ||||
|     //阅读背景
 | ||||
|     private void initTextDrawable() { | ||||
|         if (null == textDrawable) { | ||||
|             textDrawable = new ArrayList<>(); | ||||
|             Map<String, Integer> temp1 = new HashMap<>(); | ||||
|             temp1.put("textColor", Color.parseColor("#3E3D3B")); | ||||
|             temp1.put("bgIsColor", 1); | ||||
|             temp1.put("textBackground", Color.parseColor("#F3F3F3")); | ||||
|             temp1.put("darkStatusIcon", 1); | ||||
|             textDrawable.add(temp1); | ||||
| 
 | ||||
|             Map<String, Integer> temp2 = new HashMap<>(); | ||||
|             temp2.put("textColor", Color.parseColor("#5E432E")); | ||||
|             temp2.put("bgIsColor", 1); | ||||
|             temp2.put("textBackground", Color.parseColor("#C6BAA1")); | ||||
|             temp2.put("darkStatusIcon", 1); | ||||
|             textDrawable.add(temp2); | ||||
| 
 | ||||
|             Map<String, Integer> temp3 = new HashMap<>(); | ||||
|             temp3.put("textColor", Color.parseColor("#22482C")); | ||||
|             temp3.put("bgIsColor", 1); | ||||
|             temp3.put("textBackground", Color.parseColor("#E1F1DA")); | ||||
|             temp3.put("darkStatusIcon", 1); | ||||
|             textDrawable.add(temp3); | ||||
| 
 | ||||
|             Map<String, Integer> temp4 = new HashMap<>(); | ||||
|             temp4.put("textColor", Color.parseColor("#FFFFFF")); | ||||
|             temp4.put("bgIsColor", 1); | ||||
|             temp4.put("textBackground", Color.parseColor("#015A86")); | ||||
|             temp4.put("darkStatusIcon", 0); | ||||
|             textDrawable.add(temp4); | ||||
| 
 | ||||
|             Map<String, Integer> temp5 = new HashMap<>(); | ||||
|             temp5.put("textColor", Color.parseColor("#808080")); | ||||
|             temp5.put("bgIsColor", 1); | ||||
|             temp5.put("textBackground", Color.parseColor("#000000")); | ||||
|             temp5.put("darkStatusIcon", 0); | ||||
|             textDrawable.add(temp5); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public void initTextDrawableIndex() { | ||||
|         if (getIsNightTheme()) { | ||||
|             textDrawableIndex = preferences.getInt("textDrawableIndexNight", 4); | ||||
|         } else { | ||||
|             textDrawableIndex = preferences.getInt("textDrawableIndex", DEFAULT_BG); | ||||
|         } | ||||
|         if (textDrawableIndex == -1) { | ||||
|             textDrawableIndex = DEFAULT_BG; | ||||
|         } | ||||
|         initPageStyle(); | ||||
|         setTextDrawable(); | ||||
|     } | ||||
| 
 | ||||
|     @SuppressWarnings("ConstantConditions") | ||||
|     private void initPageStyle() { | ||||
|         int bgCustom = getBgCustom(textDrawableIndex); | ||||
|         if ((bgCustom == 2 || bgCustom == 3) && getBgPath(textDrawableIndex) != null) { | ||||
|             bgIsColor = false; | ||||
|             String bgPath = getBgPath(textDrawableIndex); | ||||
|             Resources resources = MyApplication.getApplication().getResources(); | ||||
|             DisplayMetrics dm = resources.getDisplayMetrics(); | ||||
|             int width = dm.widthPixels; | ||||
|             int height = dm.heightPixels; | ||||
|             if (bgCustom == 2) { | ||||
|                 bgBitmap = BitmapUtil.getFitSampleBitmap(bgPath, width, height); | ||||
|             } else { | ||||
|                 bgBitmap = MeUtils.getFitAssetsSampleBitmap(MyApplication.getApplication().getAssets(), bgPath, width, height); | ||||
|             } | ||||
|             if (bgBitmap != null) { | ||||
|                 return; | ||||
|             } | ||||
|         } else if (getBgCustom(textDrawableIndex) == 1) { | ||||
|             bgIsColor = true; | ||||
|             bgColor = getBgColor(textDrawableIndex); | ||||
|             return; | ||||
|         } | ||||
|         bgIsColor = true; | ||||
|         bgColor = textDrawable.get(textDrawableIndex).get("textBackground"); | ||||
|     } | ||||
| 
 | ||||
|     private void setTextDrawable() { | ||||
|         darkStatusIcon = getDarkStatusIcon(textDrawableIndex); | ||||
|         textColor = getTextColor(textDrawableIndex); | ||||
|     } | ||||
| 
 | ||||
|     public int getTextColor(int textDrawableIndex) { | ||||
|         if (preferences.getInt("textColor" + textDrawableIndex, 0) != 0) { | ||||
|             return preferences.getInt("textColor" + textDrawableIndex, 0); | ||||
|         } else { | ||||
|             return getDefaultTextColor(textDrawableIndex); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public void setTextColor(int textDrawableIndex, int textColor) { | ||||
|         preferences.edit() | ||||
|                 .putInt("textColor" + textDrawableIndex, textColor) | ||||
|                 .apply(); | ||||
|     } | ||||
| 
 | ||||
|     @SuppressWarnings("ConstantConditions") | ||||
|     public Drawable getBgDrawable(int textDrawableIndex, Context context, int width, int height) { | ||||
|         int color; | ||||
|         try { | ||||
|             Bitmap bitmap = null; | ||||
|             switch (getBgCustom(textDrawableIndex)) { | ||||
|                 case 3: | ||||
|                     bitmap = MeUtils.getFitAssetsSampleBitmap(context.getAssets(), getBgPath(textDrawableIndex), width, height); | ||||
|                     if (bitmap != null) { | ||||
|                         return new BitmapDrawable(context.getResources(), bitmap); | ||||
|                     } | ||||
|                 case 2: | ||||
|                     bitmap = BitmapUtil.getFitSampleBitmap(getBgPath(textDrawableIndex), width, height); | ||||
|                     if (bitmap != null) { | ||||
|                         return new BitmapDrawable(context.getResources(), bitmap); | ||||
|                     } | ||||
|                     break; | ||||
|                 case 1: | ||||
|                     color = getBgColor(textDrawableIndex); | ||||
|                     return new ColorDrawable(color); | ||||
|             } | ||||
|             if (textDrawable.get(textDrawableIndex).get("bgIsColor") != 0) { | ||||
|                 color = textDrawable.get(textDrawableIndex).get("textBackground"); | ||||
|                 return new ColorDrawable(color); | ||||
|             } else { | ||||
|                 return getDefaultBgDrawable(textDrawableIndex, context); | ||||
|             } | ||||
|         } catch (Exception e) { | ||||
|             if (textDrawable.get(textDrawableIndex).get("bgIsColor") != 0) { | ||||
|                 color = textDrawable.get(textDrawableIndex).get("textBackground"); | ||||
|                 return new ColorDrawable(color); | ||||
|             } else { | ||||
|                 return getDefaultBgDrawable(textDrawableIndex, context); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     @SuppressWarnings("ConstantConditions") | ||||
|     public Drawable getDefaultBgDrawable(int textDrawableIndex, Context context) { | ||||
|         if (textDrawable.get(textDrawableIndex).get("bgIsColor") != 0) { | ||||
|             return new ColorDrawable(textDrawable.get(textDrawableIndex).get("textBackground")); | ||||
|         } else { | ||||
|             return context.getResources().getDrawable(getDefaultBg(textDrawableIndex)); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public int getBgCustom(int textDrawableIndex) { | ||||
|         return preferences.getInt("bgCustom" + textDrawableIndex, 0); | ||||
|     } | ||||
| 
 | ||||
|     public void setBgCustom(int textDrawableIndex, int bgCustom) { | ||||
|         preferences.edit() | ||||
|                 .putInt("bgCustom" + textDrawableIndex, bgCustom) | ||||
|                 .apply(); | ||||
|     } | ||||
| 
 | ||||
|     public String getBgPath(int textDrawableIndex) { | ||||
|         return preferences.getString("bgPath" + textDrawableIndex, null); | ||||
|     } | ||||
| 
 | ||||
|     public void setBgPath(int textDrawableIndex, String bgUri) { | ||||
|         preferences.edit() | ||||
|                 .putString("bgPath" + textDrawableIndex, bgUri) | ||||
|                 .apply(); | ||||
|     } | ||||
| 
 | ||||
|     @SuppressWarnings("ConstantConditions") | ||||
|     public int getDefaultTextColor(int textDrawableIndex) { | ||||
|         return textDrawable.get(textDrawableIndex).get("textColor"); | ||||
|     } | ||||
| 
 | ||||
|     @SuppressWarnings("ConstantConditions") | ||||
|     private int getDefaultBg(int textDrawableIndex) { | ||||
|         return textDrawable.get(textDrawableIndex).get("textBackground"); | ||||
|     } | ||||
| 
 | ||||
|     public int getBgColor(int index) { | ||||
|         return preferences.getInt("bgColor" + index, Color.parseColor("#1e1e1e")); | ||||
|     } | ||||
| 
 | ||||
|     public void setBgColor(int index, int bgColor) { | ||||
|         preferences.edit() | ||||
|                 .putInt("bgColor" + index, bgColor) | ||||
|                 .apply(); | ||||
|     } | ||||
| 
 | ||||
|     private boolean getIsNightTheme() { | ||||
|         return MyApplication.getApplication().isNightTheme(); | ||||
|     } | ||||
| 
 | ||||
|     public boolean getImmersionStatusBar() { | ||||
|         return preferences.getBoolean("immersionStatusBar", false); | ||||
|     } | ||||
| 
 | ||||
|     public void setImmersionStatusBar(boolean immersionStatusBar) { | ||||
|         preferences.edit() | ||||
|                 .putBoolean("immersionStatusBar", immersionStatusBar) | ||||
|                 .apply(); | ||||
|     } | ||||
| 
 | ||||
|     public int getTextSize() { | ||||
|         return textSize; | ||||
|     } | ||||
| 
 | ||||
|     public void setTextSize(int textSize) { | ||||
|         this.textSize = textSize; | ||||
|         preferences.edit() | ||||
|                 .putInt("textSize", textSize) | ||||
|                 .apply(); | ||||
|     } | ||||
| 
 | ||||
|     public int getTextColor() { | ||||
|         return textColor; | ||||
|     } | ||||
| 
 | ||||
|     public boolean bgIsColor() { | ||||
|         return bgIsColor; | ||||
|     } | ||||
| 
 | ||||
|     public Drawable getTextBackground(Context context) { | ||||
|         if (bgIsColor) { | ||||
|             return new ColorDrawable(bgColor); | ||||
|         } | ||||
|         return new BitmapDrawable(context.getResources(), bgBitmap); | ||||
|     } | ||||
| 
 | ||||
|     public int getBgColor() { | ||||
|         return bgColor; | ||||
|     } | ||||
| 
 | ||||
|     public boolean bgBitmapIsNull() { | ||||
|         return bgBitmap == null || bgBitmap.isRecycled(); | ||||
|     } | ||||
| 
 | ||||
|     public Bitmap getBgBitmap() { | ||||
|         return bgBitmap.copy(Bitmap.Config.ARGB_8888, true); | ||||
|     } | ||||
| 
 | ||||
|     public int getTextDrawableIndex() { | ||||
|         return textDrawableIndex; | ||||
|     } | ||||
| 
 | ||||
|     public void setTextDrawableIndex(int textDrawableIndex) { | ||||
|         this.textDrawableIndex = textDrawableIndex; | ||||
|         if (getIsNightTheme()) { | ||||
|             preferences.edit() | ||||
|                     .putInt("textDrawableIndexNight", textDrawableIndex) | ||||
|                     .apply(); | ||||
|         } else { | ||||
|             preferences.edit() | ||||
|                     .putInt("textDrawableIndex", textDrawableIndex) | ||||
|                     .apply(); | ||||
|         } | ||||
|         setTextDrawable(); | ||||
|     } | ||||
| 
 | ||||
|     public void setTextConvert(int textConvert) { | ||||
|         this.textConvert = textConvert; | ||||
|         preferences.edit() | ||||
|                 .putInt("textConvertInt", textConvert) | ||||
|                 .apply(); | ||||
|     } | ||||
| 
 | ||||
|     public void setNavBarColor(int navBarColor) { | ||||
|         this.navBarColor = navBarColor; | ||||
|         preferences.edit() | ||||
|                 .putInt("navBarColorInt", navBarColor) | ||||
|                 .apply(); | ||||
|     } | ||||
| 
 | ||||
|     public int getNavBarColor() { | ||||
|         return navBarColor; | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     public void setTextBold(boolean textBold) { | ||||
|         this.textBold = textBold; | ||||
|         preferences.edit() | ||||
|                 .putBoolean("textBold", textBold) | ||||
|                 .apply(); | ||||
|     } | ||||
| 
 | ||||
|     public void setReadBookFont(String fontPath) { | ||||
|         this.fontPath = fontPath; | ||||
|         preferences.edit() | ||||
|                 .putString("fontPath", fontPath) | ||||
|                 .apply(); | ||||
|     } | ||||
| 
 | ||||
|     public String getFontPath() { | ||||
|         return fontPath; | ||||
|     } | ||||
| 
 | ||||
|     public int getTextConvert() { | ||||
|         return textConvert == -1 ? 2 : textConvert; | ||||
|     } | ||||
| 
 | ||||
|     public Boolean getTextBold() { | ||||
|         return textBold; | ||||
|     } | ||||
| 
 | ||||
|     public Boolean getCanKeyTurn(Boolean isPlay) { | ||||
|         if (!canKeyTurn) { | ||||
|             return false; | ||||
|         } else if (readAloudCanKeyTurn) { | ||||
|             return true; | ||||
|         } else { | ||||
|             return !isPlay; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public Boolean getCanKeyTurn() { | ||||
|         return canKeyTurn; | ||||
|     } | ||||
| 
 | ||||
|     public void setCanKeyTurn(Boolean canKeyTurn) { | ||||
|         this.canKeyTurn = canKeyTurn; | ||||
|         preferences.edit() | ||||
|                 .putBoolean("canKeyTurn", canKeyTurn) | ||||
|                 .apply(); | ||||
|     } | ||||
| 
 | ||||
|     public Boolean getAloudCanKeyTurn() { | ||||
|         return readAloudCanKeyTurn; | ||||
|     } | ||||
| 
 | ||||
|     public void setAloudCanKeyTurn(Boolean canAloudKeyTurn) { | ||||
|         this.readAloudCanKeyTurn = canAloudKeyTurn; | ||||
|         preferences.edit() | ||||
|                 .putBoolean("readAloudCanKeyTurn", canAloudKeyTurn) | ||||
|                 .apply(); | ||||
|     } | ||||
| 
 | ||||
|     public Boolean getCanClickTurn() { | ||||
|         return canClickTurn; | ||||
|     } | ||||
| 
 | ||||
|     public void setCanClickTurn(Boolean canClickTurn) { | ||||
|         this.canClickTurn = canClickTurn; | ||||
|         preferences.edit() | ||||
|                 .putBoolean("canClickTurn", canClickTurn) | ||||
|                 .apply(); | ||||
|     } | ||||
| 
 | ||||
|     public float getTextLetterSpacing() { | ||||
|         return textLetterSpacing; | ||||
|     } | ||||
| 
 | ||||
|     public void setTextLetterSpacing(float textLetterSpacing) { | ||||
|         this.textLetterSpacing = textLetterSpacing; | ||||
|         preferences.edit() | ||||
|                 .putFloat("textLetterSpacing", textLetterSpacing) | ||||
|                 .apply(); | ||||
|     } | ||||
| 
 | ||||
|     public float getLineMultiplier() { | ||||
|         return lineMultiplier; | ||||
|     } | ||||
| 
 | ||||
|     public void setLineMultiplier(float lineMultiplier) { | ||||
|         this.lineMultiplier = lineMultiplier; | ||||
|         preferences.edit() | ||||
|                 .putFloat("lineMultiplier", lineMultiplier) | ||||
|                 .apply(); | ||||
|     } | ||||
| 
 | ||||
|     public float getParagraphSize() { | ||||
|         return paragraphSize; | ||||
|     } | ||||
| 
 | ||||
|     public void setParagraphSize(float paragraphSize) { | ||||
|         this.paragraphSize = paragraphSize; | ||||
|         preferences.edit() | ||||
|                 .putFloat("paragraphSize", paragraphSize) | ||||
|                 .apply(); | ||||
|     } | ||||
| 
 | ||||
|     public int getCPM() { | ||||
|         return CPM; | ||||
|     } | ||||
| 
 | ||||
|     public void setCPM(int cpm) { | ||||
|         if (cpm < minCPM || cpm > maxCPM) cpm = defaultCPM; | ||||
|         this.CPM = cpm; | ||||
|         preferences.edit() | ||||
|                 .putInt("CPM", cpm) | ||||
|                 .apply(); | ||||
|     } | ||||
| 
 | ||||
|     public Boolean getClickAllNext() { | ||||
|         return clickAllNext; | ||||
|     } | ||||
| 
 | ||||
|     public void setClickAllNext(Boolean clickAllNext) { | ||||
|         this.clickAllNext = clickAllNext; | ||||
|         preferences.edit() | ||||
|                 .putBoolean("clickAllNext", clickAllNext) | ||||
|                 .apply(); | ||||
|     } | ||||
| 
 | ||||
|     public int getSpeechRate() { | ||||
|         return speechRate; | ||||
|     } | ||||
| 
 | ||||
|     public void setSpeechRate(int speechRate) { | ||||
|         this.speechRate = speechRate; | ||||
|         preferences.edit() | ||||
|                 .putInt("speechRate", speechRate) | ||||
|                 .apply(); | ||||
|     } | ||||
| 
 | ||||
|     public boolean isSpeechRateFollowSys() { | ||||
|         return speechRateFollowSys; | ||||
|     } | ||||
| 
 | ||||
|     public void setSpeechRateFollowSys(boolean speechRateFollowSys) { | ||||
|         this.speechRateFollowSys = speechRateFollowSys; | ||||
|         preferences.edit() | ||||
|                 .putBoolean("speechRateFollowSys", speechRateFollowSys) | ||||
|                 .apply(); | ||||
|     } | ||||
| 
 | ||||
|     public Boolean getShowTitle() { | ||||
|         return showTitle; | ||||
|     } | ||||
| 
 | ||||
|     public void setShowTitle(Boolean showTitle) { | ||||
|         this.showTitle = showTitle; | ||||
|         preferences.edit() | ||||
|                 .putBoolean("showTitle", showTitle) | ||||
|                 .apply(); | ||||
|     } | ||||
| 
 | ||||
|     public Boolean getShowTimeBattery() { | ||||
|         return showTimeBattery; | ||||
|     } | ||||
| 
 | ||||
|     public void setShowTimeBattery(Boolean showTimeBattery) { | ||||
|         this.showTimeBattery = showTimeBattery; | ||||
|         preferences.edit() | ||||
|                 .putBoolean("showTimeBattery", showTimeBattery) | ||||
|                 .apply(); | ||||
|     } | ||||
| 
 | ||||
|     public Boolean getHideStatusBar() { | ||||
|         return hideStatusBar; | ||||
|     } | ||||
| 
 | ||||
|     public void setHideStatusBar(Boolean hideStatusBar) { | ||||
|         this.hideStatusBar = hideStatusBar; | ||||
|         preferences.edit() | ||||
|                 .putBoolean("hide_status_bar", hideStatusBar) | ||||
|                 .apply(); | ||||
|     } | ||||
| 
 | ||||
|     public Boolean getToLh() { | ||||
|         return preferences.getBoolean("toLh", false); | ||||
|     } | ||||
| 
 | ||||
|     public void setToLh(Boolean toLh) { | ||||
|         preferences.edit() | ||||
|                 .putBoolean("toLh", toLh) | ||||
|                 .apply(); | ||||
|     } | ||||
| 
 | ||||
|     public Boolean getHideNavigationBar() { | ||||
|         return hideNavigationBar; | ||||
|     } | ||||
| 
 | ||||
|     public void setHideNavigationBar(Boolean hideNavigationBar) { | ||||
|         this.hideNavigationBar = hideNavigationBar; | ||||
|         preferences.edit() | ||||
|                 .putBoolean("hide_navigation_bar", hideNavigationBar) | ||||
|                 .apply(); | ||||
|     } | ||||
| 
 | ||||
|     public Boolean getShowLine() { | ||||
|         return showLine; | ||||
|     } | ||||
| 
 | ||||
|     public void setShowLine(Boolean showLine) { | ||||
|         this.showLine = showLine; | ||||
|         preferences.edit() | ||||
|                 .putBoolean("showLine", showLine) | ||||
|                 .apply(); | ||||
|     } | ||||
| 
 | ||||
|     public boolean getDarkStatusIcon() { | ||||
|         return darkStatusIcon; | ||||
|     } | ||||
| 
 | ||||
|     @SuppressWarnings("ConstantConditions") | ||||
|     public boolean getDarkStatusIcon(int textDrawableIndex) { | ||||
|         return preferences.getBoolean("darkStatusIcon" + textDrawableIndex, textDrawable.get(textDrawableIndex).get("darkStatusIcon") != 0); | ||||
|     } | ||||
| 
 | ||||
|     public void setDarkStatusIcon(int textDrawableIndex, Boolean darkStatusIcon) { | ||||
|         preferences.edit() | ||||
|                 .putBoolean("darkStatusIcon" + textDrawableIndex, darkStatusIcon) | ||||
|                 .apply(); | ||||
|     } | ||||
| 
 | ||||
|     public int getScreenTimeOut() { | ||||
|         return screenTimeOut; | ||||
|     } | ||||
| 
 | ||||
|     public void setScreenTimeOut(int screenTimeOut) { | ||||
|         this.screenTimeOut = screenTimeOut; | ||||
|         preferences.edit() | ||||
|                 .putInt("screenTimeOut", screenTimeOut) | ||||
|                 .apply(); | ||||
|     } | ||||
| 
 | ||||
|     public int getPaddingLeft() { | ||||
|         return paddingLeft; | ||||
|     } | ||||
| 
 | ||||
|     public void setPaddingLeft(int paddingLeft) { | ||||
|         this.paddingLeft = paddingLeft; | ||||
|         preferences.edit() | ||||
|                 .putInt("paddingLeft", paddingLeft) | ||||
|                 .apply(); | ||||
|     } | ||||
| 
 | ||||
|     public int getPaddingTop() { | ||||
|         return paddingTop; | ||||
|     } | ||||
| 
 | ||||
|     public void setPaddingTop(int paddingTop) { | ||||
|         this.paddingTop = paddingTop; | ||||
|         preferences.edit() | ||||
|                 .putInt("paddingTop", paddingTop) | ||||
|                 .apply(); | ||||
|     } | ||||
| 
 | ||||
|     public int getPaddingRight() { | ||||
|         return paddingRight; | ||||
|     } | ||||
| 
 | ||||
|     public void setPaddingRight(int paddingRight) { | ||||
|         this.paddingRight = paddingRight; | ||||
|         preferences.edit() | ||||
|                 .putInt("paddingRight", paddingRight) | ||||
|                 .apply(); | ||||
|     } | ||||
| 
 | ||||
|     public int getPaddingBottom() { | ||||
|         return paddingBottom; | ||||
|     } | ||||
| 
 | ||||
|     public void setPaddingBottom(int paddingBottom) { | ||||
|         this.paddingBottom = paddingBottom; | ||||
|         preferences.edit() | ||||
|                 .putInt("paddingBottom", paddingBottom) | ||||
|                 .apply(); | ||||
|     } | ||||
| 
 | ||||
|     public int getTipPaddingLeft() { | ||||
|         return tipPaddingLeft; | ||||
|     } | ||||
| 
 | ||||
|     public void setTipPaddingLeft(int tipPaddingLeft) { | ||||
|         this.tipPaddingLeft = tipPaddingLeft; | ||||
|         preferences.edit() | ||||
|                 .putInt("tipPaddingLeft", tipPaddingLeft) | ||||
|                 .apply(); | ||||
|     } | ||||
| 
 | ||||
|     public boolean isCanSelectText() { | ||||
|         return canSelectText; | ||||
|     } | ||||
| 
 | ||||
|     public void setCanSelectText(boolean canSelectText) { | ||||
|         this.canSelectText = canSelectText; | ||||
|         preferences.edit() | ||||
|                 .putBoolean("canSelectText", canSelectText) | ||||
|                 .apply(); | ||||
|     } | ||||
| 
 | ||||
|     public int getTipPaddingTop() { | ||||
|         return tipPaddingTop; | ||||
|     } | ||||
| 
 | ||||
|     public void setTipPaddingTop(int tipPaddingTop) { | ||||
|         this.tipPaddingTop = tipPaddingTop; | ||||
|         preferences.edit() | ||||
|                 .putInt("tipPaddingTop", tipPaddingTop) | ||||
|                 .apply(); | ||||
|     } | ||||
| 
 | ||||
|     public int getTipPaddingRight() { | ||||
|         return tipPaddingRight; | ||||
|     } | ||||
| 
 | ||||
|     public void setTipPaddingRight(int tipPaddingRight) { | ||||
|         this.tipPaddingRight = tipPaddingRight; | ||||
|         preferences.edit() | ||||
|                 .putInt("tipPaddingRight", tipPaddingRight) | ||||
|                 .apply(); | ||||
|     } | ||||
| 
 | ||||
|     public int getTipPaddingBottom() { | ||||
|         return tipPaddingBottom; | ||||
|     } | ||||
| 
 | ||||
|     public void setTipPaddingBottom(int tipPaddingBottom) { | ||||
|         this.tipPaddingBottom = tipPaddingBottom; | ||||
|         preferences.edit() | ||||
|                 .putInt("tipPaddingBottom", tipPaddingBottom) | ||||
|                 .apply(); | ||||
|     } | ||||
| 
 | ||||
|     public int getPageMode() { | ||||
|         return pageMode; | ||||
|     } | ||||
| 
 | ||||
|     public void setPageMode(int pageMode) { | ||||
|         this.pageMode = pageMode; | ||||
|         preferences.edit() | ||||
|                 .putInt("pageMode", pageMode) | ||||
|                 .apply(); | ||||
|     } | ||||
| 
 | ||||
|     public int getScreenDirection() { | ||||
|         return screenDirection; | ||||
|     } | ||||
| 
 | ||||
|     public void setScreenDirection(int screenDirection) { | ||||
|         this.screenDirection = screenDirection; | ||||
|         preferences.edit() | ||||
|                 .putInt("screenDirection", screenDirection) | ||||
|                 .apply(); | ||||
|     } | ||||
| 
 | ||||
|     public void setIndent(int indent) { | ||||
|         this.indent = indent; | ||||
|         preferences.edit() | ||||
|                 .putInt("indent", indent) | ||||
|                 .apply(); | ||||
|     } | ||||
| 
 | ||||
|     public int getIndent() { | ||||
|         return indent; | ||||
|     } | ||||
| 
 | ||||
|     public int getLight() { | ||||
|         return preferences.getInt("light", getScreenBrightness()); | ||||
|     } | ||||
| 
 | ||||
|     public void setLight(int light) { | ||||
|         preferences.edit() | ||||
|                 .putInt("light", light) | ||||
|                 .apply(); | ||||
|     } | ||||
| 
 | ||||
|     public Boolean getLightFollowSys() { | ||||
|         return preferences.getBoolean("lightFollowSys", true); | ||||
|     } | ||||
| 
 | ||||
|     public void setLightFollowSys(boolean isFollowSys) { | ||||
|         preferences.edit() | ||||
|                 .putBoolean("lightFollowSys", isFollowSys) | ||||
|                 .apply(); | ||||
|     } | ||||
| 
 | ||||
|     private int getScreenBrightness() { | ||||
|         int value = 0; | ||||
|         ContentResolver cr = MyApplication.getApplication().getContentResolver(); | ||||
|         try { | ||||
|             value = Settings.System.getInt(cr, Settings.System.SCREEN_BRIGHTNESS); | ||||
|         } catch (Settings.SettingNotFoundException ignored) { | ||||
|         } | ||||
|         return value; | ||||
|     } | ||||
| 
 | ||||
|     public boolean disableScrollClickTurn() { | ||||
|         return preferences.getBoolean("disableScrollClickTurn", false); | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,318 @@ | ||||
| package xyz.fycz.myreader.entity; | ||||
| 
 | ||||
| import com.google.gson.Gson; | ||||
| 
 | ||||
| import java.io.Serializable; | ||||
| 
 | ||||
| import xyz.fycz.myreader.enums.Font; | ||||
| import xyz.fycz.myreader.enums.Language; | ||||
| import xyz.fycz.myreader.greendao.entity.Book; | ||||
| import xyz.fycz.myreader.widget.page.PageMode; | ||||
| 
 | ||||
| /** | ||||
|  * 阅读布局 | ||||
|  */ | ||||
| 
 | ||||
| public class ReadStyle implements Serializable { | ||||
| 
 | ||||
|     private static final long serialVersionUID = 2295691803219441757L; | ||||
| 
 | ||||
|     private int readWordSize;//阅读字体大小
 | ||||
| 
 | ||||
|     private int brightProgress;//亮度 1- 100
 | ||||
| 
 | ||||
|     private boolean brightFollowSystem;//亮度跟随系统
 | ||||
| 
 | ||||
|     private Language language;//简繁体
 | ||||
| 
 | ||||
|     private Font font;//字体
 | ||||
| 
 | ||||
|     private int autoScrollSpeed;//自动滑屏速度
 | ||||
| 
 | ||||
|     private PageMode pageMode;//翻页模式
 | ||||
| 
 | ||||
|     private boolean isVolumeTurnPage = true;//是否开启音量键翻页
 | ||||
| 
 | ||||
|     private int resetScreen = 3;//息屏时间(单位:min,0是不息屏)
 | ||||
| 
 | ||||
|     private String localFontName;//本地字体名字
 | ||||
| 
 | ||||
|     private boolean isShowStatusBar;//是否显示状态栏
 | ||||
| 
 | ||||
|     private boolean alwaysNext;//是否总是翻到下一页
 | ||||
| 
 | ||||
|     private int intent;//缩进字符
 | ||||
| 
 | ||||
|     private float lineMultiplier;//行间距
 | ||||
| 
 | ||||
|     private float paragraphSize;//段间距
 | ||||
| 
 | ||||
|     private float textLetterSpacing;//字间距
 | ||||
| 
 | ||||
|     private int paddingLeft;//左边距
 | ||||
|     private int paddingTop;//上边距
 | ||||
|     private int paddingRight;//右边距
 | ||||
|     private int paddingBottom;//下边距
 | ||||
| 
 | ||||
|     private int composition;//排版选择
 | ||||
| 
 | ||||
|     private boolean tightCom;//是否紧凑排版
 | ||||
| 
 | ||||
|     private boolean bgIsColor;//背景是否为颜色 不能共用
 | ||||
| 
 | ||||
|     private boolean bgIsAssert;//背景是否为assert文件 不能共用
 | ||||
| 
 | ||||
|     private int textColor;//文字颜色 不能共用
 | ||||
| 
 | ||||
|     private int bgColor;//背景颜色 不能共用
 | ||||
| 
 | ||||
|     private String bgPath;//背景图片地址 不能共用
 | ||||
| 
 | ||||
|     private boolean protectEye;//开启护眼模式
 | ||||
| 
 | ||||
|     private int blueFilterPercent;//蓝光过滤比率
 | ||||
| 
 | ||||
|     @Override | ||||
|     public Object clone() { | ||||
|         try { | ||||
|             Gson gson = new Gson(); | ||||
|             String json = gson.toJson(this); | ||||
|             return gson.fromJson(json, ReadStyle.class); | ||||
|         } catch (Exception e) { | ||||
|             e.printStackTrace(); | ||||
|         } | ||||
|         return this; | ||||
|     } | ||||
| 
 | ||||
|     public int getReadWordSize() { | ||||
|         return readWordSize; | ||||
|     } | ||||
| 
 | ||||
|     public void setReadWordSize(int readWordSize) { | ||||
|         this.readWordSize = readWordSize; | ||||
|     } | ||||
| 
 | ||||
|     public int getBrightProgress() { | ||||
|         return brightProgress; | ||||
|     } | ||||
| 
 | ||||
|     public void setBrightProgress(int brightProgress) { | ||||
|         this.brightProgress = brightProgress; | ||||
|     } | ||||
| 
 | ||||
|     public boolean isBrightFollowSystem() { | ||||
|         return brightFollowSystem; | ||||
|     } | ||||
| 
 | ||||
|     public void setBrightFollowSystem(boolean brightFollowSystem) { | ||||
|         this.brightFollowSystem = brightFollowSystem; | ||||
|     } | ||||
| 
 | ||||
|     public Language getLanguage() { | ||||
|         return language; | ||||
|     } | ||||
| 
 | ||||
|     public void setLanguage(Language language) { | ||||
|         this.language = language; | ||||
|     } | ||||
| 
 | ||||
|     public Font getFont() { | ||||
|         return font; | ||||
|     } | ||||
| 
 | ||||
|     public void setFont(Font font) { | ||||
|         this.font = font; | ||||
|     } | ||||
| 
 | ||||
|     public int getAutoScrollSpeed() { | ||||
|         return autoScrollSpeed; | ||||
|     } | ||||
| 
 | ||||
|     public void setAutoScrollSpeed(int autoScrollSpeed) { | ||||
|         this.autoScrollSpeed = autoScrollSpeed; | ||||
|     } | ||||
| 
 | ||||
|     public PageMode getPageMode() { | ||||
|         return pageMode; | ||||
|     } | ||||
| 
 | ||||
|     public void setPageMode(PageMode pageMode) { | ||||
|         this.pageMode = pageMode; | ||||
|     } | ||||
| 
 | ||||
|     public boolean isVolumeTurnPage() { | ||||
|         return isVolumeTurnPage; | ||||
|     } | ||||
| 
 | ||||
|     public void setVolumeTurnPage(boolean volumeTurnPage) { | ||||
|         isVolumeTurnPage = volumeTurnPage; | ||||
|     } | ||||
| 
 | ||||
|     public int getResetScreen() { | ||||
|         return resetScreen; | ||||
|     } | ||||
| 
 | ||||
|     public void setResetScreen(int resetScreen) { | ||||
|         this.resetScreen = resetScreen; | ||||
|     } | ||||
| 
 | ||||
|     public String getLocalFontName() { | ||||
|         return localFontName; | ||||
|     } | ||||
| 
 | ||||
|     public void setLocalFontName(String localFontName) { | ||||
|         this.localFontName = localFontName; | ||||
|     } | ||||
| 
 | ||||
|     public boolean isShowStatusBar() { | ||||
|         return isShowStatusBar; | ||||
|     } | ||||
| 
 | ||||
|     public void setShowStatusBar(boolean showStatusBar) { | ||||
|         isShowStatusBar = showStatusBar; | ||||
|     } | ||||
| 
 | ||||
|     public boolean isAlwaysNext() { | ||||
|         return alwaysNext; | ||||
|     } | ||||
| 
 | ||||
|     public void setAlwaysNext(boolean alwaysNext) { | ||||
|         this.alwaysNext = alwaysNext; | ||||
|     } | ||||
| 
 | ||||
|     public int getIntent() { | ||||
|         return intent; | ||||
|     } | ||||
| 
 | ||||
|     public void setIntent(int intent) { | ||||
|         this.intent = intent; | ||||
|     } | ||||
| 
 | ||||
|     public float getLineMultiplier() { | ||||
|         return lineMultiplier; | ||||
|     } | ||||
| 
 | ||||
|     public void setLineMultiplier(float lineMultiplier) { | ||||
|         this.lineMultiplier = lineMultiplier; | ||||
|     } | ||||
| 
 | ||||
|     public float getParagraphSize() { | ||||
|         return paragraphSize; | ||||
|     } | ||||
| 
 | ||||
|     public void setParagraphSize(float paragraphSize) { | ||||
|         this.paragraphSize = paragraphSize; | ||||
|     } | ||||
| 
 | ||||
|     public float getTextLetterSpacing() { | ||||
|         return textLetterSpacing; | ||||
|     } | ||||
| 
 | ||||
|     public void setTextLetterSpacing(float textLetterSpacing) { | ||||
|         this.textLetterSpacing = textLetterSpacing; | ||||
|     } | ||||
| 
 | ||||
|     public int getPaddingLeft() { | ||||
|         return paddingLeft; | ||||
|     } | ||||
| 
 | ||||
|     public void setPaddingLeft(int paddingLeft) { | ||||
|         this.paddingLeft = paddingLeft; | ||||
|     } | ||||
| 
 | ||||
|     public int getPaddingTop() { | ||||
|         return paddingTop; | ||||
|     } | ||||
| 
 | ||||
|     public void setPaddingTop(int paddingTop) { | ||||
|         this.paddingTop = paddingTop; | ||||
|     } | ||||
| 
 | ||||
|     public int getPaddingRight() { | ||||
|         return paddingRight; | ||||
|     } | ||||
| 
 | ||||
|     public void setPaddingRight(int paddingRight) { | ||||
|         this.paddingRight = paddingRight; | ||||
|     } | ||||
| 
 | ||||
|     public int getPaddingBottom() { | ||||
|         return paddingBottom; | ||||
|     } | ||||
| 
 | ||||
|     public void setPaddingBottom(int paddingBottom) { | ||||
|         this.paddingBottom = paddingBottom; | ||||
|     } | ||||
| 
 | ||||
|     public int getComposition() { | ||||
|         return composition; | ||||
|     } | ||||
| 
 | ||||
|     public void setComposition(int composition) { | ||||
|         this.composition = composition; | ||||
|     } | ||||
| 
 | ||||
|     public boolean isTightCom() { | ||||
|         return tightCom; | ||||
|     } | ||||
| 
 | ||||
|     public void setTightCom(boolean tightCom) { | ||||
|         this.tightCom = tightCom; | ||||
|     } | ||||
| 
 | ||||
|     public boolean bgIsColor() { | ||||
|         return bgIsColor; | ||||
|     } | ||||
| 
 | ||||
|     public void setBgIsColor(boolean bgIsColor) { | ||||
|         this.bgIsColor = bgIsColor; | ||||
|     } | ||||
| 
 | ||||
|     public boolean bgIsAssert() { | ||||
|         return bgIsAssert; | ||||
|     } | ||||
| 
 | ||||
|     public void setBgIsAssert(boolean bgIsAssert) { | ||||
|         this.bgIsAssert = bgIsAssert; | ||||
|     } | ||||
| 
 | ||||
|     public int getTextColor() { | ||||
|         return textColor; | ||||
|     } | ||||
| 
 | ||||
|     public void setTextColor(int textColor) { | ||||
|         this.textColor = textColor; | ||||
|     } | ||||
| 
 | ||||
|     public int getBgColor() { | ||||
|         return bgColor; | ||||
|     } | ||||
| 
 | ||||
|     public void setBgColor(int bgColor) { | ||||
|         this.bgColor = bgColor; | ||||
|     } | ||||
| 
 | ||||
|     public String getBgPath() { | ||||
|         return bgPath; | ||||
|     } | ||||
| 
 | ||||
|     public void setBgPath(String bgPath) { | ||||
|         this.bgPath = bgPath; | ||||
|     } | ||||
| 
 | ||||
|     public boolean isProtectEye() { | ||||
|         return protectEye; | ||||
|     } | ||||
| 
 | ||||
|     public void setProtectEye(boolean protectEye) { | ||||
|         this.protectEye = protectEye; | ||||
|     } | ||||
| 
 | ||||
|     public int getBlueFilterPercent() { | ||||
|         return blueFilterPercent; | ||||
|     } | ||||
| 
 | ||||
|     public void setBlueFilterPercent(int blueFilterPercent) { | ||||
|         this.blueFilterPercent = blueFilterPercent; | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,102 @@ | ||||
| package xyz.fycz.myreader.entity; | ||||
| 
 | ||||
| import xyz.fycz.myreader.greendao.entity.Book; | ||||
| 
 | ||||
| /** | ||||
|  * @author fengyue | ||||
|  * @date 2020/11/29 19:01 | ||||
|  */ | ||||
| public class SharedBook { | ||||
|     private String name; | ||||
|     private String author; | ||||
|     private String type; | ||||
|     private String desc; | ||||
|     private String imgUrl; | ||||
|     private String chapterUrl; | ||||
|     private String source; | ||||
| 
 | ||||
|     public String getName() { | ||||
|         return name; | ||||
|     } | ||||
| 
 | ||||
|     public void setName(String name) { | ||||
|         this.name = name; | ||||
|     } | ||||
| 
 | ||||
|     public String getAuthor() { | ||||
|         return author; | ||||
|     } | ||||
| 
 | ||||
|     public void setAuthor(String author) { | ||||
|         this.author = author; | ||||
|     } | ||||
| 
 | ||||
|     public String getType() { | ||||
|         return type; | ||||
|     } | ||||
| 
 | ||||
|     public void setType(String type) { | ||||
|         this.type = type; | ||||
|     } | ||||
| 
 | ||||
|     public String getDesc() { | ||||
|         return desc; | ||||
|     } | ||||
| 
 | ||||
|     public void setDesc(String desc) { | ||||
|         this.desc = desc; | ||||
|     } | ||||
| 
 | ||||
|     public String getImgUrl() { | ||||
|         return imgUrl; | ||||
|     } | ||||
| 
 | ||||
|     public void setImgUrl(String imgUrl) { | ||||
|         this.imgUrl = imgUrl; | ||||
|     } | ||||
| 
 | ||||
|     public String getChapterUrl() { | ||||
|         return chapterUrl; | ||||
|     } | ||||
| 
 | ||||
|     public void setChapterUrl(String chapterUrl) { | ||||
|         this.chapterUrl = chapterUrl; | ||||
|     } | ||||
| 
 | ||||
|     public String getSource() { | ||||
|         return source; | ||||
|     } | ||||
| 
 | ||||
|     public void setSource(String source) { | ||||
|         this.source = source; | ||||
|     } | ||||
| 
 | ||||
|     public static SharedBook bookToSharedBook(Book book){ | ||||
|         int maxDesc = 208; | ||||
|         String desc = book.getDesc(); | ||||
|         if (desc.length() > maxDesc){ | ||||
|             desc = desc.substring(0, maxDesc - 1) + "…"; | ||||
|         } | ||||
|         SharedBook sharedBook = new SharedBook(); | ||||
|         sharedBook.setName(book.getName()); | ||||
|         sharedBook.setAuthor(book.getAuthor()); | ||||
|         sharedBook.setType(book.getType()); | ||||
|         sharedBook.setDesc(desc); | ||||
|         sharedBook.setImgUrl(book.getImgUrl()); | ||||
|         sharedBook.setChapterUrl(book.getChapterUrl()); | ||||
|         sharedBook.setSource(book.getSource()); | ||||
|         return sharedBook; | ||||
|     } | ||||
| 
 | ||||
|     public static Book sharedBookToBook(SharedBook sharedBook){ | ||||
|         Book book = new Book(); | ||||
|         book.setName(sharedBook.name); | ||||
|         book.setAuthor(sharedBook.author); | ||||
|         book.setType(sharedBook.type); | ||||
|         book.setDesc(sharedBook.desc); | ||||
|         book.setImgUrl(sharedBook.imgUrl); | ||||
|         book.setChapterUrl(sharedBook.chapterUrl); | ||||
|         book.setSource(sharedBook.source); | ||||
|         return book; | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,169 @@ | ||||
| package xyz.fycz.myreader.greendao.entity; | ||||
| 
 | ||||
| import android.os.Parcel; | ||||
| import android.os.Parcelable; | ||||
| 
 | ||||
| import org.greenrobot.greendao.annotation.Entity; | ||||
| import org.greenrobot.greendao.annotation.Generated; | ||||
| import org.greenrobot.greendao.annotation.Id; | ||||
| import org.greenrobot.greendao.annotation.OrderBy; | ||||
| import org.greenrobot.greendao.annotation.Transient; | ||||
| 
 | ||||
| import java.util.regex.Pattern; | ||||
| 
 | ||||
| /** | ||||
|  * Created by GKF on 2018/2/7. | ||||
|  * 阅读内容替换规则 | ||||
|  */ | ||||
| @Entity | ||||
| public class ReplaceRuleBean implements Parcelable { | ||||
|     @Id(autoincrement = true) | ||||
|     private Long id; | ||||
|     //描述
 | ||||
|     private String replaceSummary; | ||||
|     //替换规则
 | ||||
|     private String regex; | ||||
|     //替换为
 | ||||
|     private String replacement; | ||||
|     //作用于
 | ||||
|     private String useTo; | ||||
| 
 | ||||
|     private Boolean enable; | ||||
| 
 | ||||
|     private Boolean isRegex; | ||||
| 
 | ||||
|     @OrderBy | ||||
|     private int serialNumber; | ||||
| 
 | ||||
|     private ReplaceRuleBean(Parcel in) { | ||||
|         id = in.readLong(); | ||||
|         regex = in.readString(); | ||||
|         replacement = in.readString(); | ||||
|         replaceSummary = in.readString(); | ||||
|         useTo = in.readString(); | ||||
|         enable = in.readByte() != 0; | ||||
|         serialNumber = in.readInt(); | ||||
|         isRegex = in.readByte() != 0; | ||||
|     } | ||||
| 
 | ||||
|     @Generated(hash = 1896663649) | ||||
|     public ReplaceRuleBean(Long id, String replaceSummary, String regex, String replacement, | ||||
|                            String useTo, Boolean enable, Boolean isRegex, int serialNumber) { | ||||
|         this.id = id; | ||||
|         this.replaceSummary = replaceSummary; | ||||
|         this.regex = regex; | ||||
|         this.replacement = replacement; | ||||
|         this.useTo = useTo; | ||||
|         this.enable = enable; | ||||
|         this.isRegex = isRegex; | ||||
|         this.serialNumber = serialNumber; | ||||
|     } | ||||
| 
 | ||||
|     @Generated(hash = 582692869) | ||||
|     public ReplaceRuleBean() { | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void writeToParcel(Parcel parcel, int i) { | ||||
|         parcel.writeLong(id); | ||||
|         parcel.writeString(regex); | ||||
|         parcel.writeString(replacement); | ||||
|         parcel.writeString(replaceSummary); | ||||
|         parcel.writeString(useTo); | ||||
|         parcel.writeByte((byte) (enable ? 1 : 0)); | ||||
|         parcel.writeInt(serialNumber); | ||||
|         parcel.writeByte((byte) (isRegex ? 1 : 0)); | ||||
|     } | ||||
| 
 | ||||
|     @Transient | ||||
|     public static final Creator<ReplaceRuleBean> CREATOR = new Creator<ReplaceRuleBean>() { | ||||
|         @Override | ||||
|         public ReplaceRuleBean createFromParcel(Parcel in) { | ||||
|             return new ReplaceRuleBean(in); | ||||
|         } | ||||
| 
 | ||||
|         @Override | ||||
|         public ReplaceRuleBean[] newArray(int size) { | ||||
|             return new ReplaceRuleBean[size]; | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     @Override | ||||
|     public int describeContents() { | ||||
|         return 0; | ||||
|     } | ||||
| 
 | ||||
|     public String getReplaceSummary() { | ||||
|         return this.replaceSummary; | ||||
|     } | ||||
| 
 | ||||
|     public void setReplaceSummary(String replaceSummary) { | ||||
|         this.replaceSummary = replaceSummary; | ||||
|     } | ||||
| 
 | ||||
|     public String getRegex() { | ||||
|         return this.regex; | ||||
|     } | ||||
| 
 | ||||
|     public String getFixedRegex() { | ||||
|         if (getIsRegex()) | ||||
|             return this.regex; | ||||
|         else | ||||
|             return Pattern.quote(regex); | ||||
|     } | ||||
| 
 | ||||
|     public void setRegex(String regex) { | ||||
|         this.regex = regex; | ||||
|     } | ||||
| 
 | ||||
|     public String getReplacement() { | ||||
|         return this.replacement; | ||||
|     } | ||||
| 
 | ||||
|     public void setReplacement(String replacement) { | ||||
|         this.replacement = replacement; | ||||
|     } | ||||
| 
 | ||||
|     public Boolean getEnable() { | ||||
|         if (enable == null) { | ||||
|             return false; | ||||
|         } | ||||
|         return this.enable; | ||||
|     } | ||||
| 
 | ||||
|     public void setEnable(Boolean enable) { | ||||
|         this.enable = enable; | ||||
|     } | ||||
| 
 | ||||
|     public int getSerialNumber() { | ||||
|         return this.serialNumber; | ||||
|     } | ||||
| 
 | ||||
|     public void setSerialNumber(int serialNumber) { | ||||
|         this.serialNumber = serialNumber; | ||||
|     } | ||||
| 
 | ||||
|     public Long getId() { | ||||
|         return this.id; | ||||
|     } | ||||
| 
 | ||||
|     public void setId(Long id) { | ||||
|         this.id = id; | ||||
|     } | ||||
| 
 | ||||
|     public String getUseTo() { | ||||
|         return this.useTo; | ||||
|     } | ||||
| 
 | ||||
|     public void setUseTo(String useTo) { | ||||
|         this.useTo = useTo; | ||||
|     } | ||||
| 
 | ||||
|     public Boolean getIsRegex() { | ||||
|         return isRegex == null ? true : isRegex; | ||||
|     } | ||||
| 
 | ||||
|     public void setIsRegex(Boolean isRegex) { | ||||
|         this.isRegex = isRegex; | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,114 @@ | ||||
| package xyz.fycz.myreader.model; | ||||
| 
 | ||||
| import android.text.TextUtils; | ||||
| 
 | ||||
| 
 | ||||
| import java.util.List; | ||||
| 
 | ||||
| import io.reactivex.Observable; | ||||
| import io.reactivex.Single; | ||||
| import io.reactivex.SingleOnSubscribe; | ||||
| import xyz.fycz.myreader.greendao.GreenDaoManager; | ||||
| import xyz.fycz.myreader.greendao.entity.ReplaceRuleBean; | ||||
| import xyz.fycz.myreader.greendao.gen.ReplaceRuleBeanDao; | ||||
| import xyz.fycz.myreader.util.utils.GsonUtils; | ||||
| import xyz.fycz.myreader.util.utils.NetworkUtils; | ||||
| import xyz.fycz.myreader.util.utils.RxUtils; | ||||
| import xyz.fycz.myreader.util.utils.StringUtils; | ||||
| 
 | ||||
| /** | ||||
|  * Created by GKF on 2018/2/12. | ||||
|  * 替换规则管理 | ||||
|  */ | ||||
| 
 | ||||
| public class ReplaceRuleManager { | ||||
|     private static List<ReplaceRuleBean> replaceRuleBeansEnabled; | ||||
| 
 | ||||
|     public static List<ReplaceRuleBean> getEnabled() { | ||||
|         if (replaceRuleBeansEnabled == null) { | ||||
|             replaceRuleBeansEnabled = GreenDaoManager.getDaoSession() | ||||
|                     .getReplaceRuleBeanDao().queryBuilder() | ||||
|                     .where(ReplaceRuleBeanDao.Properties.Enable.eq(true)) | ||||
|                     .orderAsc(ReplaceRuleBeanDao.Properties.SerialNumber) | ||||
|                     .list(); | ||||
|         } | ||||
|         return replaceRuleBeansEnabled; | ||||
|     } | ||||
| 
 | ||||
|     public static Single<List<ReplaceRuleBean>> getAll() { | ||||
|         return Single.create((SingleOnSubscribe<List<ReplaceRuleBean>>) emitter -> emitter.onSuccess(GreenDaoManager.getDaoSession() | ||||
|                 .getReplaceRuleBeanDao().queryBuilder() | ||||
|                 .orderAsc(ReplaceRuleBeanDao.Properties.SerialNumber) | ||||
|                 .list())).compose(RxUtils::toSimpleSingle); | ||||
|     } | ||||
| 
 | ||||
|     public static Single<Boolean> saveData(ReplaceRuleBean replaceRuleBean) { | ||||
|         return Single.create((SingleOnSubscribe<Boolean>) emitter -> { | ||||
|             if (replaceRuleBean.getSerialNumber() == 0) { | ||||
|                 replaceRuleBean.setSerialNumber((int) (GreenDaoManager.getDaoSession().getReplaceRuleBeanDao().queryBuilder().count() + 1)); | ||||
|             } | ||||
|             GreenDaoManager.getDaoSession().getReplaceRuleBeanDao().insertOrReplace(replaceRuleBean); | ||||
|             refreshDataS(); | ||||
|             emitter.onSuccess(true); | ||||
|         }).compose(RxUtils::toSimpleSingle); | ||||
|     } | ||||
| 
 | ||||
|     public static void delData(ReplaceRuleBean replaceRuleBean) { | ||||
|         GreenDaoManager.getDaoSession().getReplaceRuleBeanDao().delete(replaceRuleBean); | ||||
|         refreshDataS(); | ||||
|     } | ||||
| 
 | ||||
|     public static void addDataS(List<ReplaceRuleBean> replaceRuleBeans) { | ||||
|         if (replaceRuleBeans != null && replaceRuleBeans.size() > 0) { | ||||
|             GreenDaoManager.getDaoSession().getReplaceRuleBeanDao().insertOrReplaceInTx(replaceRuleBeans); | ||||
|             refreshDataS(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public static void delDataS(List<ReplaceRuleBean> replaceRuleBeans) { | ||||
|         for (ReplaceRuleBean replaceRuleBean : replaceRuleBeans) { | ||||
|             GreenDaoManager.getDaoSession().getReplaceRuleBeanDao().delete(replaceRuleBean); | ||||
|         } | ||||
|         refreshDataS(); | ||||
|     } | ||||
| 
 | ||||
|     private static void refreshDataS() { | ||||
|         replaceRuleBeansEnabled = GreenDaoManager.getDaoSession() | ||||
|                 .getReplaceRuleBeanDao().queryBuilder() | ||||
|                 .where(ReplaceRuleBeanDao.Properties.Enable.eq(true)) | ||||
|                 .orderAsc(ReplaceRuleBeanDao.Properties.SerialNumber) | ||||
|                 .list(); | ||||
|     } | ||||
| 
 | ||||
|     public static Observable<Boolean> importReplaceRule(String text) { | ||||
|         if (TextUtils.isEmpty(text)) return null; | ||||
|         text = text.trim(); | ||||
|         if (text.length() == 0) return null; | ||||
|         if (StringUtils.isJsonType(text)) { | ||||
|             return importReplaceRuleO(text) | ||||
|                     .compose(RxUtils::toSimpleSingle); | ||||
|         } | ||||
|         /*if (NetworkUtils.isUrl(text)) { | ||||
|             return BaseModelImpl.getInstance().getRetrofitString(StringUtils.getBaseUrl(text), "utf-8") | ||||
|                     .create(IHttpGetApi.class) | ||||
|                     .get(text, AnalyzeHeaders.getMap(null)) | ||||
|                     .flatMap(rsp -> importReplaceRuleO(rsp.body())) | ||||
|                     .compose(RxUtils::toSimpleSingle); | ||||
|         }*/ | ||||
|         return Observable.error(new Exception("不是Json或Url格式")); | ||||
|     } | ||||
| 
 | ||||
|     private static Observable<Boolean> importReplaceRuleO(String json) { | ||||
|         return Observable.create(e -> { | ||||
|             try { | ||||
|                 List<ReplaceRuleBean> replaceRuleBeans = GsonUtils.parseJArray(json, ReplaceRuleBean.class); | ||||
|                 addDataS(replaceRuleBeans); | ||||
|                 e.onNext(true); | ||||
|             } catch (Exception e1) { | ||||
|                 e1.printStackTrace(); | ||||
|                 e.onNext(false); | ||||
|             } | ||||
|             e.onComplete(); | ||||
|         }); | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,333 @@ | ||||
| package xyz.fycz.myreader.model.backup; | ||||
| 
 | ||||
| import io.reactivex.annotations.NonNull; | ||||
| import xyz.fycz.myreader.application.MyApplication; | ||||
| import xyz.fycz.myreader.model.storage.Backup; | ||||
| import xyz.fycz.myreader.model.storage.Restore; | ||||
| import xyz.fycz.myreader.webapi.callback.ResultCallback; | ||||
| import xyz.fycz.myreader.common.APPCONST; | ||||
| import xyz.fycz.myreader.common.URLCONST; | ||||
| import xyz.fycz.myreader.util.*; | ||||
| import xyz.fycz.myreader.util.utils.FileUtils; | ||||
| 
 | ||||
| import java.io.*; | ||||
| import java.net.HttpURLConnection; | ||||
| import java.net.URL; | ||||
| import java.util.HashMap; | ||||
| import java.util.Map; | ||||
| 
 | ||||
| /** | ||||
|  * @author fengyue | ||||
|  * @date 2020/4/26 11:03 | ||||
|  */ | ||||
| public class UserService { | ||||
|     /** | ||||
|      * 登录 | ||||
|      * @param userLoginInfo 用户名输入的用户名和密码等登录信息 | ||||
|      * @return 是否成功登录 | ||||
|      */ | ||||
|     public static void login(final Map<String, String> userLoginInfo, final ResultCallback resultCallback) { | ||||
|         MyApplication.getApplication().newThread(() -> { | ||||
|             HttpURLConnection conn = null; | ||||
|             try { | ||||
|                 URL url = new URL(URLCONST.APP_WEB_URL + "login"); | ||||
|                 conn = (HttpURLConnection) url.openConnection(); | ||||
|                 conn.setRequestMethod("POST"); | ||||
|                 conn.setConnectTimeout(60 * 1000); | ||||
|                 conn.setReadTimeout(60 * 1000); | ||||
|                 conn.setDoInput(true); | ||||
|                 conn.setDoOutput(true); | ||||
|                 String params = "username=" + userLoginInfo.get("loginName") + | ||||
|                         "&password=" + userLoginInfo.get("loginPwd") + makeSignalParam(); | ||||
|                 // 获取URLConnection对象对应的输出流
 | ||||
|                 PrintWriter out = new PrintWriter(conn.getOutputStream()); | ||||
|                 // 发送请求参数
 | ||||
|                 out.print(params); | ||||
|                 // flush输出流的缓冲
 | ||||
|                 out.flush(); | ||||
|                 InputStream in = conn.getInputStream(); | ||||
|                 BufferedReader bw = new BufferedReader(new InputStreamReader(in, "utf-8")); | ||||
|                 StringBuilder sb = new StringBuilder(); | ||||
|                 String line = bw.readLine(); | ||||
|                 while (line != null) { | ||||
|                     sb.append(line); | ||||
|                     line = bw.readLine(); | ||||
|                 } | ||||
|                 resultCallback.onFinish(sb.toString(), 1); | ||||
|             } catch (IOException e) { | ||||
|                 e.printStackTrace(); | ||||
|                 resultCallback.onError(e); | ||||
|             }finally { | ||||
|                 if (conn != null) { | ||||
|                     conn.disconnect(); | ||||
|                 } | ||||
|             } | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     public static void register(final Map<String, String> userRegisterInfo, final ResultCallback resultCallback) { | ||||
|         MyApplication.getApplication().newThread(() -> { | ||||
|             HttpURLConnection conn = null; | ||||
|             try { | ||||
|                 URL url = new URL(URLCONST.APP_WEB_URL + "reg"); | ||||
|                 conn = (HttpURLConnection) url.openConnection(); | ||||
|                 conn.setRequestMethod("POST"); | ||||
|                 conn.setDoInput(true); | ||||
|                 conn.setDoOutput(true); | ||||
|                 String params = "username=" + userRegisterInfo.get("username") + "&password=" + | ||||
|                         CyptoUtils.encode(APPCONST.KEY, userRegisterInfo.get("password")) + "&key=" + | ||||
|                         CyptoUtils.encode(APPCONST.KEY, APPCONST.publicKey)  + makeSignalParam(); | ||||
|                 // 获取URLConnection对象对应的输出流
 | ||||
|                 PrintWriter out = new PrintWriter(conn.getOutputStream()); | ||||
|                 // 发送请求参数
 | ||||
|                 out.print(params); | ||||
|                 // flush输出流的缓冲
 | ||||
|                 out.flush(); | ||||
|                 BufferedReader bw = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8")); | ||||
|                 StringBuilder sb = new StringBuilder(); | ||||
|                 String line = bw.readLine(); | ||||
|                 while (line != null) { | ||||
|                     sb.append(line); | ||||
|                     line = bw.readLine(); | ||||
|                 } | ||||
|                 resultCallback.onFinish(sb.toString(), 1); | ||||
|             } catch (IOException e) { | ||||
|                 e.printStackTrace(); | ||||
|                 resultCallback.onError(e); | ||||
|             } finally { | ||||
|                 if (conn != null) { | ||||
|                     conn.disconnect(); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 写配置 | ||||
|      * @param userLoginInfo | ||||
|      * @return | ||||
|      */ | ||||
|     public static boolean writeConfig(Map<String,String> userLoginInfo){ | ||||
|         FileOutputStream fos = null; | ||||
|         try { | ||||
|             fos = MyApplication.getApplication().openFileOutput("userConfig.fy", MyApplication.getApplication().MODE_PRIVATE); | ||||
|             String userInfo = "username='" + userLoginInfo.get("loginName") + "',\npassword='" + userLoginInfo.get("loginPwd") + "'"; | ||||
|             byte[] bs = userInfo.getBytes(); | ||||
|             fos.write(bs); | ||||
|             //写完后一定要刷新
 | ||||
|             fos.flush(); | ||||
|             return true; | ||||
|         } catch (IOException e) { | ||||
|             e.printStackTrace(); | ||||
|             return false; | ||||
|         } finally { | ||||
|             IOUtils.close(fos); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 读配置 | ||||
|      * @return | ||||
|      */ | ||||
|     public static Map<String,String> readConfig(){ | ||||
|         File file = MyApplication.getApplication().getFileStreamPath("userConfig.fy"); | ||||
|         if (!file.exists()){ | ||||
|             return null; | ||||
|         } | ||||
|         BufferedReader br = null; | ||||
|         try { | ||||
|             br = new BufferedReader(new FileReader(file)); | ||||
|             String tem; | ||||
|             StringBuilder config = new StringBuilder(); | ||||
|             while ((tem = br.readLine()) != null){ | ||||
|                 config.append(tem); | ||||
|             } | ||||
|             String[] user = config.toString().split(","); | ||||
|             String userName = user[0].substring(user[0].indexOf("'") + 1, user[0].lastIndexOf("'")); | ||||
|             String password = user[1].substring(user[1].indexOf("'") + 1, user[1].lastIndexOf("'")); | ||||
|             Map<String,String> userInfo = new HashMap<>(); | ||||
|             userInfo.put("userName", userName); | ||||
|             userInfo.put("password", password); | ||||
|             return userInfo; | ||||
|         } catch (IOException e) { | ||||
|             e.printStackTrace(); | ||||
|         }finally { | ||||
|             IOUtils.close(br); | ||||
|         } | ||||
|         return null; | ||||
|     } | ||||
| 
 | ||||
|     public static void writeUsername(String username){ | ||||
|         File file = FileUtils.getFile(APPCONST.QQ_DATA_DIR + "user"); | ||||
|         BufferedWriter bw = null; | ||||
|         try { | ||||
|             bw = new BufferedWriter(new FileWriter(file)); | ||||
|             bw.write(username); | ||||
|             bw.flush(); | ||||
|         } catch (IOException e) { | ||||
|             e.printStackTrace(); | ||||
|         }finally { | ||||
|             IOUtils.close(bw); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public static String readUsername(){ | ||||
|         File file = new File(APPCONST.QQ_DATA_DIR + "user"); | ||||
|         if (!file.exists()){ | ||||
|             return ""; | ||||
|         } | ||||
|         BufferedReader br = null; | ||||
|         try { | ||||
|             br = new BufferedReader(new FileReader(file)); | ||||
|             return br.readLine(); | ||||
|         } catch (IOException e) { | ||||
|             e.printStackTrace(); | ||||
|             return ""; | ||||
|         } finally { | ||||
|             IOUtils.close(br); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 网络备份 | ||||
|      * @return | ||||
|      */ | ||||
|     public static void webBackup(ResultCallback rc){ | ||||
|         Map<String,String> userInfo = readConfig(); | ||||
|         if (userInfo == null){ | ||||
|             rc.onFinish(false, 0); | ||||
|         } | ||||
|         Backup.INSTANCE.backup(MyApplication.getmContext(), APPCONST.FILE_DIR + "webBackup/", new Backup.CallBack() { | ||||
|             @Override | ||||
|             public void backupSuccess() { | ||||
|                 MyApplication.getApplication().newThread(() ->{ | ||||
|                     File inputFile = FileUtils.getFile(APPCONST.FILE_DIR + "webBackup"); | ||||
|                     if (!inputFile.exists()) { | ||||
|                         rc.onFinish(false, 0); | ||||
|                     } | ||||
|                     File zipFile = FileUtils.getFile(APPCONST.FILE_DIR + "webBackup.zip"); | ||||
|                     FileInputStream fis = null; | ||||
|                     HttpURLConnection conn = null; | ||||
|                     try { | ||||
|                         //压缩文件
 | ||||
|                         ZipUtils.zipFile(inputFile, zipFile); | ||||
|                         fis = new FileInputStream(zipFile); | ||||
|                         URL url = new URL(URLCONST.APP_WEB_URL + "bak?username=" + userInfo.get("userName") + | ||||
|                                 makeSignalParam()); | ||||
|                         conn = (HttpURLConnection) url.openConnection(); | ||||
|                         conn.setRequestMethod("POST"); | ||||
|                         conn.setRequestProperty("Content-type", "multipart/form-data"); | ||||
|                         conn.setDoInput(true); | ||||
|                         conn.setDoOutput(true); | ||||
|                         OutputStream out = conn.getOutputStream(); | ||||
|                         byte[] bytes = new byte[1024]; | ||||
|                         int len = -1; | ||||
|                         while ((len = fis.read(bytes)) != -1){ | ||||
|                             out.write(bytes, 0, len); | ||||
|                         } | ||||
|                         out.flush(); | ||||
|                         zipFile.delete(); | ||||
|                         BufferedReader bw = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8")); | ||||
|                         StringBuilder sb = new StringBuilder(); | ||||
|                         String line = bw.readLine(); | ||||
|                         while (line != null) { | ||||
|                             sb.append(line); | ||||
|                             line = bw.readLine(); | ||||
|                         } | ||||
|                         String[] info = sb.toString().split(":"); | ||||
|                         int code = Integer.parseInt(info[0].trim()); | ||||
|                         rc.onFinish(code == 104, 0); | ||||
|                     } catch (Exception e) { | ||||
|                         e.printStackTrace(); | ||||
|                         rc.onError(e); | ||||
|                     } finally { | ||||
|                         IOUtils.close(fis); | ||||
|                         if (conn != null) { | ||||
|                             conn.disconnect(); | ||||
|                         } | ||||
|                     } | ||||
|                 }); | ||||
|             } | ||||
| 
 | ||||
|             @Override | ||||
|             public void backupError(@NonNull String msg) { | ||||
|                 ToastUtils.showError(msg); | ||||
|                 rc.onFinish(false, 0); | ||||
|             } | ||||
|         }, false); | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 网络恢复 | ||||
|      * @return | ||||
|      */ | ||||
|     public static void webRestore(ResultCallback rc){ | ||||
|         Map<String,String> userInfo = readConfig(); | ||||
|         if (userInfo == null){ | ||||
|             rc.onFinish(false, 0); | ||||
|         } | ||||
|         FileOutputStream fos = null; | ||||
|         File zipFile = FileUtils.getFile(APPCONST.FILE_DIR + "webBackup.zip"); | ||||
|         HttpURLConnection conn = null; | ||||
|         try { | ||||
|             URL url = new URL(URLCONST.APP_WEB_URL + "ret?username=" + userInfo.get("userName") + | ||||
|                     makeSignalParam()); | ||||
|             conn = (HttpURLConnection) url.openConnection(); | ||||
|             conn.setRequestMethod("POST"); | ||||
|             conn.setDoInput(true); | ||||
|             InputStream is = conn.getInputStream(); | ||||
|             fos = new FileOutputStream(zipFile); | ||||
|             //一边读,一边写
 | ||||
|             byte[] bytes = new byte[512]; | ||||
|             int readCount = 0; | ||||
|             while ((readCount = is.read(bytes)) != -1) { | ||||
|                 fos.write(bytes,0, readCount); | ||||
|             } | ||||
|             //刷新,输出流一定要刷新
 | ||||
|             fos.flush(); | ||||
|             if (zipFile.length() == 0){ | ||||
|                 zipFile.delete(); | ||||
|                 rc.onFinish(false, 0); | ||||
|             } | ||||
|             ZipUtils.unzipFile(zipFile.getAbsolutePath(), APPCONST.FILE_DIR); | ||||
|             Restore.INSTANCE.restore(APPCONST.FILE_DIR + "webBackup/", new Restore.CallBack() { | ||||
|                 @Override | ||||
|                 public void restoreSuccess() { | ||||
|                     zipFile.delete(); | ||||
|                     rc.onFinish(true, 0); | ||||
|                 } | ||||
| 
 | ||||
|                 @Override | ||||
|                 public void restoreError(@NonNull String msg) { | ||||
|                     ToastUtils.showError(msg); | ||||
|                     rc.onFinish(false, 0); | ||||
|                 } | ||||
|             }); | ||||
|         } catch (Exception e) { | ||||
|             e.printStackTrace(); | ||||
|             rc.onError(e); | ||||
|         }finally { | ||||
|             IOUtils.close(fos); | ||||
|             if (conn != null) { | ||||
|                 conn.disconnect(); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     private static String makeSignalParam(){ | ||||
|         return "&signal=" + AppInfoUtils.getSingInfo(MyApplication.getmContext(), | ||||
|                 MyApplication.getApplication().getPackageName(), AppInfoUtils.SHA1); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 判断是否登录 | ||||
|      * @return | ||||
|      */ | ||||
|     public static boolean isLogin(){ | ||||
|         File file = MyApplication.getApplication().getFileStreamPath("userConfig.fy"); | ||||
|         return file.exists(); | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,231 @@ | ||||
| package xyz.fycz.myreader.ui.activity; | ||||
| 
 | ||||
| import android.annotation.SuppressLint; | ||||
| import android.app.Activity; | ||||
| import android.app.ProgressDialog; | ||||
| import android.content.Intent; | ||||
| import android.graphics.Bitmap; | ||||
| import android.os.Bundle; | ||||
| import android.os.Handler; | ||||
| import android.os.Message; | ||||
| import android.text.Editable; | ||||
| import android.text.TextWatcher; | ||||
| import android.view.MotionEvent; | ||||
| import android.view.View; | ||||
| import android.view.inputmethod.InputMethodManager; | ||||
| import android.widget.Button; | ||||
| import android.widget.ImageView; | ||||
| import android.widget.TextView; | ||||
| import androidx.appcompat.widget.Toolbar; | ||||
| import butterknife.BindView; | ||||
| import com.google.android.material.textfield.TextInputLayout; | ||||
| import xyz.fycz.myreader.R; | ||||
| import xyz.fycz.myreader.model.backup.UserService; | ||||
| import xyz.fycz.myreader.base.BaseActivity; | ||||
| import xyz.fycz.myreader.webapi.callback.ResultCallback; | ||||
| import xyz.fycz.myreader.common.APPCONST; | ||||
| import xyz.fycz.myreader.ui.dialog.DialogCreator; | ||||
| import xyz.fycz.myreader.util.CodeUtil; | ||||
| import xyz.fycz.myreader.util.CyptoUtils; | ||||
| import xyz.fycz.myreader.util.ToastUtils; | ||||
| import xyz.fycz.myreader.util.utils.NetworkUtils; | ||||
| import xyz.fycz.myreader.util.utils.StringUtils; | ||||
| 
 | ||||
| import java.util.HashMap; | ||||
| import java.util.Map; | ||||
| 
 | ||||
| /** | ||||
|  * @author fengyue | ||||
|  * @date 2020/9/18 22:27 | ||||
|  */ | ||||
| public class LoginActivity extends BaseActivity implements TextWatcher { | ||||
|     @BindView(R.id.et_user) | ||||
|     TextInputLayout user; | ||||
|     @BindView(R.id.et_password) | ||||
|     TextInputLayout password; | ||||
|     @BindView(R.id.bt_login) | ||||
|     Button loginBtn; | ||||
|     @BindView(R.id.tv_register) | ||||
|     TextView tvRegister; | ||||
|     @BindView(R.id.et_captcha) | ||||
|     TextInputLayout etCaptcha; | ||||
|     @BindView(R.id.iv_captcha) | ||||
|     ImageView ivCaptcha; | ||||
| 
 | ||||
|     private String code; | ||||
| 
 | ||||
|     @SuppressLint("HandlerLeak") | ||||
|     private Handler mHandler = new Handler() { | ||||
|         @SuppressLint("HandlerLeak") | ||||
|         @Override | ||||
|         public void handleMessage(Message msg) { | ||||
|             switch (msg.what) { | ||||
|                 case 1: | ||||
|                     loginBtn.setEnabled(true); | ||||
|                     break; | ||||
|                 case 2: | ||||
|                     createCaptcha(); | ||||
|                     break; | ||||
|             } | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     @Override | ||||
|     protected int getContentId() { | ||||
|         return R.layout.activity_login; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     protected void setUpToolbar(Toolbar toolbar) { | ||||
|         super.setUpToolbar(toolbar); | ||||
|         setStatusBarColor(R.color.colorPrimary, true); | ||||
|         getSupportActionBar().setTitle("登录"); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     protected void initData(Bundle savedInstanceState) { | ||||
|         super.initData(savedInstanceState); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     protected void initWidget() { | ||||
|         super.initWidget(); | ||||
|         mHandler.sendMessage(mHandler.obtainMessage(2)); | ||||
|         String username = UserService.readUsername(); | ||||
|         user.getEditText().setText(username); | ||||
|         user.getEditText().requestFocus(username.length()); | ||||
|         //监听内容改变 -> 控制按钮的点击状态
 | ||||
|         user.getEditText().addTextChangedListener(this); | ||||
|         password.getEditText().addTextChangedListener(this); | ||||
|         etCaptcha.getEditText().addTextChangedListener(this); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     protected void initClick() { | ||||
|         super.initClick(); | ||||
|         ivCaptcha.setOnClickListener(v -> mHandler.sendMessage(mHandler.obtainMessage(2))); | ||||
| 
 | ||||
|         loginBtn.setOnClickListener(v -> { | ||||
|             mHandler.sendMessage(mHandler.obtainMessage(2)); | ||||
|             if (!code.toLowerCase().equals(etCaptcha.getEditText().getText().toString().toLowerCase())){ | ||||
|                 DialogCreator.createTipDialog(this, "验证码错误!"); | ||||
|                 return; | ||||
|             } | ||||
|             if (!NetworkUtils.isNetWorkAvailable()) { | ||||
|                 ToastUtils.showError("无网络连接!"); | ||||
|                 return; | ||||
|             } | ||||
|             ProgressDialog dialog = DialogCreator.createProgressDialog(this, null, "正在登陆..."); | ||||
|             loginBtn.setEnabled(false); | ||||
|             final String loginName = user.getEditText().getText().toString().trim(); | ||||
|             String loginPwd = password.getEditText().getText().toString(); | ||||
|             final Map<String, String> userLoginInfo = new HashMap<>(); | ||||
|             userLoginInfo.put("loginName", loginName); | ||||
|             userLoginInfo.put("loginPwd", CyptoUtils.encode(APPCONST.KEY, loginPwd)); | ||||
|             //验证用户名和密码
 | ||||
|             UserService.login(userLoginInfo, new ResultCallback() { | ||||
|                 @Override | ||||
|                 public void onFinish(Object o, int code) { | ||||
|                     String result = (String) o; | ||||
|                     String[] info = result.split(":"); | ||||
|                     int resultCode = Integer.parseInt(info[0].trim()); | ||||
|                     String resultName = info[1].trim(); | ||||
|                     //最后输出结果
 | ||||
|                     if (resultCode == 102) { | ||||
|                         UserService.writeConfig(userLoginInfo); | ||||
|                         UserService.writeUsername(loginName); | ||||
|                         Intent intent = new Intent(); | ||||
|                         intent.putExtra("isLogin", true); | ||||
|                         setResult(Activity.RESULT_OK, intent); | ||||
|                         finish(); | ||||
|                         ToastUtils.showSuccess(resultName); | ||||
|                     } else { | ||||
|                         mHandler.sendMessage(mHandler.obtainMessage(1)); | ||||
|                         dialog.dismiss(); | ||||
|                         ToastUtils.showWarring(resultName); | ||||
|                     } | ||||
| 
 | ||||
|                 } | ||||
| 
 | ||||
|                 @Override | ||||
|                 public void onError(Exception e) { | ||||
|                     ToastUtils.showError("登录失败\n" + e.getLocalizedMessage()); | ||||
|                     mHandler.sendMessage(mHandler.obtainMessage(1)); | ||||
|                     dialog.dismiss(); | ||||
|                 } | ||||
|             }); | ||||
| 
 | ||||
|         }); | ||||
| 
 | ||||
|         tvRegister.setOnClickListener(v -> { | ||||
|             Intent intent = new Intent(LoginActivity.this, RegisterActivity.class); | ||||
|             startActivity(intent); | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     public void createCaptcha() { | ||||
|         code = CodeUtil.getInstance().createCode(); | ||||
|         Bitmap codeBitmap = CodeUtil.getInstance().createBitmap(code); | ||||
|         ivCaptcha.setImageBitmap(codeBitmap); | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     /** | ||||
|      * 当有控件获得焦点focus 自动弹出键盘 | ||||
|      * 1. 点击软键盘的enter键 自动收回键盘 | ||||
|      * 2. 代码控制 InputMethodManager | ||||
|      *    requestFocus | ||||
|      *    showSoftInput:显示键盘 必须先让这个view成为焦点requestFocus | ||||
|      * | ||||
|      *    hideSoftInputFromWindow 隐藏键盘 | ||||
|      */ | ||||
|     @Override | ||||
|     public boolean onTouchEvent(MotionEvent event) { | ||||
|         if (event.getAction() == MotionEvent.ACTION_DOWN){ | ||||
|             //隐藏键盘
 | ||||
|             //1.获取系统输入的管理器
 | ||||
|             InputMethodManager inputManager = | ||||
|                     (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE); | ||||
| 
 | ||||
|             //2.隐藏键盘
 | ||||
|             inputManager.hideSoftInputFromWindow(user.getWindowToken(),0); | ||||
| 
 | ||||
|             //3.取消焦点
 | ||||
|             View focusView = getCurrentFocus(); | ||||
|             if (focusView != null) { | ||||
|                 focusView.clearFocus(); //取消焦点
 | ||||
|             } | ||||
| 
 | ||||
|             //getCurrentFocus().clearFocus();
 | ||||
| 
 | ||||
|             //focusView.requestFocus();//请求焦点
 | ||||
|         } | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void beforeTextChanged(CharSequence s, int start, int count, int after) { | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void onTextChanged(CharSequence s, int start, int before, int count) { | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void afterTextChanged(Editable s) { | ||||
|         //禁止输入中文
 | ||||
|         StringUtils.isNotChinese(s); | ||||
|         //判断两个输入框是否有内容
 | ||||
|         if (user.getEditText().getText().toString().length() > 0 && | ||||
|                 password.getEditText().getText().toString().length() > 0 && | ||||
|                 etCaptcha.getEditText().getText().toString().length() > 0){ | ||||
|             //按钮可以点击
 | ||||
|             loginBtn.setEnabled(true); | ||||
|         }else{ | ||||
|             //按钮不能点击
 | ||||
|             loginBtn.setEnabled(false); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -0,0 +1,261 @@ | ||||
| package xyz.fycz.myreader.ui.activity; | ||||
| 
 | ||||
| import android.app.Activity; | ||||
| import android.content.Intent; | ||||
| import android.content.pm.PackageManager; | ||||
| import android.graphics.Bitmap; | ||||
| import android.graphics.BitmapFactory; | ||||
| import android.os.Bundle; | ||||
| import android.util.Log; | ||||
| import android.view.Menu; | ||||
| import android.view.MenuItem; | ||||
| import android.view.View; | ||||
| import android.view.animation.Animation; | ||||
| import android.view.animation.AnimationUtils; | ||||
| import android.widget.LinearLayout; | ||||
| import android.widget.TextView; | ||||
| 
 | ||||
| import androidx.annotation.NonNull; | ||||
| import androidx.appcompat.widget.Toolbar; | ||||
| import androidx.core.app.ActivityCompat; | ||||
| 
 | ||||
| import com.google.android.material.floatingactionbutton.FloatingActionButton; | ||||
| 
 | ||||
| import java.util.Objects; | ||||
| 
 | ||||
| import butterknife.BindView; | ||||
| import cn.bingoogolapple.qrcode.core.QRCodeView; | ||||
| import cn.bingoogolapple.qrcode.zxing.ZXingView; | ||||
| import io.reactivex.Single; | ||||
| import io.reactivex.SingleOnSubscribe; | ||||
| import xyz.fycz.myreader.R; | ||||
| import xyz.fycz.myreader.base.BaseActivity; | ||||
| import xyz.fycz.myreader.base.observer.MySingleObserver; | ||||
| import xyz.fycz.myreader.util.PermissionsChecker; | ||||
| import xyz.fycz.myreader.util.StringHelper; | ||||
| import xyz.fycz.myreader.util.ToastUtils; | ||||
| import xyz.fycz.myreader.util.utils.RxUtils; | ||||
| 
 | ||||
| import static xyz.fycz.myreader.util.UriFileUtil.getPath; | ||||
| 
 | ||||
| /** | ||||
|  * @author fengyue | ||||
|  * @date 2020/11/30 8:31 | ||||
|  */ | ||||
| 
 | ||||
| public class QRCodeScanActivity extends BaseActivity implements QRCodeView.Delegate { | ||||
| 
 | ||||
|     @BindView(R.id.zxingview) | ||||
|     ZXingView zxingview; | ||||
|     @BindView(R.id.toolbar) | ||||
|     Toolbar toolbar; | ||||
|     @BindView(R.id.ll_flashlight) | ||||
|     LinearLayout llFlashLight; | ||||
|     @BindView(R.id.fab_flashlight) | ||||
|     FloatingActionButton fabFlashlight; | ||||
|     @BindView(R.id.tv_flashlight) | ||||
|     TextView tvFlashlight; | ||||
| 
 | ||||
|     private final int REQUEST_QR_IMAGE = 202; | ||||
|     private static final String CAMERA = "android.permission.CAMERA"; | ||||
|     private static final int PERMISSIONS_REQUEST_CAMERA = 101; | ||||
|     private boolean flashlightIsOpen; | ||||
|     private boolean needScale = true; | ||||
|     private String picPath; | ||||
| 
 | ||||
|     @Override | ||||
|     protected int getContentId() { | ||||
|         return R.layout.activity_qrcode_capture; | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     @Override | ||||
|     protected void setUpToolbar(Toolbar toolbar) { | ||||
|         super.setUpToolbar(toolbar); | ||||
|         setStatusBarColor(R.color.colorPrimary, true); | ||||
|         getSupportActionBar().setTitle("扫一扫"); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 数据初始化 | ||||
|      */ | ||||
|     @Override | ||||
|     protected void initData(Bundle savedInstanceState) { | ||||
|         zxingview.setDelegate(this); | ||||
|         fabFlashlight.setOnClickListener(view -> { | ||||
|             if (flashlightIsOpen) { | ||||
|                 flashlightIsOpen = false; | ||||
|                 zxingview.closeFlashlight(); | ||||
|                 tvFlashlight.setText(getString(R.string.light_contact)); | ||||
|             } else { | ||||
|                 flashlightIsOpen = true; | ||||
|                 zxingview.openFlashlight(); | ||||
|                 tvFlashlight.setText(getString(R.string.close_contact)); | ||||
|             } | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     protected void onStart() { | ||||
|         super.onStart(); | ||||
|         startCamera(); | ||||
|     } | ||||
| 
 | ||||
|     private void startCamera() { | ||||
|         requestPermission(); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     protected void onStop() { | ||||
|         zxingview.stopCamera(); // 关闭摄像头预览,并且隐藏扫描框
 | ||||
|         super.onStop(); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     protected void onDestroy() { | ||||
|         zxingview.onDestroy(); // 销毁二维码扫描控件
 | ||||
|         super.onDestroy(); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void onScanQRCodeSuccess(String result) { | ||||
|         Log.d("onScanQRCodeSuccess", needScale + ""); | ||||
|         if (result == null) { | ||||
|             if (!needScale){ | ||||
|                 needScale = true; | ||||
|                 if (StringHelper.isEmpty(picPath)) { | ||||
|                     return; | ||||
|                 } | ||||
|                 scanFromPath(picPath); | ||||
|             }else { | ||||
|                 ToastUtils.showError("二维码扫描失败"); | ||||
|             } | ||||
|         }else { | ||||
|             Intent intent = new Intent(); | ||||
|             Log.d("result", result); | ||||
|             intent.putExtra("result", result); | ||||
|             setResult(RESULT_OK, intent); | ||||
|             finish(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void onCameraAmbientBrightnessChanged(boolean isDark) { | ||||
|         if (isDark){ | ||||
|             llFlashLight.setVisibility(View.VISIBLE); | ||||
|         }else { | ||||
|             if (!flashlightIsOpen) { | ||||
|                 llFlashLight.setVisibility(View.GONE); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void onScanQRCodeOpenCameraError() { | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     private void startScan() { | ||||
|         zxingview.setVisibility(View.VISIBLE); | ||||
|         zxingview.startSpotAndShowRect(); // 显示扫描框,并开始识别
 | ||||
|     } | ||||
| 
 | ||||
|     private void requestPermission() { | ||||
|         //获取读取和写入SD卡的权限
 | ||||
|         if (new PermissionsChecker(this).lacksPermissions(CAMERA)) { | ||||
|             ActivityCompat.requestPermissions(this, new String[]{CAMERA}, PERMISSIONS_REQUEST_CAMERA); | ||||
|         } else { | ||||
|             startScan(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { | ||||
|         super.onRequestPermissionsResult(requestCode, permissions, grantResults); | ||||
|         switch (requestCode) { | ||||
|             case PERMISSIONS_REQUEST_CAMERA: { | ||||
|                 // 如果取消权限,则返回的值为0
 | ||||
|                 if (grantResults.length > 0 | ||||
|                         && grantResults[0] == PackageManager.PERMISSION_GRANTED) { | ||||
|                     //申请权限成功
 | ||||
|                     startScan(); | ||||
|                 } else { | ||||
|                     //申请权限失败
 | ||||
|                     finish(); | ||||
|                     ToastUtils.showWarring("请给予相机权限,否则无法进行扫码!"); | ||||
|                 } | ||||
|                 return; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     // 添加菜单
 | ||||
|     @Override | ||||
|     public boolean onCreateOptionsMenu(Menu menu) { | ||||
|         getMenuInflater().inflate(R.menu.menu_qr_code_scan, menu); | ||||
|         return super.onCreateOptionsMenu(menu); | ||||
|     } | ||||
| 
 | ||||
|     //菜单
 | ||||
|     @Override | ||||
|     public boolean onOptionsItemSelected(MenuItem item) { | ||||
|         int id = item.getItemId(); | ||||
|         switch (id) { | ||||
|             case R.id.action_choose_from_gallery: | ||||
|                 chooseFromGallery(); | ||||
|                 break; | ||||
|         } | ||||
|         return super.onOptionsItemSelected(item); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     protected void onActivityResult(int requestCode, int resultCode, Intent data) { | ||||
|         super.onActivityResult(requestCode, resultCode, data); | ||||
| 
 | ||||
|         zxingview.startSpotAndShowRect(); // 显示扫描框,并开始识别
 | ||||
| 
 | ||||
|         if (resultCode == Activity.RESULT_OK && requestCode == REQUEST_QR_IMAGE) { | ||||
|             picPath = getPath(this, data.getData()); | ||||
|             if (StringHelper.isEmpty(picPath)) { | ||||
|                 return; | ||||
|             } | ||||
|             scanFromPath(picPath); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private void scanFromPath(String path){ | ||||
|         // 本来就用到 QRCodeView 时可直接调 QRCodeView 的方法,走通用的回调
 | ||||
|         Single.create((SingleOnSubscribe<Bitmap>) emitter -> { | ||||
|             Bitmap bitmap = BitmapFactory.decodeFile(path); | ||||
|             if (bitmap == null) | ||||
|                 return; | ||||
|             if (needScale) { | ||||
|                 int size = 360; | ||||
|                 bitmap = Bitmap.createBitmap(bitmap, bitmap.getWidth() - size, bitmap.getHeight() - size, size, size); | ||||
|             } | ||||
|             emitter.onSuccess(bitmap); | ||||
|         }).compose(RxUtils::toSimpleSingle) | ||||
|                 .subscribe(new MySingleObserver<Bitmap>() { | ||||
|                     @Override | ||||
|                     public void onSuccess(Bitmap bitmap) { | ||||
|                         zxingview.decodeQRCode(bitmap); | ||||
|                     } | ||||
|                 }); | ||||
|     } | ||||
| 
 | ||||
|     private void chooseFromGallery() { | ||||
|         try { | ||||
|             if (needScale){ | ||||
|                 ToastUtils.showInfo("选择图片仅支持扫描书籍分享图片"); | ||||
|             } | ||||
|             Intent intent = new Intent(Intent.ACTION_GET_CONTENT); | ||||
|             intent.addCategory(Intent.CATEGORY_OPENABLE); | ||||
|             intent.setType("image/*"); | ||||
|             startActivityForResult(intent, REQUEST_QR_IMAGE); | ||||
|         } catch (Exception e) { | ||||
|             e.printStackTrace(); | ||||
|             ToastUtils.showError(Objects.requireNonNull(e.getLocalizedMessage())); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -0,0 +1,271 @@ | ||||
| package xyz.fycz.myreader.ui.activity; | ||||
| 
 | ||||
| import android.annotation.SuppressLint; | ||||
| import android.app.ProgressDialog; | ||||
| import android.graphics.Bitmap; | ||||
| import android.os.Handler; | ||||
| import android.os.Message; | ||||
| import android.text.Editable; | ||||
| import android.text.TextWatcher; | ||||
| import android.text.method.LinkMovementMethod; | ||||
| import android.view.View; | ||||
| import android.widget.Button; | ||||
| import android.widget.CheckBox; | ||||
| import android.widget.ImageView; | ||||
| import android.widget.TextView; | ||||
| import androidx.appcompat.widget.Toolbar; | ||||
| import butterknife.BindView; | ||||
| import com.google.android.material.textfield.TextInputLayout; | ||||
| import xyz.fycz.myreader.R; | ||||
| import xyz.fycz.myreader.model.backup.UserService; | ||||
| import xyz.fycz.myreader.base.BaseActivity; | ||||
| import xyz.fycz.myreader.webapi.callback.ResultCallback; | ||||
| import xyz.fycz.myreader.ui.dialog.DialogCreator; | ||||
| import xyz.fycz.myreader.util.CodeUtil; | ||||
| import xyz.fycz.myreader.util.ToastUtils; | ||||
| import xyz.fycz.myreader.util.utils.StringUtils; | ||||
| 
 | ||||
| import java.util.HashMap; | ||||
| import java.util.Map; | ||||
| 
 | ||||
| /** | ||||
|  * @author fengyue | ||||
|  * @date 2020/9/18 22:37 | ||||
|  */ | ||||
| public class RegisterActivity extends BaseActivity { | ||||
|     @BindView(R.id.et_username) | ||||
|     TextInputLayout etUsername; | ||||
|     @BindView(R.id.et_password) | ||||
|     TextInputLayout etPassword; | ||||
|     @BindView(R.id.et_rp_password) | ||||
|     TextInputLayout etRpPassword; | ||||
|     @BindView(R.id.et_captcha) | ||||
|     TextInputLayout etCaptcha; | ||||
|     @BindView(R.id.iv_captcha) | ||||
|     ImageView ivCaptcha; | ||||
|     @BindView(R.id.bt_register) | ||||
|     Button btRegister; | ||||
|     @BindView(R.id.tv_register_tip) | ||||
|     TextView tvRegisterTip; | ||||
|     @BindView(R.id.cb_agreement) | ||||
|     CheckBox cbAgreement; | ||||
|     @BindView(R.id.tv_agreement) | ||||
|     TextView tvAgreement; | ||||
|     private String code; | ||||
|     private String username = ""; | ||||
|     private String password = ""; | ||||
|     private String rpPassword = ""; | ||||
|     private String inputCode = ""; | ||||
| 
 | ||||
|     @SuppressLint("HandlerLeak") | ||||
|     private Handler mHandler = new Handler() { | ||||
|         @SuppressLint("HandlerLeak") | ||||
|         @Override | ||||
|         public void handleMessage(Message msg) { | ||||
|             switch (msg.what) { | ||||
|                 case 1: | ||||
|                     createCaptcha(); | ||||
|                     break; | ||||
|                 case 2: | ||||
|                     showTip((String) msg.obj); | ||||
|                     break; | ||||
|                 case 3: | ||||
|                     tvRegisterTip.setVisibility(View.GONE); | ||||
|                     break; | ||||
|             } | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
| 
 | ||||
|     @Override | ||||
|     protected int getContentId() { | ||||
|         return R.layout.activity_register; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     protected void setUpToolbar(Toolbar toolbar) { | ||||
|         super.setUpToolbar(toolbar); | ||||
|         setStatusBarColor(R.color.colorPrimary, true); | ||||
|         getSupportActionBar().setTitle("注册"); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     protected void initWidget() { | ||||
|         super.initWidget(); | ||||
|         mHandler.sendMessage(mHandler.obtainMessage(1)); | ||||
|         etUsername.requestFocus(); | ||||
|         etUsername.getEditText().addTextChangedListener(new TextWatcher() { | ||||
|             @Override | ||||
|             public void beforeTextChanged(CharSequence s, int start, int count, int after) { | ||||
| 
 | ||||
|             } | ||||
| 
 | ||||
|             @Override | ||||
|             public void onTextChanged(CharSequence s, int start, int before, int count) { | ||||
| 
 | ||||
|             } | ||||
| 
 | ||||
|             @Override | ||||
|             public void afterTextChanged(Editable s) { | ||||
|                 StringUtils.isNotChinese(s); | ||||
|                 username = s.toString(); | ||||
|                 if (username.length() < 6 || username.length() >14){ | ||||
|                     mHandler.sendMessage(mHandler.obtainMessage(2, "用户名必须在6-14位之间")); | ||||
|                 } else if(!username.substring(0, 1).matches("^[A-Za-z]$")){ | ||||
|                     mHandler.sendMessage(mHandler.obtainMessage(2, | ||||
|                             "用户名只能以字母开头")); | ||||
|                 }else if(!username.matches("^[A-Za-z0-9-_]+$")){ | ||||
|                     mHandler.sendMessage(mHandler.obtainMessage(2, | ||||
|                             "用户名只能由数字、字母、下划线、减号组成")); | ||||
|                 }else { | ||||
|                     mHandler.sendMessage(mHandler.obtainMessage(3)); | ||||
|                 } | ||||
|                 checkNotNone(); | ||||
|             } | ||||
|         }); | ||||
| 
 | ||||
|         etPassword.getEditText().addTextChangedListener(new TextWatcher() { | ||||
|             @Override | ||||
|             public void beforeTextChanged(CharSequence s, int start, int count, int after) { | ||||
| 
 | ||||
|             } | ||||
| 
 | ||||
|             @Override | ||||
|             public void onTextChanged(CharSequence s, int start, int before, int count) { | ||||
| 
 | ||||
|             } | ||||
| 
 | ||||
|             @Override | ||||
|             public void afterTextChanged(Editable s) { | ||||
|                 password = s.toString(); | ||||
|                 if (password.length() < 8 || password.length() > 16){ | ||||
|                     mHandler.sendMessage(mHandler.obtainMessage(2, "密码必须在8-16位之间")); | ||||
|                 } else if(password.matches("^\\d+$")){ | ||||
|                     mHandler.sendMessage(mHandler.obtainMessage(2, "密码不能是纯数字")); | ||||
|                 } else { | ||||
|                     mHandler.sendMessage(mHandler.obtainMessage(3)); | ||||
|                 } | ||||
|                 checkNotNone(); | ||||
|             } | ||||
|         }); | ||||
| 
 | ||||
|         etRpPassword.getEditText().addTextChangedListener(new TextWatcher() { | ||||
|             @Override | ||||
|             public void beforeTextChanged(CharSequence s, int start, int count, int after) { | ||||
| 
 | ||||
|             } | ||||
| 
 | ||||
|             @Override | ||||
|             public void onTextChanged(CharSequence s, int start, int before, int count) { | ||||
| 
 | ||||
|             } | ||||
| 
 | ||||
|             @Override | ||||
|             public void afterTextChanged(Editable s) { | ||||
|                 rpPassword = s.toString(); | ||||
|                 if (!rpPassword.equals(password)){ | ||||
|                     mHandler.sendMessage(mHandler.obtainMessage(2, "两次输入的密码不一致")); | ||||
|                 } else { | ||||
|                     mHandler.sendMessage(mHandler.obtainMessage(3)); | ||||
|                 } | ||||
|                 checkNotNone(); | ||||
|             } | ||||
|         }); | ||||
| 
 | ||||
|         etCaptcha.getEditText().addTextChangedListener(new TextWatcher() { | ||||
|             @Override | ||||
|             public void beforeTextChanged(CharSequence s, int start, int count, int after) { | ||||
| 
 | ||||
|             } | ||||
| 
 | ||||
|             @Override | ||||
|             public void onTextChanged(CharSequence s, int start, int before, int count) { | ||||
| 
 | ||||
|             } | ||||
| 
 | ||||
|             @Override | ||||
|             public void afterTextChanged(Editable s) { | ||||
|                 inputCode = s.toString().trim().toLowerCase(); | ||||
|                 if (!inputCode.equals(code.toLowerCase())){ | ||||
|                     mHandler.sendMessage(mHandler.obtainMessage(2, "验证码错误")); | ||||
|                 } else { | ||||
|                     mHandler.sendMessage(mHandler.obtainMessage(3)); | ||||
|                 } | ||||
|                 checkNotNone(); | ||||
|             } | ||||
|         }); | ||||
| 
 | ||||
|         tvAgreement.setMovementMethod(LinkMovementMethod.getInstance()); | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     protected void initClick() { | ||||
|         super.initClick(); | ||||
|         ivCaptcha.setOnClickListener(v -> mHandler.sendMessage(mHandler.obtainMessage(1))); | ||||
| 
 | ||||
|         btRegister.setOnClickListener(v -> { | ||||
|             if (!username.matches("^[A-Za-z][A-Za-z0-9]{5,13}$")){ | ||||
|                 DialogCreator.createTipDialog(this, "用户名格式错误", | ||||
|                         "用户名必须在6-14位之间\n用户名只能以字母开头\n用户名只能由数字、字母、下划线、减号组成"); | ||||
|             }else if(password.matches("^\\d+$") || !password.matches("^.{8,16}$")){ | ||||
|                 DialogCreator.createTipDialog(this, "密码格式错误", | ||||
|                         "密码必须在8-16位之间\n密码不能是纯数字"); | ||||
|             }else if(!password.equals(rpPassword)){ | ||||
|                 DialogCreator.createTipDialog(this, "重复密码错误", | ||||
|                         "两次输入的密码不一致"); | ||||
|             }else if(!inputCode.trim().toLowerCase().equals(code.toLowerCase())){ | ||||
|                 DialogCreator.createTipDialog(this, "验证码错误"); | ||||
|             }else if(!cbAgreement.isChecked()){ | ||||
|                 DialogCreator.createTipDialog(this, "请勾选同意《用户服务协议》"); | ||||
|             }else { | ||||
|                 ProgressDialog dialog = DialogCreator.createProgressDialog(this, null, "正在注册..."); | ||||
|                 Map<String, String> userRegisterInfo = new HashMap<>(); | ||||
|                 userRegisterInfo.put("username", username); | ||||
|                 userRegisterInfo.put("password", password); | ||||
|                 UserService.register(userRegisterInfo, new ResultCallback() { | ||||
|                     @Override | ||||
|                     public void onFinish(Object o, int code) { | ||||
|                         String[] info = ((String) o).split(":"); | ||||
|                         int result = Integer.parseInt(info[0].trim()); | ||||
|                         if (result == 101){ | ||||
|                             UserService.writeUsername(username); | ||||
|                             ToastUtils.showSuccess(info[1]); | ||||
|                             finish(); | ||||
|                         }else { | ||||
|                             ToastUtils.showWarring(info[1]); | ||||
|                         } | ||||
|                         dialog.dismiss(); | ||||
|                     } | ||||
|                     @Override | ||||
|                     public void onError(Exception e) { | ||||
|                         ToastUtils.showError("注册失败:\n" + e.getLocalizedMessage()); | ||||
|                         dialog.dismiss(); | ||||
|                     } | ||||
|                 }); | ||||
|             } | ||||
|             mHandler.sendMessage(mHandler.obtainMessage(1)); | ||||
|         }); | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     public void createCaptcha() { | ||||
|         code = CodeUtil.getInstance().createCode(); | ||||
|         Bitmap codeBitmap = CodeUtil.getInstance().createBitmap(code); | ||||
|         ivCaptcha.setImageBitmap(codeBitmap); | ||||
|     } | ||||
| 
 | ||||
|     public void showTip(String tip) { | ||||
|         tvRegisterTip.setVisibility(View.VISIBLE); | ||||
|         tvRegisterTip.setText(tip); | ||||
|     } | ||||
| 
 | ||||
|     public void checkNotNone(){ | ||||
|         if ("".equals(username) || "".equals(password) || "".equals(rpPassword) || "".equals(inputCode)){ | ||||
|             btRegister.setEnabled(false); | ||||
|         }else { | ||||
|             btRegister.setEnabled(true); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -0,0 +1,86 @@ | ||||
| package xyz.fycz.myreader.ui.popmenu; | ||||
| 
 | ||||
| import android.content.Context; | ||||
| import android.util.AttributeSet; | ||||
| import android.view.LayoutInflater; | ||||
| import android.view.View; | ||||
| import android.widget.FrameLayout; | ||||
| import android.widget.SeekBar; | ||||
| import android.widget.TextView; | ||||
| 
 | ||||
| import androidx.annotation.NonNull; | ||||
| import androidx.annotation.Nullable; | ||||
| 
 | ||||
| import butterknife.BindView; | ||||
| import butterknife.ButterKnife; | ||||
| import xyz.fycz.myreader.R; | ||||
| import xyz.fycz.myreader.application.SysManager; | ||||
| import xyz.fycz.myreader.entity.Setting; | ||||
| 
 | ||||
| public class AutoPageMenu extends FrameLayout { | ||||
| 
 | ||||
|     @BindView(R.id.tv_auto_scroll_speed) | ||||
|     TextView tvAutoPageSpeed; | ||||
|     @BindView(R.id.sb_auto_scroll_progress) | ||||
|     SeekBar sbAutoPageSpeed; | ||||
|     @BindView(R.id.tv_exit_auto_page) | ||||
|     TextView tvExitAutoPage; | ||||
|     @BindView(R.id.vwNavigationBar) | ||||
|     View vwNavigationBar; | ||||
| 
 | ||||
|     public AutoPageMenu(@NonNull Context context) { | ||||
|         super(context); | ||||
|         init(context); | ||||
|     } | ||||
| 
 | ||||
|     public AutoPageMenu(@NonNull Context context, @Nullable AttributeSet attrs) { | ||||
|         super(context, attrs); | ||||
|         init(context); | ||||
|     } | ||||
| 
 | ||||
|     public AutoPageMenu(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) { | ||||
|         super(context, attrs, defStyleAttr); | ||||
|         init(context); | ||||
|     } | ||||
| 
 | ||||
|     private void init(Context context) { | ||||
|         View view = LayoutInflater.from(context).inflate(R.layout.menu_auto_page, this); | ||||
|         ButterKnife.bind(this, view); | ||||
|     } | ||||
| 
 | ||||
|     public void setListener(Callback callback) { | ||||
|         Setting setting = SysManager.getSetting(); | ||||
|         sbAutoPageSpeed.setProgress(110 - setting.getAutoScrollSpeed()); | ||||
|         tvAutoPageSpeed.setText(String.format("翻页速度:%s %%", 110 - setting.getAutoScrollSpeed())); | ||||
|         sbAutoPageSpeed.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { | ||||
|             @Override | ||||
|             public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { | ||||
|                 tvAutoPageSpeed.setText(String.format("翻页速度:%s %%", progress)); | ||||
|             } | ||||
| 
 | ||||
|             @Override | ||||
|             public void onStartTrackingTouch(SeekBar seekBar) { | ||||
| 
 | ||||
|             } | ||||
| 
 | ||||
|             @Override | ||||
|             public void onStopTrackingTouch(SeekBar seekBar) { | ||||
|                 int progress = seekBar.getProgress(); | ||||
|                 int speed = 110 - progress; | ||||
|                 setting.setAutoScrollSpeed(speed); | ||||
|                 SysManager.saveSetting(setting); | ||||
|                 callback.onSpeedChange(); | ||||
|             } | ||||
|         }); | ||||
|         tvExitAutoPage.setOnClickListener(v -> callback.onExitClick()); | ||||
|     } | ||||
| 
 | ||||
|     public void setNavigationBarHeight(int height) { | ||||
|         vwNavigationBar.getLayoutParams().height = height; | ||||
|     } | ||||
| 
 | ||||
|     public interface Callback{ | ||||
|         void onSpeedChange(); | ||||
|         void onExitClick(); | ||||
|     } | ||||
| } | ||||