diff --git a/app/src/main/assets/updatelog.fy b/app/src/main/assets/updatelog.fy index 4a2ceaa..814173f 100644 --- a/app/src/main/assets/updatelog.fy +++ b/app/src/main/assets/updatelog.fy @@ -1,3 +1,8 @@ +2021.06.14 +风月读书v2.1.3 +更新内容: +1、优化阅读文字选择 + 2021.06.13 风月读书v2.1.2 更新内容: diff --git a/app/src/main/java/xyz/fycz/myreader/common/APPCONST.java b/app/src/main/java/xyz/fycz/myreader/common/APPCONST.java index 1df4798..6401ab7 100644 --- a/app/src/main/java/xyz/fycz/myreader/common/APPCONST.java +++ b/app/src/main/java/xyz/fycz/myreader/common/APPCONST.java @@ -22,18 +22,17 @@ import javax.script.ScriptEngineManager; public class APPCONST { public static String publicKey = "";//服务端公钥 - public static String privateKey;//app私钥 public static final String KEY = ""; public static final String[] STORAGE_PERMISSIONS = new String[]{Permission.WRITE_EXTERNAL_STORAGE, Permission.READ_EXTERNAL_STORAGE}; - public static final String FILE_DIR = Environment.getExternalStorageDirectory() + "/FYReader/"; - public static final String SHARE_FILE_DIR = Environment.getExternalStorageDirectory() + "/FYReader/share/"; - public static String LOG_DIR = FileUtils.getCachePath() + "/log/"; - public static String COVER_DIR = FileUtils.getCachePath() + "/covers/"; - public static final String BG_FILE_DIR = Environment.getExternalStorageDirectory() + "/FYReader/bg/"; - public static String TEM_FILE_DIR = FileUtils.getCachePath() + "/tem/"; + public static final String FILE_DIR = Environment.getExternalStorageDirectory() + "/FYReader/"; + public static final String SHARE_FILE_DIR = Environment.getExternalStorageDirectory() + "/FYReader/share/"; + public static String LOG_DIR = FileUtils.getCachePath() + "/log/"; + public static String COVER_DIR = FileUtils.getCachePath() + "/covers/"; + public static final String BG_FILE_DIR = Environment.getExternalStorageDirectory() + "/FYReader/bg/"; + public static String TEM_FILE_DIR = FileUtils.getCachePath() + "/tem/"; public static final String BACKUP_FILE_DIR = Environment.getExternalStorageDirectory() + "/FYReader/backup/"; public static final String TXT_BOOK_DIR = Environment.getExternalStorageDirectory() + "/FYReader/noveltxt/"; public static final String FONT_BOOK_DIR = Environment.getExternalStorageDirectory() + "/FYReader/font/"; @@ -41,9 +40,9 @@ public class APPCONST { public static final String QQ_DATA_DIR = Environment.getExternalStorageDirectory() + "/tencent/MobileQQ/data/"; //BookCachePath (因为getCachePath引用了Context,所以必须是静态变量,不能够是静态常量) public static String BOOK_CACHE_PATH = FileUtils.getCachePath() + File.separator - + "book_cache"+ File.separator ; + + "book_cache" + File.separator; public static String HTML_CACHE_PATH = FileUtils.getCachePath() + File.separator - + "html_cache"+ File.separator ; + + "html_cache" + File.separator; public static long exitTime; public static final int exitConfirmTime = 2000; @@ -120,6 +119,7 @@ public class APPCONST { public static final Pattern JS_PATTERN = Pattern.compile("([\\w\\W]*?|@js:[\\w\\W]*$)", Pattern.CASE_INSENSITIVE); public static final Pattern EXP_PATTERN = Pattern.compile("\\{\\{([\\w\\W]*?)\\}\\}"); +// public static final Pattern IMG_PATTERN = Pattern.compile("", Pattern.CASE_INSENSITIVE); public static final ScriptEngine SCRIPT_ENGINE = new ScriptEngineManager().getEngineByName("rhino"); diff --git a/app/src/main/java/xyz/fycz/myreader/ui/activity/ReadActivity.java b/app/src/main/java/xyz/fycz/myreader/ui/activity/ReadActivity.java index 2b362e4..e46e2a5 100644 --- a/app/src/main/java/xyz/fycz/myreader/ui/activity/ReadActivity.java +++ b/app/src/main/java/xyz/fycz/myreader/ui/activity/ReadActivity.java @@ -28,6 +28,7 @@ import android.view.WindowManager; import android.view.animation.Animation; import android.view.animation.AnimationUtils; import android.widget.FrameLayout; +import android.widget.ImageView; import android.widget.SeekBar; import androidx.annotation.NonNull; @@ -111,6 +112,7 @@ import xyz.fycz.myreader.widget.BubblePopupView; import xyz.fycz.myreader.widget.page.PageLoader; import xyz.fycz.myreader.widget.page.PageMode; import xyz.fycz.myreader.widget.page.PageView; +import xyz.fycz.myreader.widget.page.TxtChar; import static android.view.View.GONE; import static android.view.View.VISIBLE; @@ -1741,6 +1743,9 @@ public class ReadActivity extends BaseActivity implements ColorPickerDialogListe longPressMenu.hidePopupListWindow(); break; case MotionEvent.ACTION_MOVE: + ImageView left = binding.getRoot().findViewWithTag("left"); + ImageView right = binding.getRoot().findViewWithTag("right"); + int dx = (int) event.getRawX() - lastX; int dy = (int) event.getRawY() - lastY; int l = v.getLeft() + dx; @@ -1759,17 +1764,52 @@ public class ReadActivity extends BaseActivity implements ColorPickerDialogListe int hh = binding.cursorLeft.getHeight(); int ww = binding.cursorLeft.getWidth(); - if (v.getId() == R.id.cursor_left) { - binding.readPvContent.setFirstSelectTxtChar(binding.readPvContent.getCurrentTxtChar(lastX + ww, lastY - hh)); - if (binding.readPvContent.getFirstSelectTxtChar() != null) { - binding.cursorLeft.setX(binding.readPvContent.getFirstSelectTxtChar().getTopLeftPosition().x - ww); - binding.cursorLeft.setY(binding.readPvContent.getFirstSelectTxtChar().getBottomLeftPosition().y); + if (v.getId() == left.getId()) { + TxtChar first = binding.readPvContent.getCurrentTxtChar(lastX + ww, lastY - hh, true); + if (first != null) { + binding.readPvContent.setFirstSelectTxtChar(first); } + left.setX(binding.readPvContent.getFirstSelectTxtChar().getBottomLeftPosition().x - ww); + left.setY(binding.readPvContent.getFirstSelectTxtChar().getBottomLeftPosition().y); } else { - binding.readPvContent.setLastSelectTxtChar(binding.readPvContent.getCurrentTxtChar(lastX - ww, lastY - hh)); - if (binding.readPvContent.getLastSelectTxtChar() != null) { - binding.cursorRight.setX(binding.readPvContent.getLastSelectTxtChar().getBottomRightPosition().x); - binding.cursorRight.setY(binding.readPvContent.getLastSelectTxtChar().getBottomRightPosition().y); + TxtChar last = binding.readPvContent.getCurrentTxtChar(lastX - ww, lastY - hh, false); + if (last != null) { + binding.readPvContent.setLastSelectTxtChar(last); + } + right.setX(binding.readPvContent.getLastSelectTxtChar().getBottomRightPosition().x); + right.setY(binding.readPvContent.getLastSelectTxtChar().getBottomRightPosition().y); + } + + + float leftX = left.getX(); + float leftY = left.getY(); + float rightX = right.getX(); + float rightY = right.getY(); + + if ((leftY == rightY && leftX > rightX) || leftY > rightY) { + left.setTag("right"); + left.setImageDrawable(ContextCompat.getDrawable(this, R.drawable.ic_cursor_right)); + right.setTag("left"); + right.setImageDrawable(ContextCompat.getDrawable(this, R.drawable.ic_cursor_left)); + + if (v.getId() == left.getId()) { + TxtChar last = binding.readPvContent.getLastSelectTxtChar(); + last = binding.readPvContent.getNextTxtChar(last); + binding.readPvContent.setFirstSelectTxtChar(last); + if (last != null) { + right.setX(last.getBottomLeftPosition().x - ww); + right.setY(last.getBottomLeftPosition().y); + } else { + return true; + } + } else { + TxtChar first = binding.readPvContent.getFirstSelectTxtChar(); + first = binding.readPvContent.getLastTxtChar(first); + binding.readPvContent.setLastSelectTxtChar(first); + if (first != null) { + left.setX(first.getBottomRightPosition().x); + left.setY(first.getBottomRightPosition().y); + } } } @@ -1826,15 +1866,17 @@ public class ReadActivity extends BaseActivity implements ColorPickerDialogListe * 显示选择 */ private void cursorShow() { - binding.cursorLeft.setVisibility(View.VISIBLE); - binding.cursorRight.setVisibility(View.VISIBLE); + ImageView left = binding.getRoot().findViewWithTag("left"); + ImageView right = binding.getRoot().findViewWithTag("right"); + left.setVisibility(View.VISIBLE); + right.setVisibility(View.VISIBLE); int hh = binding.cursorLeft.getHeight(); int ww = binding.cursorLeft.getWidth(); if (binding.readPvContent.getFirstSelectTxtChar() != null) { - binding.cursorLeft.setX(binding.readPvContent.getFirstSelectTxtChar().getTopLeftPosition().x - ww); - binding.cursorLeft.setY(binding.readPvContent.getFirstSelectTxtChar().getBottomLeftPosition().y); - binding.cursorRight.setX(binding.readPvContent.getFirstSelectTxtChar().getBottomRightPosition().x); - binding.cursorRight.setY(binding.readPvContent.getFirstSelectTxtChar().getBottomRightPosition().y); + left.setX(binding.readPvContent.getFirstSelectTxtChar().getTopLeftPosition().x - ww); + left.setY(binding.readPvContent.getFirstSelectTxtChar().getBottomLeftPosition().y); + right.setX(binding.readPvContent.getFirstSelectTxtChar().getBottomRightPosition().x); + right.setY(binding.readPvContent.getFirstSelectTxtChar().getBottomRightPosition().y); } } diff --git a/app/src/main/java/xyz/fycz/myreader/widget/page/EpubPageLoader.java b/app/src/main/java/xyz/fycz/myreader/widget/page/EpubPageLoader.java index de01364..e191663 100644 --- a/app/src/main/java/xyz/fycz/myreader/widget/page/EpubPageLoader.java +++ b/app/src/main/java/xyz/fycz/myreader/widget/page/EpubPageLoader.java @@ -53,6 +53,7 @@ public class EpubPageLoader extends PageLoader { EpubPageLoader(PageView pageView, xyz.fycz.myreader.greendao.entity.Book bookShelfBean, Setting setting) { super(pageView, bookShelfBean, setting); + mStatus = STATUS_PARING; } @Override @@ -91,13 +92,17 @@ public class EpubPageLoader extends PageLoader { @Override public void onNext(xyz.fycz.myreader.greendao.entity.Book bookShelfBean) { isChapterListPrepare = true; + //提示目录加载完成 + if (mPageChangeListener != null) { + mPageChangeListener.onCategoryFinish(mChapterList); + } // 加载并显示当前章节 openChapter(); } @Override public void onError(Throwable e) { - error(STATUS_CATEGORY_ERROR, e.getMessage()); + error(STATUS_PARSE_ERROR, e.getMessage()); } }); } @@ -249,9 +254,8 @@ public class EpubPageLoader extends PageLoader { } private Observable checkChapterList(xyz.fycz.myreader.greendao.entity.Book collBook) { - if (mCollBook.getChapterTotalNum() != 0) { - mChapterList = ChapterService.getInstance().findBookAllChapterByBookId(mCollBook.getId()); - mPageChangeListener.onCategoryFinish(mChapterList); + mChapterList = ChapterService.getInstance().findBookAllChapterByBookId(mCollBook.getId()); + if (!mChapterList.isEmpty()) { return Observable.just(collBook); } else { return Observable.create((ObservableOnSubscribe>) e -> { diff --git a/app/src/main/java/xyz/fycz/myreader/widget/page/LocalPageLoader.java b/app/src/main/java/xyz/fycz/myreader/widget/page/LocalPageLoader.java index b95b2e2..2279cf4 100644 --- a/app/src/main/java/xyz/fycz/myreader/widget/page/LocalPageLoader.java +++ b/app/src/main/java/xyz/fycz/myreader/widget/page/LocalPageLoader.java @@ -69,15 +69,15 @@ public class LocalPageLoader extends PageLoader { // 对于文件是否存在,或者为空的判断,不作处理。 ==> 在文件打开前处理过了。 mBookFile = new File(mCollBook.getChapterUrl()); if (!mBookFile.exists()) { - error(STATUS_CATEGORY_ERROR, "书籍源文件不存在\n" + mCollBook.getChapterUrl()); + error(STATUS_PARSE_ERROR, "书籍源文件不存在\n" + mCollBook.getChapterUrl()); return; } mCharset = mCollBook.getInfoUrl(); // 判断文件是否已经加载过,并具有缓存 - if (mCollBook.getChapterTotalNum() != 0) { + mChapterList = mChapterService.findBookAllChapterByBookId(mCollBook.getId()); + if (!mChapterList.isEmpty()) { - mChapterList = mChapterService.findBookAllChapterByBookId(mCollBook.getId()); isChapterListPrepare = true; //提示目录加载完成 diff --git a/app/src/main/java/xyz/fycz/myreader/widget/page/PageLoader.java b/app/src/main/java/xyz/fycz/myreader/widget/page/PageLoader.java index 5611a0d..377cdf9 100644 --- a/app/src/main/java/xyz/fycz/myreader/widget/page/PageLoader.java +++ b/app/src/main/java/xyz/fycz/myreader/widget/page/PageLoader.java @@ -32,13 +32,11 @@ import xyz.fycz.myreader.model.audio.ReadAloudService; import xyz.fycz.myreader.util.IOUtils; import xyz.fycz.myreader.util.ToastUtils; import xyz.fycz.myreader.util.help.ChapterContentHelp; -import xyz.fycz.myreader.util.help.StringHelper; import xyz.fycz.myreader.util.utils.BitmapUtil; import xyz.fycz.myreader.util.utils.MeUtils; import xyz.fycz.myreader.util.utils.RxUtils; import xyz.fycz.myreader.util.utils.ScreenUtils; import xyz.fycz.myreader.util.utils.StringUtils; -import xyz.fycz.myreader.widget.page2.TxtLine; import java.io.BufferedReader; import java.io.File; @@ -46,6 +44,7 @@ import java.io.IOException; import java.text.DecimalFormat; import java.util.ArrayList; import java.util.List; +import java.util.Objects; /** * Created by fengyue on 20-11-21 @@ -785,7 +784,7 @@ public abstract class PageLoader { error(STATUS_ERROR, msg); } - public void error(int status, String msg){ + public void error(int status, String msg) { //加载错误 mStatus = status; errorMsg = msg; @@ -1044,10 +1043,10 @@ public abstract class PageLoader { tip = "章节内容为空"; break; case STATUS_PARING: - tip = "正在拆分章节请等待..."; + tip = "正在解析文件请等待..."; break; case STATUS_PARSE_ERROR: - tip = "文件解析错误"; + tip = "文件解析错误\n" + errorMsg; break; case STATUS_CATEGORY_EMPTY: tip = "目录列表为空"; @@ -1056,7 +1055,8 @@ public abstract class PageLoader { tip = "目录加载失败\n" + errorMsg; break; } - if (mStatus == STATUS_ERROR || mStatus == STATUS_CATEGORY_ERROR) { + if (mStatus == STATUS_ERROR || mStatus == STATUS_CATEGORY_ERROR + || mStatus == STATUS_PARSE_ERROR) { drawErrorMsg(canvas, tip, 0); } else { //将提示语句放到正中间 @@ -2061,6 +2061,10 @@ public abstract class PageLoader { } } + enum Detect { + None, Left, Right + } + /** * -------------------- * 检测获取按压坐标所在位置的字符,没有的话返回null @@ -2068,7 +2072,7 @@ public abstract class PageLoader { * author: huangwei * 2017年7月4日上午10:23:19 */ - TxtChar detectPressTxtChar(float down_X2, float down_Y2) { + TxtChar detectPressTxtChar(float down_X2, float down_Y2, Detect detect) { TxtPage txtPage = mCurPage; if (txtPage == null) return null; List txtLines = txtPage.txtLists; @@ -2076,14 +2080,24 @@ public abstract class PageLoader { for (TxtLine l : txtLines) { List txtChars = l.getCharsData(); if (txtChars != null) { - for (TxtChar c : txtChars) { + for (int i = 0; i < txtChars.size(); i++) { + TxtChar c = txtChars.get(i); Point leftPoint = c.getBottomLeftPosition(); Point rightPoint = c.getBottomRightPosition(); if (leftPoint != null && down_Y2 > leftPoint.y) { break;// 说明是在下一行 } - if (leftPoint != null && rightPoint != null && down_X2 >= leftPoint.x && down_X2 <= rightPoint.x) { - return c; + if (leftPoint != null && rightPoint != null) { + boolean flag = down_X2 >= leftPoint.x && down_X2 <= rightPoint.x; + switch (detect) { + case Left: + flag = flag || (i == 0 && down_X2 < leftPoint.x); + break; + case Right: + flag = flag || (i == txtChars.size() - 1 && down_X2 > rightPoint.x); + break; + } + if (flag) return c; } } @@ -2092,6 +2106,42 @@ public abstract class PageLoader { return null; } + TxtChar detectLastTxtChar(TxtChar txtChar) { + TxtChar last = txtChar; + TxtPage txtPage = mCurPage; + if (txtPage == null) return txtChar; + List txtLines = txtPage.txtLists; + if (txtLines == null) return txtChar; + for (TxtLine l : txtLines) { + List txtChars = l.getCharsData(); + if (txtChars != null) { + for (TxtChar c : txtChars) { + if (c != null && c.getIndex() == txtChar.getIndex()) return last; + last = c; + } + } + } + return txtChar; + } + + TxtChar detectNextTxtChar(TxtChar txtChar) { + TxtPage txtPage = mCurPage; + boolean isNext = false; + if (txtPage == null) return txtChar; + List txtLines = txtPage.txtLists; + if (txtLines == null) return txtChar; + for (TxtLine l : txtLines) { + List txtChars = l.getCharsData(); + if (txtChars != null) { + for (TxtChar c : txtChars) { + if (isNext) return c; + if (c != null && c.getIndex() == txtChar.getIndex()) isNext = true; + } + } + } + return txtChar; + } + public boolean isPrev() { return isPrev; } diff --git a/app/src/main/java/xyz/fycz/myreader/widget/page/PageView.java b/app/src/main/java/xyz/fycz/myreader/widget/page/PageView.java index 4e70e1a..48a0bbb 100644 --- a/app/src/main/java/xyz/fycz/myreader/widget/page/PageView.java +++ b/app/src/main/java/xyz/fycz/myreader/widget/page/PageView.java @@ -26,7 +26,6 @@ import xyz.fycz.myreader.util.utils.FileUtils; import xyz.fycz.myreader.util.utils.SnackbarUtils; import xyz.fycz.myreader.webapi.crawler.base.ReadCrawler; import xyz.fycz.myreader.widget.animation.*; -import xyz.fycz.myreader.widget.page2.TxtLine; /** * Created by Administrator on 2016/8/29 0029. @@ -125,7 +124,7 @@ public class PageView extends View { performLongClick(); if (mStartX > 0 && mStartY > 0) {// 说明还没释放,是长按事件 isLongPress = true;//长按 - TxtChar p = mPageLoader.detectPressTxtChar(mStartX, mStartY);//找到长按的点 + TxtChar p = mPageLoader.detectPressTxtChar(mStartX, mStartY, PageLoader.Detect.None);//找到长按的点 firstSelectTxtChar = p;//设置开始位置字符 lastSelectTxtChar = p;//设置结束位置字符 selectMode = SelectMode.PressSelectText;//设置模式为长按选择 @@ -628,8 +627,16 @@ public class PageView extends View { } //根据当前坐标返回文字 - public TxtChar getCurrentTxtChar(float x, float y) { - return mPageLoader.detectPressTxtChar(x, y); + public TxtChar getCurrentTxtChar(float x, float y, boolean left) { + return mPageLoader.detectPressTxtChar(x, y, left ? PageLoader.Detect.Left : PageLoader.Detect.Right); + } + + public TxtChar getLastTxtChar(TxtChar txtChar){ + return mPageLoader.detectLastTxtChar(txtChar); + } + + public TxtChar getNextTxtChar(TxtChar txtChar){ + return mPageLoader.detectNextTxtChar(txtChar); } private void drawOaleSeletLinesBg(Canvas canvas) {// 绘制选中背景 diff --git a/app/src/main/java/xyz/fycz/myreader/widget/page/TxtLine.kt b/app/src/main/java/xyz/fycz/myreader/widget/page/TxtLine.kt index 9667781..d7694c0 100644 --- a/app/src/main/java/xyz/fycz/myreader/widget/page/TxtLine.kt +++ b/app/src/main/java/xyz/fycz/myreader/widget/page/TxtLine.kt @@ -1,6 +1,4 @@ -package xyz.fycz.myreader.widget.page2 - -import xyz.fycz.myreader.widget.page.TxtChar +package xyz.fycz.myreader.widget.page class TxtLine { diff --git a/app/src/main/java/xyz/fycz/myreader/widget/page/TxtPage.java b/app/src/main/java/xyz/fycz/myreader/widget/page/TxtPage.java index 630a418..02e9b7f 100644 --- a/app/src/main/java/xyz/fycz/myreader/widget/page/TxtPage.java +++ b/app/src/main/java/xyz/fycz/myreader/widget/page/TxtPage.java @@ -2,8 +2,6 @@ package xyz.fycz.myreader.widget.page; import java.util.List; -import xyz.fycz.myreader.widget.page2.TxtLine; - public class TxtPage { int position; String title; diff --git a/app/src/main/res/layout/activity_read.xml b/app/src/main/res/layout/activity_read.xml index ed184f7..8982090 100644 --- a/app/src/main/res/layout/activity_read.xml +++ b/app/src/main/res/layout/activity_read.xml @@ -82,6 +82,7 @@ + xmlns:app="http://schemas.android.com/apk/res-auto" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:background="@color/colorBackground" + android:orientation="vertical"> + android:layout_width="match_parent" + android:layout_height="wrap_content"> + + layout="@layout/toolbar" /> + + android:id="@+id/iv_refresh_search" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_alignParentEnd="true" + android:layout_centerInParent="true" + android:padding="8dp" + android:background="?android:attr/selectableItemBackground" + app:srcCompat="@drawable/ic_refresh" /> + + android:id="@+id/iv_stop_search" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_centerInParent="true" + android:background="?android:attr/selectableItemBackground" + android:layout_toStartOf="@+id/iv_refresh_search" + android:padding="8dp" + app:srcCompat="@drawable/ic_stop_black_24dp" /> + android:id="@+id/rpb" + android:layout_width="match_parent" + android:layout_height="3dp" + android:visibility="visible" />