├── App.vue ├── android ├── assets │ ├── logo.png │ └── splash.png └── com │ └── itstudy │ └── io │ ├── GetComicContent.java │ ├── GetComicList.java │ ├── GetDirectoryList.java │ ├── GetExtSDCardPathList.java │ ├── GetFileList.java │ └── GetText.java ├── assets └── js │ ├── config.js │ ├── gb2312.js │ ├── html-parse.js │ ├── index.js │ └── util.js ├── changelog.md ├── common ├── mixin │ ├── app.js │ ├── book.js │ ├── bookcertify.js │ ├── cache.js │ ├── index.js │ ├── lyric.js │ ├── music.js │ └── musiccertify.js └── online │ ├── getBook.js │ ├── getComic.js │ └── getMusic.js ├── components ├── bubble-item │ └── bubble-item.nvue ├── bubble │ └── bubble.nvue ├── c-button │ └── c-button.nvue ├── c-icon │ └── c-icon.nvue ├── c-image │ └── c-image.nvue ├── c-switch │ └── c-switch.nvue ├── comic-image │ └── comic-image.nvue ├── crosswise │ └── crosswise.nvue ├── fileList │ └── fileList.nvue ├── fixed-button │ └── fixed-button.nvue ├── gap-bar │ └── gap-bar.nvue ├── list-scroll │ └── list-scroll.nvue ├── loading │ └── loading.nvue ├── music-btn │ └── music-btn.nvue ├── music-icon │ └── music-icon.nvue ├── music-lyric │ └── music-lyric.nvue ├── nav-bar │ └── nav-bar.nvue ├── no-data │ └── no-data.nvue ├── progress │ └── progress.nvue └── search │ └── search.nvue ├── js_sdk └── mmmm-image-tools │ └── index.js ├── main.js ├── manifest.json ├── modules ├── actionSheet.nvue ├── catalog.nvue ├── confirm.nvue ├── edit.nvue └── security.nvue ├── nativeplugins └── YingBingNativePlugin │ ├── android │ └── uniplugin_yingbing-release.aar │ └── package.json ├── package.json ├── pages.json ├── pages ├── about │ └── index.nvue ├── book │ ├── detail │ │ └── index.nvue │ ├── online │ │ └── index.nvue │ ├── read │ │ └── index.vue │ ├── search │ │ └── index.nvue │ └── setting │ │ └── index.nvue ├── comic │ ├── detail │ │ └── index.nvue │ ├── online │ │ └── index.nvue │ ├── read │ │ └── index.nvue │ ├── search │ │ └── index.nvue │ └── setting │ │ └── index.nvue ├── index │ └── index.nvue ├── menu │ └── menu.nvue ├── music │ ├── index.nvue │ ├── online.nvue │ ├── player.nvue │ └── search.nvue └── setting │ └── index.nvue ├── plugins ├── dom │ └── index.js ├── index.js ├── request │ ├── index.js │ └── request.js ├── router │ ├── index.js │ └── router.js └── xhr │ ├── index.js │ └── xhr.js ├── readme.md ├── static ├── cover │ ├── cover_1.png │ ├── cover_2.png │ ├── cover_3.png │ ├── cover_4.png │ ├── cover_5.png │ ├── cover_6.png │ └── cover_default.jpg ├── menuBack.png ├── music │ ├── border-default.png │ ├── border-night.png │ ├── loop.png │ ├── music-bg.jpg │ ├── music-icon.png │ ├── music-list.png │ ├── music-type.png │ ├── next.png │ ├── once.png │ ├── pause.png │ ├── play.png │ ├── prev.png │ └── random.png └── no-data.png ├── store ├── config.js ├── index.js └── modules │ ├── app.js │ ├── book.js │ ├── bookcertify.js │ ├── cache.js │ ├── music.js │ ├── musiccertify.js │ └── skin.js └── uni_modules └── yingbing-ReadPage ├── changelog.md ├── components ├── computed-page │ └── computed-page.vue ├── flip-page │ └── flip-page.vue ├── page-no-chapter │ └── page-no-chapter.vue ├── page-refresh │ └── page-refresh.vue ├── scroll-page │ ├── scroll-page - 副本.vue │ └── scroll-page.vue └── yingbing-ReadPage │ └── yingbing-ReadPage.vue ├── node_modules └── @better-scroll │ ├── core │ ├── LICENSE │ ├── README.md │ ├── README_zh-CN.md │ ├── dist │ │ ├── core.esm.js │ │ ├── core.js │ │ ├── core.min.js │ │ └── types │ │ │ ├── BScroll.d.ts │ │ │ ├── Instance.d.ts │ │ │ ├── Options.d.ts │ │ │ ├── animater │ │ │ ├── Animation.d.ts │ │ │ ├── Base.d.ts │ │ │ ├── Transition.d.ts │ │ │ └── index.d.ts │ │ │ ├── base │ │ │ └── ActionsHandler.d.ts │ │ │ ├── index.d.ts │ │ │ ├── scroller │ │ │ ├── Actions.d.ts │ │ │ ├── Behavior.d.ts │ │ │ ├── DirectionLock.d.ts │ │ │ ├── Scroller.d.ts │ │ │ └── createOptions.d.ts │ │ │ ├── translater │ │ │ └── index.d.ts │ │ │ └── utils │ │ │ ├── bubbling.d.ts │ │ │ ├── compare.d.ts │ │ │ ├── compat.d.ts │ │ │ └── typesHelper.d.ts │ ├── package.json │ └── src │ │ ├── BScroll.ts │ │ ├── Instance.ts │ │ ├── Options.ts │ │ ├── __mocks__ │ │ ├── Options.ts │ │ └── index.ts │ │ ├── __tests__ │ │ ├── Options.spec.ts │ │ ├── __utils__ │ │ │ ├── event.ts │ │ │ └── layout.ts │ │ └── index.spec.ts │ │ ├── animater │ │ ├── Animation.ts │ │ ├── Base.ts │ │ ├── Transition.ts │ │ ├── __mocks__ │ │ │ ├── Animation.ts │ │ │ ├── Transition.ts │ │ │ └── index.ts │ │ ├── __tests__ │ │ │ ├── Animation.spec.ts │ │ │ ├── Transition.spec.ts │ │ │ └── index.spec.ts │ │ └── index.ts │ │ ├── base │ │ ├── ActionsHandler.ts │ │ ├── __mocks__ │ │ │ └── ActionsHandler.ts │ │ └── __tests__ │ │ │ └── ActionsHandler.spec.ts │ │ ├── index.ts │ │ ├── scroller │ │ ├── Actions.ts │ │ ├── Behavior.ts │ │ ├── DirectionLock.ts │ │ ├── Scroller.ts │ │ ├── __mocks__ │ │ │ ├── Actions.ts │ │ │ ├── Behavior.ts │ │ │ ├── DirectionLock.ts │ │ │ └── Scroller.ts │ │ ├── __tests__ │ │ │ ├── Actions.spec.ts │ │ │ ├── Behavior.spec.ts │ │ │ ├── DirectionLock.spec.ts │ │ │ ├── Scroller.spec.ts │ │ │ └── createOptions.spec.ts │ │ └── createOptions.ts │ │ ├── translater │ │ ├── __mocks__ │ │ │ └── index.ts │ │ ├── __tests__ │ │ │ └── index.spec.ts │ │ └── index.ts │ │ └── utils │ │ ├── __tests__ │ │ └── bubbling.spec.ts │ │ ├── bubbling.ts │ │ ├── compare.ts │ │ ├── compat.ts │ │ └── typesHelper.ts │ ├── pull-down │ ├── LICENSE │ ├── README.md │ ├── README_zh-CN.md │ ├── dist │ │ ├── pull-down.esm.js │ │ ├── pull-down.js │ │ ├── pull-down.min.js │ │ └── types │ │ │ ├── index.d.ts │ │ │ └── propertiesConfig.d.ts │ ├── package.json │ └── src │ │ ├── __tests__ │ │ └── index.spec.ts │ │ ├── index.ts │ │ └── propertiesConfig.ts │ └── pull-up │ ├── LICENSE │ ├── README.md │ ├── README_zh-CN.md │ ├── dist │ ├── pull-up.esm.js │ ├── pull-up.js │ ├── pull-up.min.js │ └── types │ │ ├── index.d.ts │ │ └── propertiesConfig.d.ts │ ├── package.json │ └── src │ ├── __tests__ │ └── index.spec.ts │ ├── index.ts │ └── propertiesConfig.ts ├── package.json └── readme.md /App.vue: -------------------------------------------------------------------------------- 1 | 32 | 33 | 87 | -------------------------------------------------------------------------------- /android/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yingbing-developer/uni-reader/1b767e77869a344d01401fa41175a70facde4d89/android/assets/logo.png -------------------------------------------------------------------------------- /android/assets/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yingbing-developer/uni-reader/1b767e77869a344d01401fa41175a70facde4d89/android/assets/splash.png -------------------------------------------------------------------------------- /android/com/itstudy/io/GetDirectoryList.java: -------------------------------------------------------------------------------- 1 | package com.itstudy.io; 2 | 3 | 4 | import org.json.JSONArray; 5 | import org.json.JSONException; 6 | import org.json.JSONObject; 7 | 8 | import java.io.File; 9 | import java.io.IOException; 10 | import java.text.SimpleDateFormat; 11 | 12 | /** 13 | * @Title: FileList 14 | * @author: 康雷 e-mail: 1014295211@qq.com 15 | * @date: 2020/9/22 16:51 16 | * @ClassName: GetDirectoryList 17 | * @Description: 获取指定路径下的文件夹列表 18 | */ 19 | public class GetDirectoryList { 20 | 21 | 22 | public String getDirectories(String path) throws IOException, JSONException { 23 | File file = new File(path); 24 | File[] files = file.listFiles(); 25 | JSONArray folderJsonArray = new JSONArray(); 26 | for (File value : files) { 27 | if ( !value.isHidden() ) { 28 | JSONObject jsonObject = new JSONObject(); 29 | if (value.isDirectory()) { 30 | jsonObject.put("name", value.getName()); 31 | jsonObject.put("path", value.getPath()); 32 | jsonObject.put("type", "folder"); 33 | jsonObject.put("size", "0B"); 34 | jsonObject.put("time", this.getFileTime(value)); 35 | jsonObject.put("createTime",value.lastModified()); 36 | folderJsonArray.put(jsonObject); 37 | } 38 | } 39 | } 40 | return folderJsonArray.toString(); 41 | } 42 | 43 | private String getFileTime(File file) { 44 | SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm"); 45 | return formatter.format(file.lastModified()); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /android/com/itstudy/io/GetExtSDCardPathList.java: -------------------------------------------------------------------------------- 1 | package com.itstudy.io; 2 | 3 | 4 | import android.os.Build; 5 | import android.os.Environment; 6 | import android.os.UserHandle; 7 | import android.support.annotation.RequiresApi; 8 | 9 | import org.json.JSONArray; 10 | import org.json.JSONException; 11 | import org.json.JSONObject; 12 | 13 | import java.io.File; 14 | import java.io.IOException; 15 | import java.lang.reflect.Constructor; 16 | import java.lang.reflect.Method; 17 | 18 | /** 19 | * @Title: FileList 20 | * @author: 康雷 e-mail: 1014295211@qq.com 21 | * @date: 2020/9/22 16:51 22 | * @ClassName: GetExtSDCardPathList 23 | * @Description: 获取扩展TF卡路径 24 | */ 25 | public class GetExtSDCardPathList { 26 | 27 | 28 | @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) 29 | public static String getSDPath() throws IOException, JSONException{ 30 | JSONArray paths = new JSONArray(); 31 | try { 32 | //===========================获取UserEnvironment================ 33 | Class userEnvironment = Class.forName("android.os.Environment$UserEnvironment"); 34 | Method getExternalDirs =userEnvironment.getDeclaredMethod("getExternalDirs"); 35 | getExternalDirs.setAccessible(true); 36 | //========获取构造UserEnvironment的必要参数UserId================ 37 | Class userHandle = Class.forName("android.os.UserHandle"); 38 | Method myUserId = userHandle.getDeclaredMethod("myUserId"); 39 | myUserId.setAccessible(true); 40 | int mUserId = (int) myUserId.invoke(UserHandle.class); 41 | Constructor declaredConstructor = userEnvironment.getDeclaredConstructor(Integer.TYPE); 42 | // 得到UserEnvironment instance 43 | Object instance = declaredConstructor.newInstance(mUserId); 44 | File[] files = (File[]) getExternalDirs.invoke(instance); 45 | for (int i = 0; i < files.length; i++) { 46 | if (Environment.isExternalStorageRemovable(files[i])){ 47 | JSONObject jsonObject = new JSONObject(); 48 | jsonObject.put("path", files[i].getPath()); 49 | paths.put(jsonObject); 50 | } 51 | } 52 | } catch (Exception e) { 53 | 54 | } 55 | return paths.toString(); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /android/com/itstudy/io/GetText.java: -------------------------------------------------------------------------------- 1 | package com.itstudy.io; 2 | 3 | import java.io.*; 4 | 5 | /** 6 | * @Title: TestTranslate 7 | * @author: 何杰 e-mail: 734412450@qq.com 8 | * @date: 2020/8/26 16:45 9 | * @ClassName: GetText 10 | * @Description: 获取txt文本内容 11 | */ 12 | public class GetText { 13 | 14 | 15 | 16 | //判断编码格式方法 17 | private static String getFileCharset(File sourceFile) { 18 | String charset = "GBK"; 19 | byte[] first3Bytes = new byte[3]; 20 | try { 21 | boolean checked = false; 22 | BufferedInputStream bis = new BufferedInputStream(new FileInputStream(sourceFile)); 23 | bis.mark(0); 24 | int read = bis.read(first3Bytes, 0, 3); 25 | //文件编码为 ANSI 26 | if (read == -1) { 27 | return charset; 28 | } else if (first3Bytes[0] == (byte) 0xFF 29 | && first3Bytes[1] == (byte) 0xFE) { 30 | //文件编码为 Unicode 31 | charset = "UTF-16LE"; 32 | checked = true; 33 | } else if (first3Bytes[0] == (byte) 0xFE 34 | && first3Bytes[1] == (byte) 0xFF) { 35 | //文件编码为 Unicode big endian 36 | charset = "UTF-16BE"; 37 | checked = true; 38 | } else if (first3Bytes[0] == (byte) 0xEF 39 | && first3Bytes[1] == (byte) 0xBB 40 | && first3Bytes[2] == (byte) 0xBF) { 41 | //文件编码为 UTF-8 42 | charset = "UTF-8"; 43 | checked = true; 44 | } 45 | bis.reset(); 46 | if (!checked) { 47 | int loc = 0; 48 | while ((read = bis.read()) != -1) { 49 | loc++; 50 | if (read >= 0xF0) { 51 | break; 52 | } 53 | // 单独出现BF以下的,也算是GBK 54 | if (0x80 <= read && read <= 0xBF) { 55 | break; 56 | } 57 | if (0xC0 <= read && read <= 0xDF) { 58 | read = bis.read(); 59 | // 双字节 (0xC0 - 0xDF) 60 | if (0x80 <= read && read <= 0xBF) 61 | // (0x80 62 | // - 0xBF),也可能在GB编码内 63 | { 64 | continue; 65 | } else { 66 | break; 67 | } 68 | // 也有可能出错,但是几率较小 69 | } else if (0xE0 <= read && read <= 0xEF) { 70 | read = bis.read(); 71 | if (0x80 <= read && read <= 0xBF) { 72 | read = bis.read(); 73 | if (0x80 <= read && read <= 0xBF) { 74 | charset = "UTF-8"; 75 | break; 76 | } else{ 77 | break;} 78 | } else { 79 | break; 80 | } 81 | } 82 | } 83 | } 84 | bis.close(); 85 | } catch (Exception e) { 86 | e.printStackTrace(); 87 | } 88 | return charset; 89 | } 90 | 91 | public String getTextFromText(String filePath) { 92 | 93 | try { 94 | // 获取输入流 95 | InputStreamReader isr = new InputStreamReader(new FileInputStream(filePath), getFileCharset(new File(filePath))); 96 | BufferedReader br = new BufferedReader(isr); 97 | 98 | StringBuffer sb = new StringBuffer(); 99 | String temp = null; 100 | while ((temp = br.readLine()) != null) { 101 | sb.append(temp+"\r\n"); 102 | } 103 | br.close(); 104 | return sb.toString(); 105 | } catch (FileNotFoundException e) { 106 | // TODO Auto-generated catch block 107 | e.printStackTrace(); 108 | 109 | } catch (IOException e) { 110 | // TODO Auto-generated catch block 111 | e.printStackTrace(); 112 | } 113 | return null; 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /assets/js/config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | //小说网站链接 3 | BOOKURL: { 4 | 'baoshuu': { 5 | title: '手机宝书', 6 | href: 'http://m.baoshuu.com' 7 | } 8 | }, 9 | 10 | //漫画网站链接 11 | COMICURL: { 12 | 'mangabz': { 13 | title: 'mangaBz', 14 | href: 'http://www.mangabz.com' 15 | }, 16 | 'sixmh': { 17 | title: '6漫画', 18 | href: 'http://m.sixmh7.com' 19 | }, 20 | 'dmzj': { 21 | title: '动漫之家', 22 | href: 'https://www.dmzj.com' 23 | } 24 | }, 25 | //音乐网站链接 26 | MUSICURL: { 27 | 'qqmusic': { 28 | title: 'QQ音乐', 29 | href: 'https://c.y.qq.com' 30 | }, 31 | '163music': { 32 | title: '网易云音乐', 33 | href: 'https://autumnfish.cn' 34 | } 35 | }, 36 | 37 | //青壮年内容 38 | ADULTS: [], 39 | 40 | //QQ音乐请求常量 41 | commonParams: { 42 | g_tk: 5381, 43 | loginUin: 0, 44 | hostUin: 0, 45 | format: 'json', 46 | inCharset: 'utf8', 47 | outCharset: 'utf-8', 48 | notice: 0, 49 | platform: 'yqq.json', 50 | needNewCode: 0 51 | }, 52 | 53 | 54 | //请求成功编码 55 | ERR_OK: 200, 56 | //请求失败编码 57 | ERR_FALSE: 300, 58 | //请求超时时间 59 | TIMEOUT: 50000 60 | } 61 | -------------------------------------------------------------------------------- /assets/js/index.js: -------------------------------------------------------------------------------- 1 | import Vue from "vue"; 2 | import Utils from './util.js'; 3 | import Config from './config.js'; 4 | 5 | Vue.prototype.$utils = Utils; 6 | Vue.prototype.$config = Config; -------------------------------------------------------------------------------- /changelog.md: -------------------------------------------------------------------------------- 1 | ## 2.9.8.5(2021-10-19) 2 | * 更新阅读插件 3 | * 修复显示一些图片app会卡死的问题 4 | * 优化部分图片缓存问题 5 | ## 2.9.8.4(2021-10-14) 6 | * 新增小说接口 7 | * 添加青少年模式 8 | * 接入最新版阅读插件 9 | * 添加在线小说阅读页面进度条显示 10 | ## 2.9.8.3(2021-09-22) 11 | * 修复阅读在线小说有时部分页面不显示的bug 12 | * 修复在线小说阅读新章节时会继承上次阅读章节的阅读位置的bug 13 | * 更改音乐播放全局控件样式,更改播放列表样式 14 | ## 2.9.8.2(2021-09-17) 15 | * 修复某个漫画接口不能显示图片的问题 16 | * 修改了在线小说内容获取方式 17 | * 修改了在线漫画内容获取方式 18 | * 删除了一个漫画接口 19 | ## 2.9.81(2021-09-08) 20 | * 修复了漫画阅读页面不能切换章节的问题 21 | * 现在将获取本地小说文本内容的原生方法封装成了插件,同时获取文件列表的方法也使用native.js方法获取,如果你不需要阅读本地漫画,就可以直接云打包 22 | ## 2.9.8(2021-09-06) 23 | * 修复阅读本地小说到最后会从开始重新排版的bug 24 | * 修复阅读小说设置窗口可能打不开的bug 25 | ## 2.9.7(2021-09-04) 26 | * 新增在线小说接口 27 | * 修复部分在线漫画接口 28 | * 优化了代码格式 29 | * 优化了文件结构 30 | ## 2.9.6(2021-08-28) 31 | * 更新了失效的音乐搜索接口 32 | * 将文件搜索列表独立成组件 33 | * 更新了获取漫画内容的方式 34 | * 更新小说分页组件,现在被独立成一个插件,大家可以去看看我新发布的分页插件[小说阅读分页插件](https://ext.dcloud.net.cn/plugin?id=6026) 35 | ## 2.9.5(2021-06-14) 36 | * 新增小说编辑功能,非常适合发现有错别字并且有强迫症的人 37 | * 一些组件添加了点击交互效果 38 | * 本地小说搜索页替换了新的获取文件的方法,不再调用原生方法,但还有某些问题,想要使用原生方法的可以使用同文件夹下的副本页面 39 | ## 2.9.4(2021-04-06) 40 | * 1、新增一个在线音乐接口 41 | * 2、修复和优化问题若干 42 | ## 2.9.3(2021-03-23) 43 | * 1、新增音乐播放界面 44 | * 2、新增歌词显示功能 45 | * 3、新增全局歌词显示功能 46 | * 4、修改了播放列表样式 47 | * ps(需要注意此次更新修改了音乐数据的格式,所以打包apk安装之前,请将原本保存的歌曲先清空掉,避免出现bug) 48 | ## 2.9.0(2021-03-18) 49 | * 1、新增2个获取在线漫画的来源 50 | * 2、新增获取在线音乐的接口 51 | * 3、设置页面新增控制在线音乐和在线漫画来源的按钮 52 | * 4、修复若干bug 53 | ## 2.8.4(2021-02-27) 54 | * 1、修复一些显示bug 55 | * 2、优化漫画图片尺寸问题 56 | * 3、优化一些漫画阅读细节问题 57 | ## 2.8.2(2021-02-21) 58 | * 1、修改漫画阅读页图片尺寸不对的问题 59 | * 2、修复获取在线漫画内容开头闪屏的问题 60 | * 3、修复在线漫画搜索页搜索框清空内容会触发搜索事件的问题 61 | * 4、修复在线漫画会出现已读完的问题 62 | ## 2.8.0(2021-02-20) 63 | * 1、新增一个添加在线漫画的接口 64 | * 2、新增一个漫画详情页面 65 | * 3、新增一个获取漫画详情信息的接口 66 | * 4、新增一个html页面用于获取漫画内容 67 | ## 2.7.5(2021-01-05) 68 | * 1、优化翻页方式切换逻辑 69 | * 2、将弹出确认框做成全局方法,并优化样式 70 | * 3、将弹出选择框做成全局方法,并优化样式 71 | ## 2.7.0(2020-12-26) 72 | * 1、小说阅读方式新增 【伪·仿真翻页】【覆盖翻页】(ps: 因为只能横向翻页,所以叫伪·仿真翻页) 73 | * 2、修复首页书籍之间间隔不一样的问题 74 | * 3、修复音乐列表名称过长没有隐藏的问题 75 | * 4、优化路由跳转代码,将路由跳转的代码写在公共方法中 76 | ## 2.6.1(2020-11-24) 77 | * 优化长列表,减少白屏时间 78 | * 不知道是不是错觉,总感觉优化后变卡了,哪位测试过麻烦告诉我一下 79 | ## 2.6.0(2020-11-23) 80 | * 新增文件分享功能,可以在添加小说,音乐,漫画页面分享文件 81 | * ps(只支持单文件分享) 82 | ## 2.5.1(2020-11-20) 83 | * 优化音乐控件的触摸事件,解决点击和拖动的冲突 84 | ## 2.5.0(2020-11-19) 85 | * 新增音乐播放功能,只支持应用内播放 86 | ## 2.1.0(2020-11-16) 87 | * 1、修改原生方法,新增生成缩略图的方法,现在读取漫画列表时,会在每本漫画一级文件夹下生成一张叫做 “000_preview.jpg” 的图片,是由漫画第一张图片压缩成的,这样做是为了减少手机内存负担 88 | * 2、新增获取扩展内存卡的方法,但不适配所有手机 89 | ## 2.0.5(2020-11-13) 90 | * 1、新增读取漫画内容和漫画列表的原生方法,提升了读取漫画内容的速度 91 | * 2、修复了添加小说页面直接阅读小说,进度显示NaN的bug 92 | * 3、删除了漫画阅读页面夜间模式下亮度会降低的设置 93 | * 4、修复了旋转屏幕后,图片高度异常的bug 94 | ## 2.0.0(2020-11-12) 95 | * 1、新增阅读本地漫画的功能 96 | * ps: 漫画资源结构有2种,分别为: 97 | - 1、漫画文件夹 => 漫画图片 98 | - 2、漫画文件夹 => 章节文件夹 => 漫画图片; 99 | - 3、如果漫画文件夹下同时存在图片和文件夹,以文件夹优先,会忽略图片。 100 | * 2、更改了关于页面内容 101 | * 3、更改了原生方法,如果要打包的朋友,注意替换原生方法 102 | * 4、与读取小说内容一样,读取漫画内容也分调试用的方法和正式打包使用的方法,都是注释好了的,根据情况选择使用 103 | ## 1.2.5(2020-11-02) 104 | * 1、优化了列表组件和导航栏组件的代码,去除了不必要的传参 105 | * 2、修复了阅读页文本有时右边会超出一部分的bug 106 | * 3、修改了首页书籍列表展示布局 107 | * 4、修复了阅读页拖动进度条到100%时,无法点击回上一页的bug 108 | ## 1.2.0(2020-10-21) 109 | * 1、新增滑动阅读功能分为上下滑动和左右滑动同时保留点击翻页 110 | * 2、开放设置界面,用于设置阅读方式和动画时间 111 | * 3、此版本几乎重构了整个阅读页,如果要打包安装的朋友请将原本的版本数据清空 112 | ## 1.1.0(2020-10-12) 113 | * 1、将阅读页面设置窗口改为原生子窗体,现在设置窗口的滑入和滑出动画更加流畅 114 | * 2、修复访问文件夹时滚动条位置不变的bug 115 | * 3、修复进度条拖动bug 116 | ## 1.0.2(2020-10-09) 117 | * 1、修复了首页和本地文件页面,不能搜索的bug 118 | * 2、本地文件页面也能直接读取txt文件内容 119 | * 3、稍微优化了下自定义列表组件的代码 120 | * 4、除了原生的弹框,其余自定义组件的弹窗都适配了夜间模式 121 | * 5、优化了删除提示,删除单个文件时,会提示文件名称,避免删错文件 122 | ## 1.0.0(2020-09-29) 123 | * 主要功能: 124 | * 1、首页显示本地导入的小说列表(显示信息包括(阅读进度、导入时间,小说名称)) 125 | * 2、可拖曳的抽屉菜单(效果不是很好) 126 | * 3、搜索本地txt文件列表 127 | * 4、导入本地txt文档 128 | * 5、删除txt文件 129 | * 6、小说左右分页阅读(只有左右分页且没有动画效果) 130 | * 7、可以跳转进度阅读小说 131 | * 8、查看小说章节,如果小说的章节格式符合规格的话 132 | * 9、保存书签,显示书签列表 133 | -------------------------------------------------------------------------------- /common/mixin/app.js: -------------------------------------------------------------------------------- 1 | import { mapGetters, mapMutations } from 'vuex' 2 | const appMixin = { 3 | computed: { 4 | ...mapGetters({ 5 | getAdult: 'app/getAdult', 6 | getAdultPwd: 'app/getAdultPwd' 7 | }) 8 | }, 9 | methods: { 10 | ...mapMutations({ 11 | setAdult: 'app/setAdult', 12 | setAdultPwd: 'app/setAdultPwd' 13 | }) 14 | } 15 | } 16 | 17 | export default appMixin; -------------------------------------------------------------------------------- /common/mixin/book.js: -------------------------------------------------------------------------------- 1 | import { mapGetters, mapMutations } from 'vuex' 2 | const bookMixin = { 3 | computed: { 4 | ...mapGetters({ 5 | bookList: 'book/bookList', 6 | bookmarks: 'book/bookmarks', 7 | bookPathHistory: 'book/bookPathHistory', 8 | bookReadMode: 'book/bookReadMode', 9 | getBookSourcesController: 'book/getBookSourcesController', 10 | comicPathHistory: 'book/comicPathHistory', 11 | comicOrienMode: 'book/comicOrienMode', 12 | getComicSourcesController: 'book/getComicSourcesController', 13 | }) 14 | }, 15 | methods: { 16 | ...mapMutations({ 17 | addBooks: 'book/addBooks', 18 | deleteBook: 'book/deleteBook', 19 | clearBooks: 'book/clearBooks', 20 | updateBookInfo: 'book/updateBookInfo', 21 | updateBookPath: 'book/updateBookPath', 22 | changeBookFontSize: 'book/changeBookFontSize', 23 | changeBookReadPageType: 'book/changeBookReadPageType', 24 | changeBookReadLineHeight: 'book/changeBookReadLineHeight', 25 | changeBookLight: 'book/changeBookLight', 26 | saveBookmark: 'book/saveBookmark', 27 | clearBookmark: 'book/clearBookmark', 28 | setBookSourcesController: 'book/setBookSourcesController', 29 | setComicSourcesController: 'book/setComicSourcesController', 30 | updateComicPath: 'book/updateComicPath', 31 | clearComicPath: 'book/clearComicPath', 32 | changeComicOrien: 'book/changeComicOrien', 33 | setComicSourcesController: 'book/setComicSourcesController' 34 | }) 35 | } 36 | } 37 | 38 | export default bookMixin; -------------------------------------------------------------------------------- /common/mixin/bookcertify.js: -------------------------------------------------------------------------------- 1 | import { mapGetters, mapMutations } from 'vuex' 2 | const bookcertifyMixin = { 3 | computed: { 4 | ...mapGetters({ 5 | bookInfo: 'bookcertify/getBookInfo', 6 | bookChapters: 'bookcertify/getBookChapters', 7 | pageInfo: 'bookcertify/getBookPageInfo' 8 | }) 9 | }, 10 | methods: { 11 | ...mapMutations({ 12 | setBookInfo: 'bookcertify/setBookInfo', 13 | setBookChapters: 'bookcertify/setBookChapters', 14 | setBookPageInfo: 'bookcertify/setBookPageInfo' 15 | }) 16 | } 17 | } 18 | 19 | export default bookcertifyMixin; -------------------------------------------------------------------------------- /common/mixin/cache.js: -------------------------------------------------------------------------------- 1 | import { mapGetters, mapMutations } from 'vuex' 2 | const cacheMixin = { 3 | computed: { 4 | ...mapGetters({ 5 | imageCache: 'cache/getImageCache' 6 | }) 7 | }, 8 | methods: { 9 | ...mapMutations({ 10 | addImageCache: 'cache/addImageCache', 11 | removeImageCache: 'cache/removeImageCache', 12 | clearImageCache: 'cache/clearImageCache' 13 | }) 14 | } 15 | } 16 | 17 | export default cacheMixin; -------------------------------------------------------------------------------- /common/mixin/index.js: -------------------------------------------------------------------------------- 1 | import { mapGetters, mapMutations } from 'vuex' 2 | export const skinMixin = { 3 | computed: { 4 | ...mapGetters({ 5 | skinMode: 'skin/skinMode', 6 | skinColor: 'skin/skinColor' 7 | }) 8 | }, 9 | methods: { 10 | ...mapMutations({ 11 | changeSkin: 'skin/changeSkin', 12 | }) 13 | } 14 | } 15 | 16 | //菜单拖曳显示 17 | export const menuTouchMixin = { 18 | data () { 19 | return { 20 | pointX: 0, 21 | touchTime: 0, 22 | menuLate: 0, 23 | menuOpac: 0, 24 | //控制列表是否滚动 25 | scrollable: true 26 | } 27 | }, 28 | methods: { 29 | touchstart (e) { 30 | if ( e.touches.length > 1 ) { 31 | return; 32 | } 33 | const touch = e.touches[0]; 34 | this.pointX = touch.pageX; 35 | this.scrollable = false; 36 | this.$refs.leftMenu.open(); 37 | this.timer = setInterval(() => { 38 | this.touchTime += 0.1; 39 | }, 100) 40 | }, 41 | touchmove (e) { 42 | if ( this.touchTime < 0.3 ) { 43 | return; 44 | } 45 | const touch = e.touches[0]; 46 | this.menuLate = this.$refs.leftMenu.mulriple * (touch.pageX - this.pointX); 47 | this.menuOpac = this.menuLate / Math.abs(this.$refs.leftMenu.anima.late) * this.$refs.leftMenu.anima.opac; 48 | }, 49 | touchend (e) { 50 | if ( this.timer ) { 51 | clearInterval(this.timer); 52 | } 53 | if ( this.$refs.leftMenu.popuplate >= -240 || (this.touchTime <= 0.3 && this.$refs.leftMenu.popuplate > -540) ) { 54 | this.$refs.leftMenu.show(); 55 | } else { 56 | this.$refs.leftMenu.hide(); 57 | setTimeout(() => { 58 | this.menuLate = -30; 59 | }, this.$refs.leftMenu.anima.duration) 60 | } 61 | this.$nextTick(() => { 62 | this.pointX = 0; 63 | this.touchTime = 0; 64 | this.scrollable = true; 65 | }) 66 | } 67 | } 68 | } -------------------------------------------------------------------------------- /common/mixin/lyric.js: -------------------------------------------------------------------------------- 1 | import musicMixin from '@/common/mixin/music.js' 2 | import musiccertifyMixin from '@/common/mixin/musiccertify.js' 3 | const lyricMixin = { 4 | mixins: [musicMixin, musiccertifyMixin], 5 | computed: { 6 | //播放记录 7 | playRecord () { 8 | return this.getMusicPlayRecord; 9 | }, 10 | //已播放时长 11 | playTime () { 12 | return this.getMusicPlayTime; 13 | }, 14 | playLyric () { 15 | return this.getMusicLyric; 16 | }, 17 | //是否显示歌词 18 | lyricShow () { 19 | return this.getMusicLyricShow; 20 | }, 21 | //当前歌词字符串 22 | lyricNowTitle () { 23 | return this.playLyric.length > 0 && this.lyricNowIndex > -1 ? this.playLyric[this.lyricNowIndex].title : this.musicInfo ? this.musicInfo.name : '暂无歌曲'; 24 | }, 25 | //当前歌词位置索引 26 | lyricNowIndex () { 27 | let len = this.playLyric.length; 28 | let nowLyricTime = 0; 29 | let prevLyricTime = 0; 30 | let nextLyricTime = 0; 31 | for ( let i = 0; i < len; i++ ) { 32 | nowLyricTime = this.playLyric[i].time; 33 | switch(i) { 34 | case 0: 35 | nextLyricTime = this.playLyric[i + 1].time; 36 | if ( this.playTime < nextLyricTime && this.playTime >= nowLyricTime ) return i; 37 | break; 38 | case this.playLyric.length - 1: 39 | prevLyricTime = this.playLyric[i - 1].time; 40 | if ( this.playTime > prevLyricTime && this.playTime >= nowLyricTime ) return i; 41 | break; 42 | default: 43 | prevLyricTime = this.playLyric[i - 1].time; 44 | nextLyricTime = this.playLyric[i + 1].time; 45 | if ( this.playTime > prevLyricTime && this.playTime < nextLyricTime && this.playTime >= nowLyricTime ) return i; 46 | } 47 | } 48 | return -1; 49 | } 50 | } 51 | } 52 | export default lyricMixin; -------------------------------------------------------------------------------- /common/mixin/music.js: -------------------------------------------------------------------------------- 1 | import { mapGetters, mapMutations } from 'vuex' 2 | const musicMixin = { 3 | computed: { 4 | ...mapGetters({ 5 | playList: 'music/playList', 6 | musicPathHistory: 'music/musicPathHistory', 7 | getMusicPlayMode: 'music/getMusicPlayMode', 8 | getMusicPlayRecord: 'music/getMusicPlayRecord', 9 | getMusicLyricShow: 'music/getMusicLyricShow', 10 | getMusicSourcesController: 'music/getMusicSourcesController' 11 | }) 12 | }, 13 | methods: { 14 | ...mapMutations({ 15 | addMusic: 'music/addMusic', 16 | deleteMusic: 'music/deleteMusic', 17 | clearMusic: 'music/clearMusic', 18 | updateMusicPlayRecord: 'music/updateMusicPlayRecord', 19 | changeMusicPlayMode: 'music/changeMusicPlayMode', 20 | setMusicLyricShow: 'music/setMusicLyricShow', 21 | updateMusicPath: 'music/updateMusicPath', 22 | setMusicSourcesController: 'music/setMusicSourcesController' 23 | }) 24 | } 25 | } 26 | 27 | export default musicMixin; -------------------------------------------------------------------------------- /common/mixin/musiccertify.js: -------------------------------------------------------------------------------- 1 | import { mapGetters, mapMutations } from 'vuex' 2 | const musiccertifyMixin = { 3 | computed: { 4 | ...mapGetters({ 5 | musicInfo: 'musiccertify/getMusicInfo', 6 | getMusicPlayStatus: 'musiccertify/getMusicPlayStatus', 7 | getMusicPlayTime: 'musiccertify/getMusicPlayTime', 8 | getMusicPlayDuration: 'musiccertify/getMusicPlayDuration', 9 | getMusicLyric: 'musiccertify/getMusicLyric' 10 | }) 11 | }, 12 | methods: { 13 | ...mapMutations({ 14 | setMusicInfo: 'musiccertify/setMusicInfo', 15 | setMusicPlayStatus: 'musiccertify/setMusicPlayStatus', 16 | setMusicPlayTime: 'musiccertify/setMusicPlayTime', 17 | setMusicPlayDuration: 'musiccertify/setMusicPlayDuration', 18 | setMusicLyric: 'musiccertify/setMusicLyric' 19 | }) 20 | } 21 | } 22 | 23 | export default musiccertifyMixin; -------------------------------------------------------------------------------- /components/bubble-item/bubble-item.nvue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 24 | 25 | 36 | -------------------------------------------------------------------------------- /components/bubble/bubble.nvue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 91 | 92 | 124 | -------------------------------------------------------------------------------- /components/c-button/c-button.nvue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 68 | 69 | 103 | -------------------------------------------------------------------------------- /components/c-switch/c-switch.nvue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 69 | 70 | 99 | -------------------------------------------------------------------------------- /components/comic-image/comic-image.nvue: -------------------------------------------------------------------------------- 1 | 25 | 26 | 87 | 88 | 98 | -------------------------------------------------------------------------------- /components/crosswise/crosswise.nvue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 52 | 53 | 62 | -------------------------------------------------------------------------------- /components/fixed-button/fixed-button.nvue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 70 | 71 | 84 | -------------------------------------------------------------------------------- /components/gap-bar/gap-bar.nvue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 27 | 28 | 31 | -------------------------------------------------------------------------------- /components/list-scroll/list-scroll.nvue: -------------------------------------------------------------------------------- 1 | 26 | 27 | 176 | 177 | 186 | -------------------------------------------------------------------------------- /components/loading/loading.nvue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 54 | 55 | 58 | -------------------------------------------------------------------------------- /components/music-lyric/music-lyric.nvue: -------------------------------------------------------------------------------- 1 | 2 | 3 | 59 | 60 | 62 | -------------------------------------------------------------------------------- /components/nav-bar/nav-bar.nvue: -------------------------------------------------------------------------------- 1 | 23 | 24 | 78 | 79 | 135 | -------------------------------------------------------------------------------- /components/no-data/no-data.nvue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 22 | 23 | 42 | -------------------------------------------------------------------------------- /components/search/search.nvue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 58 | 59 | 90 | -------------------------------------------------------------------------------- /main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import App from './App' 3 | import store from './store'//引入vuex 4 | import '@/plugins' 5 | import '@/assets/js' 6 | 7 | Vue.config.productionTip = false 8 | 9 | App.mpType = 'app' 10 | 11 | const app = new Vue({ 12 | ...App, 13 | store 14 | }) 15 | app.$mount() 16 | -------------------------------------------------------------------------------- /modules/actionSheet.nvue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 110 | 111 | 153 | -------------------------------------------------------------------------------- /modules/confirm.nvue: -------------------------------------------------------------------------------- 1 | 23 | 24 | 108 | 109 | 179 | -------------------------------------------------------------------------------- /modules/edit.nvue: -------------------------------------------------------------------------------- 1 |