├── .gitignore ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── codingbingo │ │ └── fastreader │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── codingbingo │ │ │ └── fastreader │ │ │ ├── Constants.java │ │ │ ├── FRApplication.java │ │ │ ├── base │ │ │ ├── BaseActivity.java │ │ │ ├── BaseFragment.java │ │ │ ├── utils │ │ │ │ └── BaseUtils.java │ │ │ └── view │ │ │ │ └── BaseReadView.java │ │ │ ├── dao │ │ │ ├── Book.java │ │ │ ├── BookDao.java │ │ │ ├── Chapter.java │ │ │ ├── ChapterDao.java │ │ │ ├── DaoMaster.java │ │ │ └── DaoSession.java │ │ │ ├── jni │ │ │ └── FileProcessing.java │ │ │ ├── manager │ │ │ └── SettingManager.java │ │ │ ├── model │ │ │ ├── LocalFile.java │ │ │ └── eventbus │ │ │ │ ├── BookReadProgressChangeEvent.java │ │ │ │ ├── BookStatusChangeEvent.java │ │ │ │ ├── RefreshBookListEvent.java │ │ │ │ └── StyleChangeEvent.java │ │ │ ├── ui │ │ │ ├── activity │ │ │ │ ├── LocalFileListActivity.java │ │ │ │ ├── MainActivity.java │ │ │ │ └── ReadingActivity.java │ │ │ ├── adapter │ │ │ │ ├── BookListAdapter.java │ │ │ │ ├── ChapterListAdapter.java │ │ │ │ ├── FileListAdapter.java │ │ │ │ └── ReadingBackgroundAdapter.java │ │ │ ├── fragment │ │ │ │ ├── ChapterListFragment.java │ │ │ │ ├── MainControllerBottomSheetFragment.java │ │ │ │ └── ReadingFragment.java │ │ │ └── listener │ │ │ │ ├── OnChapterClickListener.java │ │ │ │ └── OnReadChapterProgressListener.java │ │ │ ├── utils │ │ │ ├── BrightnessUtils.java │ │ │ ├── CommonUtils.java │ │ │ ├── FileUtils.java │ │ │ ├── LogUtils.java │ │ │ ├── ScreenUtils.java │ │ │ ├── SharedPreferenceUtils.java │ │ │ ├── SimpleDividerItemDecoration.java │ │ │ ├── StringUtils.java │ │ │ ├── ThreadPool.java │ │ │ └── encode │ │ │ │ ├── BytesEncodingDetect.java │ │ │ │ └── Encoding.java │ │ │ └── view │ │ │ ├── BookNestedScrollView.java │ │ │ ├── LoadingDialog.java │ │ │ ├── SwitchableSeekBar.java │ │ │ ├── loadingview │ │ │ ├── CatLoadingView.java │ │ │ ├── EyelidView.java │ │ │ └── GraduallyTextView.java │ │ │ └── readview │ │ │ ├── BookStatus.java │ │ │ ├── PageFactory.java │ │ │ ├── PageWidget.java │ │ │ ├── ReadController.java │ │ │ └── interfaces │ │ │ └── OnControllerStatusChangeListener.java │ └── res │ │ ├── anim │ │ ├── bottom_in_animation.xml │ │ ├── bottom_out_animation.xml │ │ ├── top_in_animation.xml │ │ └── top_out_animation.xml │ │ ├── drawable-hdpi │ │ ├── cat.png │ │ ├── eyes.png │ │ └── mouse.png │ │ ├── drawable-xhdpi │ │ ├── about.png │ │ ├── add_book_normal.png │ │ ├── add_book_pressed.png │ │ ├── arrow_left.png │ │ ├── arrow_left_pressed.png │ │ ├── arrow_left_white.png │ │ ├── arrow_right_white.png │ │ ├── book_tag_bg.9.png │ │ ├── dark.png │ │ ├── feedback.png │ │ ├── file_import.png │ │ ├── font_type.png │ │ ├── lighten.png │ │ ├── list.png │ │ ├── menu_icon_black.png │ │ ├── menu_icon_grey.png │ │ ├── menu_icon_white.png │ │ ├── moon.png │ │ ├── more.png │ │ ├── reload.png │ │ ├── reload_pressed.png │ │ ├── search_icon_black.png │ │ ├── search_icon_grey.png │ │ ├── search_icon_white.png │ │ ├── sun.png │ │ ├── top_panel_bg.png │ │ └── txt_file_icon.png │ │ ├── drawable │ │ ├── add_book_bg.xml │ │ ├── arrow_left_selector.xml │ │ ├── custom_progress.xml │ │ ├── dot.xml │ │ ├── line_divider.xml │ │ ├── main_menu_item_bg.xml │ │ ├── rectangle_bg.xml │ │ └── reload_selector.xml │ │ ├── layout │ │ ├── activity_local_file_list.xml │ │ ├── activity_main.xml │ │ ├── activity_reading.xml │ │ ├── book_list_item.xml │ │ ├── bottom_sheet_dialog_fragment.xml │ │ ├── cat_loading.xml │ │ ├── chapter_list_item.xml │ │ ├── file_item.xml │ │ ├── fragment_chapter_list.xml │ │ ├── fragment_reading.xml │ │ ├── main_menu.xml │ │ ├── read_background_item.xml │ │ └── read_controller.xml │ │ ├── mipmap-xxxhdpi │ │ └── ic_launcher.png │ │ ├── values-w820dp │ │ └── dimens.xml │ │ └── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── codingbingo │ └── fastreader │ └── ExampleUnitTest.java ├── build.gradle ├── database ├── .gitignore ├── build.gradle ├── libs │ ├── freemarker-2.3.25-incubating.jar │ └── greendao-generator-3.2.0.jar └── src │ └── main │ └── java │ └── com │ └── codingbingo │ └── Main.java ├── doc └── images │ ├── FileList.png │ ├── Loading.png │ ├── MainView.png │ ├── ReadingView.png │ ├── ReadingViewWithController.png │ └── ReadingViewWithStyleController.png ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | .DS_Store 5 | /build 6 | /captures 7 | .externalNativeBuild 8 | .idea -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FastReader 2 | 3 | 一款开源的电子图书阅览器。 4 | 5 | ## Todo: 6 | 7 | ~~1. 打开大型txt文档~~ 8 | 9 | 打开大于10M的txt文本不会出现奔溃现象且阅读流畅。 10 | 11 | ~~2. 拆分章节~~ 12 | 13 | 将书籍拆分成若干章节。 14 | 15 | ~~3. 加载动画~~ 16 | 17 | 书籍在处理的过程中动画并提示处理书籍的比例。 18 | 19 | ~~4. 断点加载~~ 20 | 21 | 书籍正在加载,由于其他事件中断,下次进入的时候继续上次的位置继续处理书籍。 22 | 23 | ~~5. 动态设置阅读背景颜色~~ 24 | 25 | 在阅读过程中,用户可以调整阅读文本背景。目前内置6种颜色。 26 | 27 | ~~6. 动态设置阅读字体大小~~ 28 | 29 | 在阅读中,用户可以动态调整字体的大小。 30 | 31 | ~~7. 拖动进度条跳到指定章节~~ 32 | 33 | 在阅读页面,拖动进度条,动态跳转到该章节。 34 | 35 | ~~8. 删除已经添加的书籍~~ 36 | 37 | 长按书本,可以删除书本。 38 | 39 | 40 | ~~9. 多书籍同时加载~~ 41 | 42 | 多书籍同时加载,显示正常 43 | 44 | 10. 添加下载小说 45 | 46 | 11. 添加广告功能 47 | 48 | 12. 支持各种格式书籍(目前只支持txt文本) 49 | 50 | ## 示例 51 | * 主页 52 |
53 | 54 | 55 |
56 | 57 | * 阅读页 58 |
59 | 60 | 61 | 62 |
63 | 64 | * 本地文件添加 65 |
66 | 67 |
68 | 69 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 23 5 | buildToolsVersion "23.0.3" 6 | defaultConfig { 7 | applicationId "com.codingbingo.fastreader" 8 | minSdkVersion 15 9 | targetSdkVersion 23 10 | versionCode 1 11 | versionName "1.0" 12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | 21 | //为了解决部分第三方库重复打包了META-INF的问题 22 | packagingOptions { 23 | exclude 'META-INF/LICENSE.txt' 24 | exclude 'META-INF/NOTICE.txt' 25 | } 26 | } 27 | 28 | dependencies { 29 | //greenDao 30 | compile 'org.greenrobot:greendao:3.2.0' 31 | 32 | compile fileTree(dir: 'libs', include: ['*.jar']) 33 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { 34 | exclude group: 'com.android.support', module: 'support-annotations' 35 | }) 36 | compile 'com.android.support:appcompat-v7:23.4.0' 37 | compile 'com.android.support:design:23.4.0' 38 | testCompile 'junit:junit:4.12' 39 | 40 | // LeanCloud 基础包 41 | compile('cn.leancloud.android:avoscloud-sdk:v3.+') 42 | // LeanCloud 统计包 43 | compile('cn.leancloud.android:avoscloud-statistics:v3.+') 44 | // 推送与实时聊天需要的包 45 | compile('cn.leancloud.android:avoscloud-push:v3.+@aar') { transitive = true } 46 | 47 | compile 'org.greenrobot:eventbus:3.1.1' 48 | //发布到线上的时候删除 49 | compile 'com.facebook.stetho:stetho:1.4.2' 50 | } 51 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Users/bingo/Library/Android/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | 19 | -keepattributes *Annotation* 20 | -keepclassmembers class ** { 21 | @org.greenrobot.eventbus.Subscribe ; 22 | } 23 | -keep enum org.greenrobot.eventbus.ThreadMode { *; } 24 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/codingbingo/fastreader/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.codingbingo.fastreader; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumentation test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() throws Exception { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("com.codingbingo.fastreader", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 21 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 34 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /app/src/main/java/com/codingbingo/fastreader/Constants.java: -------------------------------------------------------------------------------- 1 | package com.codingbingo.fastreader; 2 | 3 | /** 4 | * Created by bingo on 2017/1/4. 5 | */ 6 | 7 | public class Constants { 8 | 9 | public static final String APP_ID = "OPzGifOOcII3IHvXEllk6SRS-gzGzoHsz"; 10 | public static final String APP_KEY = "ABleRzk9C1SJRIQYRCuOWWV8"; 11 | public static final String DB_NAME = "reader_db"; 12 | 13 | public static final int TYPE_FROM_MAIN_ACTIVITY = 1; 14 | public static final int TYPE_FROM_LOCAL_FILE_ACTIVITY = 2; 15 | 16 | public static final int STYLE_MAX_FONT_SIZE = 95; 17 | public static final int STYLE_MIN_FONT_SIZE = 40; 18 | public static final int STYLE_NORMAL_FONT_SIZE = 50; 19 | 20 | /** 21 | * 只是插入数据,未做任何处理 22 | */ 23 | public static final int BOOK_UNPROCESS = -1; 24 | 25 | /** 26 | * 已经读取编码方式 27 | */ 28 | public static final int BOOK_CHARSETFINISH = 0; 29 | /** 30 | * 正在处理中 31 | */ 32 | public static final int BOOK_PROCESSING = 1; 33 | /** 34 | * 35 | */ 36 | public static final int BOOK_PROCESSED = 2; 37 | } 38 | -------------------------------------------------------------------------------- /app/src/main/java/com/codingbingo/fastreader/FRApplication.java: -------------------------------------------------------------------------------- 1 | package com.codingbingo.fastreader; 2 | 3 | import android.app.Application; 4 | import android.app.Service; 5 | 6 | import com.avos.avoscloud.AVAnalytics; 7 | import com.avos.avoscloud.AVOSCloud; 8 | import com.codingbingo.fastreader.dao.DaoMaster; 9 | import com.codingbingo.fastreader.dao.DaoSession; 10 | import com.codingbingo.fastreader.utils.SharedPreferenceUtils; 11 | import com.facebook.stetho.Stetho; 12 | 13 | import org.greenrobot.greendao.database.Database; 14 | 15 | import java.util.HashMap; 16 | 17 | /** 18 | * Created by bingo on 2016/12/19. 19 | */ 20 | 21 | public class FRApplication extends Application { 22 | 23 | private static FRApplication instance; 24 | 25 | private HashMap serviceList; 26 | 27 | private DaoSession daoSession; 28 | 29 | @Override 30 | public void onCreate() { 31 | super.onCreate(); 32 | 33 | instance = this; 34 | 35 | initCloudService(); 36 | initDatabase(); 37 | init(); 38 | 39 | Stetho.initializeWithDefaults(this); 40 | } 41 | 42 | public static FRApplication getInstance(){ 43 | return instance; 44 | } 45 | 46 | private void init() { 47 | SharedPreferenceUtils.init(this, "FastReader"); 48 | } 49 | 50 | /** 51 | * 初始化LeanCloud服务 52 | */ 53 | private void initCloudService() { 54 | AVAnalytics.setAnalyticsEnabled(false); 55 | // 初始化参数依次为 this, AppId, AppKey 56 | AVOSCloud.initialize(this, Constants.APP_ID, Constants.APP_KEY); 57 | // AVAnalytics.enableCrashReport(this, true); 58 | //调试过程中,出现debug的log 59 | AVOSCloud.setDebugLogEnabled(true); 60 | } 61 | 62 | /** 63 | * 初始化数据库相关 64 | */ 65 | private void initDatabase() { 66 | DaoMaster.DevOpenHelper devOpenHelper = new DaoMaster.DevOpenHelper(this, Constants.DB_NAME); 67 | Database database = devOpenHelper.getWritableDb(); 68 | daoSession = new DaoMaster(database).newSession(); 69 | } 70 | 71 | public DaoSession getDaoSession() { 72 | return daoSession; 73 | } 74 | 75 | /** 76 | * 通过service的名称获取Service对象 77 | * 78 | * @param name 79 | * @return 80 | */ 81 | public Service findServiceByInterface(String name) { 82 | return serviceList.get(name); 83 | } 84 | 85 | public void registerService(String name, Service service) { 86 | if (serviceList == null) { 87 | serviceList = new HashMap<>(); 88 | } 89 | 90 | if (serviceList.containsKey(name)) { 91 | serviceList.put(name, service); 92 | } 93 | } 94 | } -------------------------------------------------------------------------------- /app/src/main/java/com/codingbingo/fastreader/base/BaseActivity.java: -------------------------------------------------------------------------------- 1 | package com.codingbingo.fastreader.base; 2 | 3 | import android.app.FragmentManager; 4 | import android.app.ProgressDialog; 5 | import android.os.Build; 6 | import android.os.Bundle; 7 | import android.support.annotation.Nullable; 8 | import android.support.v7.app.AppCompatActivity; 9 | import android.view.WindowManager; 10 | import android.widget.Toast; 11 | 12 | import com.avos.avoscloud.AVAnalytics; 13 | import com.codingbingo.fastreader.FRApplication; 14 | import com.codingbingo.fastreader.dao.DaoSession; 15 | import com.codingbingo.fastreader.view.LoadingDialog; 16 | 17 | /** 18 | * Created by bingo on 2016/12/23. 19 | */ 20 | 21 | public class BaseActivity extends AppCompatActivity { 22 | public static final int NO_BOOK_ID = -1; 23 | protected FragmentManager mFragmentManager; 24 | 25 | private LoadingDialog loadingDialog; 26 | private Toast toast; 27 | 28 | @Override 29 | protected void onCreate(@Nullable Bundle savedInstanceState) { 30 | super.onCreate(savedInstanceState); 31 | 32 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { 33 | //透明状态栏 34 | getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); 35 | //透明导航栏 36 | getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION); 37 | } 38 | 39 | init(); 40 | } 41 | 42 | /** 43 | * 初始化操作 44 | */ 45 | private void init() { 46 | mFragmentManager = getFragmentManager(); 47 | } 48 | 49 | @Override 50 | protected void onStart() { 51 | super.onStart(); 52 | } 53 | 54 | @Override 55 | protected void onDestroy() { 56 | super.onDestroy(); 57 | } 58 | 59 | @Override 60 | protected void onPause() { 61 | super.onPause(); 62 | AVAnalytics.onPause(this); 63 | } 64 | 65 | @Override 66 | protected void onResume() { 67 | super.onResume(); 68 | AVAnalytics.onResume(this); 69 | } 70 | 71 | /** 72 | * 获取数据库session 73 | * 74 | * @return 75 | */ 76 | protected DaoSession getDaoSession() { 77 | return FRApplication.getInstance().getDaoSession(); 78 | } 79 | 80 | protected void showToast(String content) { 81 | if (toast == null) { 82 | toast = Toast.makeText(this, content, Toast.LENGTH_SHORT); 83 | } else { 84 | toast.setText(content); 85 | } 86 | 87 | toast.show(); 88 | } 89 | 90 | /** 91 | * 显示加载动画 92 | * 93 | * @param message 94 | */ 95 | protected void showLoadingDialog(String message) { 96 | if (loadingDialog == null) { 97 | loadingDialog = new LoadingDialog(this); 98 | } 99 | 100 | loadingDialog.show(); 101 | } 102 | 103 | /** 104 | * 关闭加载动画 105 | */ 106 | protected void dismissLoadingDialog() { 107 | if (loadingDialog != null) { 108 | loadingDialog.dismiss(); 109 | } 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /app/src/main/java/com/codingbingo/fastreader/base/BaseFragment.java: -------------------------------------------------------------------------------- 1 | package com.codingbingo.fastreader.base; 2 | 3 | import android.app.Fragment; 4 | import android.view.Window; 5 | import android.view.WindowManager; 6 | import android.widget.Toast; 7 | 8 | import com.avos.avoscloud.AVAnalytics; 9 | import com.codingbingo.fastreader.FRApplication; 10 | import com.codingbingo.fastreader.dao.DaoSession; 11 | import com.codingbingo.fastreader.view.LoadingDialog; 12 | 13 | /** 14 | * Created by bingo on 2016/12/24. 15 | */ 16 | 17 | public abstract class BaseFragment extends Fragment { 18 | private LoadingDialog loadingDialog; 19 | private Toast toast; 20 | 21 | public abstract String getFragmentName(); 22 | 23 | @Override 24 | public void onPause() { 25 | super.onPause(); 26 | 27 | AVAnalytics.onFragmentEnd(getFragmentName()); 28 | } 29 | 30 | @Override 31 | public void onResume() { 32 | super.onResume(); 33 | 34 | AVAnalytics.onFragmentStart(getFragmentName()); 35 | } 36 | 37 | protected Window getWindow() { 38 | return getActivity().getWindow(); 39 | } 40 | 41 | protected void switchFullScreen(boolean isFullScreen) { 42 | if (isFullScreen) { 43 | WindowManager.LayoutParams params = getWindow().getAttributes(); 44 | params.flags |= WindowManager.LayoutParams.FLAG_FULLSCREEN; 45 | getWindow().setAttributes(params); 46 | getWindow().addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS); 47 | } else { 48 | WindowManager.LayoutParams params = getWindow().getAttributes(); 49 | params.flags &= (~WindowManager.LayoutParams.FLAG_FULLSCREEN); 50 | getWindow().setAttributes(params); 51 | getWindow().clearFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS); 52 | } 53 | } 54 | 55 | /** 56 | * 获取数据库session 57 | * 58 | * @return 59 | */ 60 | protected DaoSession getDaoSession() { 61 | return FRApplication.getInstance().getDaoSession(); 62 | } 63 | 64 | protected void showToast(String content) { 65 | if (toast == null) { 66 | toast = Toast.makeText(getActivity(), content, Toast.LENGTH_SHORT); 67 | } else { 68 | toast.setText(content); 69 | } 70 | toast.show(); 71 | } 72 | 73 | /** 74 | * 显示加载动画 75 | * 76 | * @param message 77 | */ 78 | protected void showLoadingDialog(String message) { 79 | if (loadingDialog == null) { 80 | loadingDialog = new LoadingDialog(getActivity()); 81 | } 82 | 83 | loadingDialog.show(); 84 | } 85 | 86 | /** 87 | * 关闭加载动画 88 | */ 89 | protected void dismissLoadingDialog() { 90 | if (loadingDialog != null) { 91 | loadingDialog.dismiss(); 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /app/src/main/java/com/codingbingo/fastreader/base/utils/BaseUtils.java: -------------------------------------------------------------------------------- 1 | package com.codingbingo.fastreader.base.utils; 2 | 3 | import java.util.logging.Logger; 4 | 5 | /** 6 | * Author: bingo 7 | * Email: codingbingo@gmail.com 8 | * By 2017/1/15. 9 | */ 10 | 11 | public class BaseUtils { 12 | protected static Logger logger = Logger.getLogger(BaseUtils.class.getName()); 13 | } 14 | -------------------------------------------------------------------------------- /app/src/main/java/com/codingbingo/fastreader/base/view/BaseReadView.java: -------------------------------------------------------------------------------- 1 | package com.codingbingo.fastreader.base.view; 2 | 3 | import android.content.Context; 4 | import android.graphics.Bitmap; 5 | import android.graphics.Canvas; 6 | import android.graphics.PointF; 7 | import android.support.annotation.Nullable; 8 | import android.util.AttributeSet; 9 | import android.view.MotionEvent; 10 | import android.view.View; 11 | import android.widget.Scroller; 12 | import android.widget.Toast; 13 | 14 | import com.avos.avoscloud.LogUtil; 15 | import com.codingbingo.fastreader.Constants; 16 | import com.codingbingo.fastreader.FRApplication; 17 | import com.codingbingo.fastreader.base.BaseActivity; 18 | import com.codingbingo.fastreader.dao.Book; 19 | import com.codingbingo.fastreader.dao.BookDao; 20 | import com.codingbingo.fastreader.dao.ChapterDao; 21 | import com.codingbingo.fastreader.dao.DaoSession; 22 | import com.codingbingo.fastreader.model.eventbus.StyleChangeEvent; 23 | import com.codingbingo.fastreader.utils.ScreenUtils; 24 | import com.codingbingo.fastreader.view.readview.BookStatus; 25 | import com.codingbingo.fastreader.view.readview.PageFactory; 26 | 27 | import org.greenrobot.eventbus.EventBus; 28 | import org.greenrobot.eventbus.Subscribe; 29 | import org.greenrobot.eventbus.ThreadMode; 30 | 31 | /** 32 | * Created by bingo on 2017/1/4. 33 | */ 34 | 35 | public abstract class BaseReadView extends View { 36 | protected Context mContext; 37 | 38 | protected int mScreenWidth; 39 | protected int mScreenHeight; 40 | 41 | protected PointF mTouch = new PointF(); 42 | protected float actiondownX, actiondownY; 43 | protected float touch_down = 0; // 当前触摸点与按下时的点的差值 44 | 45 | protected Bitmap mCurPageBitmap, mNextPageBitmap; 46 | protected Canvas mCurrentPageCanvas, mNextPageCanvas; 47 | protected PageFactory pagefactory = null; 48 | 49 | protected long bookId = BaseActivity.NO_BOOK_ID; 50 | protected String bookPath; 51 | protected Book book; 52 | protected boolean isPrepared = true; 53 | 54 | private Toast toast; 55 | protected Scroller mScroller; 56 | 57 | protected DaoSession daoSession; 58 | protected BookDao bookDao; 59 | protected ChapterDao chapterDao; 60 | 61 | 62 | public BaseReadView(Context context){ 63 | this(context, null, 0); 64 | } 65 | 66 | public BaseReadView(Context context, @Nullable AttributeSet attrs) { 67 | super(context, attrs, 0); 68 | } 69 | 70 | public BaseReadView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { 71 | super(context, attrs, defStyleAttr); 72 | 73 | mContext = context; 74 | 75 | mScreenWidth = ScreenUtils.getScreenWidth(context); 76 | mScreenHeight = ScreenUtils.getScreenHeight(context); 77 | 78 | mCurPageBitmap = Bitmap.createBitmap(mScreenWidth, mScreenHeight, Bitmap.Config.ARGB_8888); 79 | mNextPageBitmap = Bitmap.createBitmap(mScreenWidth, mScreenHeight, Bitmap.Config.ARGB_8888); 80 | mCurrentPageCanvas = new Canvas(mCurPageBitmap); 81 | mNextPageCanvas = new Canvas(mNextPageBitmap); 82 | 83 | mScroller = new Scroller(getContext()); 84 | pagefactory = new PageFactory(context); 85 | 86 | 87 | //数据库 88 | daoSession = ((FRApplication) context.getApplicationContext()).getDaoSession(); 89 | bookDao = daoSession.getBookDao(); 90 | chapterDao = daoSession.getChapterDao(); 91 | } 92 | 93 | 94 | protected synchronized void init() { 95 | try { 96 | book = bookDao.load(bookId); 97 | 98 | pagefactory.onDraw(mCurrentPageCanvas); 99 | //主动刷新界面 100 | postInvalidate(); 101 | } catch (Exception e) { 102 | } 103 | } 104 | 105 | public void setBookId(long bookId, boolean needRefresh) { 106 | LogUtil.log.e("bookId: " + bookId + " ------ this.bookId: " + this.bookId); 107 | LogUtil.log.e("book is null: " + (book == null)); 108 | LogUtil.log.e("book process status: " + (book != null ? book.getProcessStatus() : "null")); 109 | 110 | if (book == null || book.getProcessStatus() != Constants.BOOK_PROCESSED || this.bookId != bookId || needRefresh == true) { 111 | this.bookId = bookId; 112 | pagefactory.openBook(bookId); 113 | } else { 114 | pagefactory.clearParams(); 115 | } 116 | 117 | init(); 118 | } 119 | 120 | public void setBookPath(String bookPath) { 121 | if (this.bookPath == null || !this.bookPath.equals(bookPath)) { 122 | this.bookPath = bookPath; 123 | pagefactory.openBook(bookPath); 124 | } else { 125 | pagefactory.clearParams(); 126 | } 127 | 128 | init(); 129 | } 130 | 131 | private int dx, dy; 132 | private long et = 0; 133 | private boolean cancel = false; 134 | private boolean center = false; 135 | 136 | @Override 137 | public boolean onTouchEvent(MotionEvent e) { 138 | // switch (e.getAction()) { 139 | // case MotionEvent.ACTION_DOWN: 140 | // 141 | // break; 142 | // case MotionEvent.ACTION_MOVE: 143 | // if (center) 144 | // break; 145 | // int mx = (int) e.getX(); 146 | // int my = (int) e.getY(); 147 | // cancel = (actiondownX < mScreenWidth / 2 && mx < mTouch.x) || (actiondownX > mScreenWidth / 2 && mx > mTouch.x); 148 | // mTouch.x = mx; 149 | // mTouch.y = my; 150 | // touch_down = mTouch.x - actiondownX; 151 | // this.postInvalidate(); 152 | // break; 153 | // case MotionEvent.ACTION_UP: 154 | // case MotionEvent.ACTION_CANCEL: 155 | // 156 | // break; 157 | // default: 158 | // break; 159 | // } 160 | return true; 161 | } 162 | 163 | /** 164 | * 复位触摸点位 165 | */ 166 | protected void resetTouchPoint() { 167 | mTouch.x = 0.1f; 168 | mTouch.y = 0.1f; 169 | touch_down = 0; 170 | calcCornerXY(mTouch.x, mTouch.y); 171 | } 172 | 173 | 174 | @Override 175 | protected void onDraw(Canvas canvas) { 176 | calcPoints(); 177 | drawCurrentPageArea(canvas); 178 | drawNextPageAreaAndShadow(canvas); 179 | drawCurrentPageShadow(canvas); 180 | drawCurrentBackArea(canvas); 181 | } 182 | 183 | protected abstract void drawNextPageAreaAndShadow(Canvas canvas); 184 | 185 | protected abstract void drawCurrentPageShadow(Canvas canvas); 186 | 187 | protected abstract void drawCurrentBackArea(Canvas canvas); 188 | 189 | protected abstract void drawCurrentPageArea(Canvas canvas); 190 | 191 | protected abstract void calcPoints(); 192 | 193 | protected abstract void calcCornerXY(float x, float y); 194 | 195 | @Override 196 | protected void onDetachedFromWindow() { 197 | super.onDetachedFromWindow(); 198 | //取消订阅事件 199 | if (EventBus.getDefault().isRegistered(this)) { 200 | EventBus.getDefault().unregister(this); 201 | } 202 | } 203 | 204 | @Override 205 | protected void onAttachedToWindow() { 206 | super.onAttachedToWindow(); 207 | //订阅事件 208 | if (EventBus.getDefault().isRegistered(this) == false) { 209 | EventBus.getDefault().register(this); 210 | } 211 | } 212 | 213 | @Subscribe(threadMode = ThreadMode.MAIN) 214 | public void onReceiveStyleChangeEvent(StyleChangeEvent styleChangeEvent){ 215 | if (pagefactory != null) { 216 | pagefactory.refreshAccordingToStyle(mCurrentPageCanvas); 217 | invalidate(); 218 | } 219 | } 220 | 221 | /** 222 | * 显示Toast提示 223 | * @param content 224 | */ 225 | protected void showToast(String content){ 226 | if (toast == null) { 227 | toast = Toast.makeText(mContext, content, Toast.LENGTH_SHORT); 228 | }else { 229 | toast.setText(content); 230 | } 231 | toast.show(); 232 | } 233 | 234 | public void nextPage() { 235 | BookStatus status = pagefactory.nextPage(); 236 | if (status == BookStatus.NO_NEXT_PAGE) { 237 | showToast("没有下一页啦"); 238 | return; 239 | } else if (status == BookStatus.LOAD_SUCCESS) { 240 | if (isPrepared) { 241 | pagefactory.onDraw(mCurrentPageCanvas); 242 | postInvalidate(); 243 | } 244 | } else { 245 | return; 246 | } 247 | 248 | } 249 | 250 | public void prePage() { 251 | BookStatus status = pagefactory.prePage(); 252 | if (status == BookStatus.NO_PRE_PAGE) { 253 | showToast("没有上一页啦"); 254 | return; 255 | } else if (status == BookStatus.LOAD_SUCCESS) { 256 | if (isPrepared) { 257 | pagefactory.onDraw(mCurrentPageCanvas); 258 | postInvalidate(); 259 | } 260 | } else { 261 | return; 262 | } 263 | } 264 | } 265 | -------------------------------------------------------------------------------- /app/src/main/java/com/codingbingo/fastreader/dao/Book.java: -------------------------------------------------------------------------------- 1 | package com.codingbingo.fastreader.dao; 2 | 3 | import org.greenrobot.greendao.annotation.*; 4 | 5 | // THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT. Enable "keep" sections if you want to edit. 6 | 7 | /** 8 | * Entity mapped to table "BOOK". 9 | */ 10 | @Entity 11 | public class Book { 12 | 13 | @Id(autoincrement = true) 14 | private Long id; 15 | 16 | @NotNull 17 | private String bookName; 18 | private String bookImagePath; 19 | private String description; 20 | private String tags; 21 | private String writer; 22 | private String charSet; 23 | private String bookPath; 24 | private Integer currentChapter; 25 | private Integer currentPosition; 26 | private int processStatus; 27 | 28 | @Generated 29 | public Book() { 30 | } 31 | 32 | public Book(Long id) { 33 | this.id = id; 34 | } 35 | 36 | @Generated 37 | public Book(Long id, String bookName, String bookImagePath, String description, String tags, String writer, String charSet, String bookPath, Integer currentChapter, Integer currentPosition, int processStatus) { 38 | this.id = id; 39 | this.bookName = bookName; 40 | this.bookImagePath = bookImagePath; 41 | this.description = description; 42 | this.tags = tags; 43 | this.writer = writer; 44 | this.charSet = charSet; 45 | this.bookPath = bookPath; 46 | this.currentChapter = currentChapter; 47 | this.currentPosition = currentPosition; 48 | this.processStatus = processStatus; 49 | } 50 | 51 | public Long getId() { 52 | return id; 53 | } 54 | 55 | public void setId(Long id) { 56 | this.id = id; 57 | } 58 | 59 | @NotNull 60 | public String getBookName() { 61 | return bookName; 62 | } 63 | 64 | /** Not-null value; ensure this value is available before it is saved to the database. */ 65 | public void setBookName(@NotNull String bookName) { 66 | this.bookName = bookName; 67 | } 68 | 69 | public String getBookImagePath() { 70 | return bookImagePath; 71 | } 72 | 73 | public void setBookImagePath(String bookImagePath) { 74 | this.bookImagePath = bookImagePath; 75 | } 76 | 77 | public String getDescription() { 78 | return description; 79 | } 80 | 81 | public void setDescription(String description) { 82 | this.description = description; 83 | } 84 | 85 | public String getTags() { 86 | return tags; 87 | } 88 | 89 | public void setTags(String tags) { 90 | this.tags = tags; 91 | } 92 | 93 | public String getWriter() { 94 | return writer; 95 | } 96 | 97 | public void setWriter(String writer) { 98 | this.writer = writer; 99 | } 100 | 101 | public String getCharSet() { 102 | return charSet; 103 | } 104 | 105 | public void setCharSet(String charSet) { 106 | this.charSet = charSet; 107 | } 108 | 109 | public String getBookPath() { 110 | return bookPath; 111 | } 112 | 113 | public void setBookPath(String bookPath) { 114 | this.bookPath = bookPath; 115 | } 116 | 117 | public Integer getCurrentChapter() { 118 | return currentChapter; 119 | } 120 | 121 | public void setCurrentChapter(Integer currentChapter) { 122 | this.currentChapter = currentChapter; 123 | } 124 | 125 | public Integer getCurrentPosition() { 126 | return currentPosition; 127 | } 128 | 129 | public void setCurrentPosition(Integer currentPosition) { 130 | this.currentPosition = currentPosition; 131 | } 132 | 133 | public int getProcessStatus() { 134 | return processStatus; 135 | } 136 | 137 | public void setProcessStatus(int processStatus) { 138 | this.processStatus = processStatus; 139 | } 140 | 141 | } 142 | -------------------------------------------------------------------------------- /app/src/main/java/com/codingbingo/fastreader/dao/BookDao.java: -------------------------------------------------------------------------------- 1 | package com.codingbingo.fastreader.dao; 2 | 3 | import android.database.Cursor; 4 | import android.database.sqlite.SQLiteStatement; 5 | 6 | import org.greenrobot.greendao.AbstractDao; 7 | import org.greenrobot.greendao.Property; 8 | import org.greenrobot.greendao.internal.DaoConfig; 9 | import org.greenrobot.greendao.database.Database; 10 | import org.greenrobot.greendao.database.DatabaseStatement; 11 | 12 | // THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT. 13 | /** 14 | * DAO for table "BOOK". 15 | */ 16 | public class BookDao extends AbstractDao { 17 | 18 | public static final String TABLENAME = "BOOK"; 19 | 20 | /** 21 | * Properties of entity Book.
22 | * Can be used for QueryBuilder and for referencing column names. 23 | */ 24 | public static class Properties { 25 | public final static Property Id = new Property(0, Long.class, "id", true, "_id"); 26 | public final static Property BookName = new Property(1, String.class, "bookName", false, "BOOK_NAME"); 27 | public final static Property BookImagePath = new Property(2, String.class, "bookImagePath", false, "BOOK_IMAGE_PATH"); 28 | public final static Property Description = new Property(3, String.class, "description", false, "DESCRIPTION"); 29 | public final static Property Tags = new Property(4, String.class, "tags", false, "TAGS"); 30 | public final static Property Writer = new Property(5, String.class, "writer", false, "WRITER"); 31 | public final static Property CharSet = new Property(6, String.class, "charSet", false, "CHAR_SET"); 32 | public final static Property BookPath = new Property(7, String.class, "bookPath", false, "BOOK_PATH"); 33 | public final static Property CurrentChapter = new Property(8, Integer.class, "currentChapter", false, "CURRENT_CHAPTER"); 34 | public final static Property CurrentPosition = new Property(9, Integer.class, "currentPosition", false, "CURRENT_POSITION"); 35 | public final static Property ProcessStatus = new Property(10, int.class, "processStatus", false, "PROCESS_STATUS"); 36 | } 37 | 38 | 39 | public BookDao(DaoConfig config) { 40 | super(config); 41 | } 42 | 43 | public BookDao(DaoConfig config, DaoSession daoSession) { 44 | super(config, daoSession); 45 | } 46 | 47 | /** Creates the underlying database table. */ 48 | public static void createTable(Database db, boolean ifNotExists) { 49 | String constraint = ifNotExists? "IF NOT EXISTS ": ""; 50 | db.execSQL("CREATE TABLE " + constraint + "\"BOOK\" (" + // 51 | "\"_id\" INTEGER PRIMARY KEY AUTOINCREMENT ," + // 0: id 52 | "\"BOOK_NAME\" TEXT NOT NULL ," + // 1: bookName 53 | "\"BOOK_IMAGE_PATH\" TEXT," + // 2: bookImagePath 54 | "\"DESCRIPTION\" TEXT," + // 3: description 55 | "\"TAGS\" TEXT," + // 4: tags 56 | "\"WRITER\" TEXT," + // 5: writer 57 | "\"CHAR_SET\" TEXT," + // 6: charSet 58 | "\"BOOK_PATH\" TEXT," + // 7: bookPath 59 | "\"CURRENT_CHAPTER\" INTEGER," + // 8: currentChapter 60 | "\"CURRENT_POSITION\" INTEGER," + // 9: currentPosition 61 | "\"PROCESS_STATUS\" INTEGER NOT NULL );"); // 10: processStatus 62 | } 63 | 64 | /** Drops the underlying database table. */ 65 | public static void dropTable(Database db, boolean ifExists) { 66 | String sql = "DROP TABLE " + (ifExists ? "IF EXISTS " : "") + "\"BOOK\""; 67 | db.execSQL(sql); 68 | } 69 | 70 | @Override 71 | protected final void bindValues(DatabaseStatement stmt, Book entity) { 72 | stmt.clearBindings(); 73 | 74 | Long id = entity.getId(); 75 | if (id != null) { 76 | stmt.bindLong(1, id); 77 | } 78 | stmt.bindString(2, entity.getBookName()); 79 | 80 | String bookImagePath = entity.getBookImagePath(); 81 | if (bookImagePath != null) { 82 | stmt.bindString(3, bookImagePath); 83 | } 84 | 85 | String description = entity.getDescription(); 86 | if (description != null) { 87 | stmt.bindString(4, description); 88 | } 89 | 90 | String tags = entity.getTags(); 91 | if (tags != null) { 92 | stmt.bindString(5, tags); 93 | } 94 | 95 | String writer = entity.getWriter(); 96 | if (writer != null) { 97 | stmt.bindString(6, writer); 98 | } 99 | 100 | String charSet = entity.getCharSet(); 101 | if (charSet != null) { 102 | stmt.bindString(7, charSet); 103 | } 104 | 105 | String bookPath = entity.getBookPath(); 106 | if (bookPath != null) { 107 | stmt.bindString(8, bookPath); 108 | } 109 | 110 | Integer currentChapter = entity.getCurrentChapter(); 111 | if (currentChapter != null) { 112 | stmt.bindLong(9, currentChapter); 113 | } 114 | 115 | Integer currentPosition = entity.getCurrentPosition(); 116 | if (currentPosition != null) { 117 | stmt.bindLong(10, currentPosition); 118 | } 119 | stmt.bindLong(11, entity.getProcessStatus()); 120 | } 121 | 122 | @Override 123 | protected final void bindValues(SQLiteStatement stmt, Book entity) { 124 | stmt.clearBindings(); 125 | 126 | Long id = entity.getId(); 127 | if (id != null) { 128 | stmt.bindLong(1, id); 129 | } 130 | stmt.bindString(2, entity.getBookName()); 131 | 132 | String bookImagePath = entity.getBookImagePath(); 133 | if (bookImagePath != null) { 134 | stmt.bindString(3, bookImagePath); 135 | } 136 | 137 | String description = entity.getDescription(); 138 | if (description != null) { 139 | stmt.bindString(4, description); 140 | } 141 | 142 | String tags = entity.getTags(); 143 | if (tags != null) { 144 | stmt.bindString(5, tags); 145 | } 146 | 147 | String writer = entity.getWriter(); 148 | if (writer != null) { 149 | stmt.bindString(6, writer); 150 | } 151 | 152 | String charSet = entity.getCharSet(); 153 | if (charSet != null) { 154 | stmt.bindString(7, charSet); 155 | } 156 | 157 | String bookPath = entity.getBookPath(); 158 | if (bookPath != null) { 159 | stmt.bindString(8, bookPath); 160 | } 161 | 162 | Integer currentChapter = entity.getCurrentChapter(); 163 | if (currentChapter != null) { 164 | stmt.bindLong(9, currentChapter); 165 | } 166 | 167 | Integer currentPosition = entity.getCurrentPosition(); 168 | if (currentPosition != null) { 169 | stmt.bindLong(10, currentPosition); 170 | } 171 | stmt.bindLong(11, entity.getProcessStatus()); 172 | } 173 | 174 | @Override 175 | public Long readKey(Cursor cursor, int offset) { 176 | return cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0); 177 | } 178 | 179 | @Override 180 | public Book readEntity(Cursor cursor, int offset) { 181 | Book entity = new Book( // 182 | cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0), // id 183 | cursor.getString(offset + 1), // bookName 184 | cursor.isNull(offset + 2) ? null : cursor.getString(offset + 2), // bookImagePath 185 | cursor.isNull(offset + 3) ? null : cursor.getString(offset + 3), // description 186 | cursor.isNull(offset + 4) ? null : cursor.getString(offset + 4), // tags 187 | cursor.isNull(offset + 5) ? null : cursor.getString(offset + 5), // writer 188 | cursor.isNull(offset + 6) ? null : cursor.getString(offset + 6), // charSet 189 | cursor.isNull(offset + 7) ? null : cursor.getString(offset + 7), // bookPath 190 | cursor.isNull(offset + 8) ? null : cursor.getInt(offset + 8), // currentChapter 191 | cursor.isNull(offset + 9) ? null : cursor.getInt(offset + 9), // currentPosition 192 | cursor.getInt(offset + 10) // processStatus 193 | ); 194 | return entity; 195 | } 196 | 197 | @Override 198 | public void readEntity(Cursor cursor, Book entity, int offset) { 199 | entity.setId(cursor.isNull(offset + 0) ? null : cursor.getLong(offset + 0)); 200 | entity.setBookName(cursor.getString(offset + 1)); 201 | entity.setBookImagePath(cursor.isNull(offset + 2) ? null : cursor.getString(offset + 2)); 202 | entity.setDescription(cursor.isNull(offset + 3) ? null : cursor.getString(offset + 3)); 203 | entity.setTags(cursor.isNull(offset + 4) ? null : cursor.getString(offset + 4)); 204 | entity.setWriter(cursor.isNull(offset + 5) ? null : cursor.getString(offset + 5)); 205 | entity.setCharSet(cursor.isNull(offset + 6) ? null : cursor.getString(offset + 6)); 206 | entity.setBookPath(cursor.isNull(offset + 7) ? null : cursor.getString(offset + 7)); 207 | entity.setCurrentChapter(cursor.isNull(offset + 8) ? null : cursor.getInt(offset + 8)); 208 | entity.setCurrentPosition(cursor.isNull(offset + 9) ? null : cursor.getInt(offset + 9)); 209 | entity.setProcessStatus(cursor.getInt(offset + 10)); 210 | } 211 | 212 | @Override 213 | protected final Long updateKeyAfterInsert(Book entity, long rowId) { 214 | entity.setId(rowId); 215 | return rowId; 216 | } 217 | 218 | @Override 219 | public Long getKey(Book entity) { 220 | if(entity != null) { 221 | return entity.getId(); 222 | } else { 223 | return null; 224 | } 225 | } 226 | 227 | @Override 228 | public boolean hasKey(Book entity) { 229 | return entity.getId() != null; 230 | } 231 | 232 | @Override 233 | protected final boolean isEntityUpdateable() { 234 | return true; 235 | } 236 | 237 | } 238 | -------------------------------------------------------------------------------- /app/src/main/java/com/codingbingo/fastreader/dao/Chapter.java: -------------------------------------------------------------------------------- 1 | package com.codingbingo.fastreader.dao; 2 | 3 | import org.greenrobot.greendao.annotation.*; 4 | 5 | import com.codingbingo.fastreader.dao.DaoSession; 6 | import org.greenrobot.greendao.DaoException; 7 | 8 | // THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT. Enable "keep" sections if you want to edit. 9 | 10 | /** 11 | * Entity mapped to table "CHAPTER". 12 | */ 13 | @Entity(active = true) 14 | public class Chapter { 15 | 16 | @Id(autoincrement = true) 17 | private Long id; 18 | private String title; 19 | private int position; 20 | private Integer pageCount; 21 | private Boolean isRead; 22 | private long bookId; 23 | 24 | /** Used to resolve relations */ 25 | @Generated 26 | private transient DaoSession daoSession; 27 | 28 | /** Used for active entity operations. */ 29 | @Generated 30 | private transient ChapterDao myDao; 31 | 32 | @ToOne(joinProperty = "bookId") 33 | private Book book; 34 | 35 | @Generated 36 | private transient Long book__resolvedKey; 37 | 38 | @Generated 39 | public Chapter() { 40 | } 41 | 42 | public Chapter(Long id) { 43 | this.id = id; 44 | } 45 | 46 | @Generated 47 | public Chapter(Long id, String title, int position, Integer pageCount, Boolean isRead, long bookId) { 48 | this.id = id; 49 | this.title = title; 50 | this.position = position; 51 | this.pageCount = pageCount; 52 | this.isRead = isRead; 53 | this.bookId = bookId; 54 | } 55 | 56 | /** called by internal mechanisms, do not call yourself. */ 57 | @Generated 58 | public void __setDaoSession(DaoSession daoSession) { 59 | this.daoSession = daoSession; 60 | myDao = daoSession != null ? daoSession.getChapterDao() : null; 61 | } 62 | 63 | public Long getId() { 64 | return id; 65 | } 66 | 67 | public void setId(Long id) { 68 | this.id = id; 69 | } 70 | 71 | public String getTitle() { 72 | return title; 73 | } 74 | 75 | public void setTitle(String title) { 76 | this.title = title; 77 | } 78 | 79 | public int getPosition() { 80 | return position; 81 | } 82 | 83 | public void setPosition(int position) { 84 | this.position = position; 85 | } 86 | 87 | public Integer getPageCount() { 88 | return pageCount; 89 | } 90 | 91 | public void setPageCount(Integer pageCount) { 92 | this.pageCount = pageCount; 93 | } 94 | 95 | public Boolean getIsRead() { 96 | return isRead; 97 | } 98 | 99 | public void setIsRead(Boolean isRead) { 100 | this.isRead = isRead; 101 | } 102 | 103 | public long getBookId() { 104 | return bookId; 105 | } 106 | 107 | public void setBookId(long bookId) { 108 | this.bookId = bookId; 109 | } 110 | 111 | /** To-one relationship, resolved on first access. */ 112 | @Generated 113 | public Book getBook() { 114 | long __key = this.bookId; 115 | if (book__resolvedKey == null || !book__resolvedKey.equals(__key)) { 116 | __throwIfDetached(); 117 | BookDao targetDao = daoSession.getBookDao(); 118 | Book bookNew = targetDao.load(__key); 119 | synchronized (this) { 120 | book = bookNew; 121 | book__resolvedKey = __key; 122 | } 123 | } 124 | return book; 125 | } 126 | 127 | @Generated 128 | public void setBook(Book book) { 129 | if (book == null) { 130 | throw new DaoException("To-one property 'bookId' has not-null constraint; cannot set to-one to null"); 131 | } 132 | synchronized (this) { 133 | this.book = book; 134 | bookId = book.getId(); 135 | book__resolvedKey = bookId; 136 | } 137 | } 138 | 139 | /** 140 | * Convenient call for {@link org.greenrobot.greendao.AbstractDao#delete(Object)}. 141 | * Entity must attached to an entity context. 142 | */ 143 | @Generated 144 | public void delete() { 145 | __throwIfDetached(); 146 | myDao.delete(this); 147 | } 148 | 149 | /** 150 | * Convenient call for {@link org.greenrobot.greendao.AbstractDao#update(Object)}. 151 | * Entity must attached to an entity context. 152 | */ 153 | @Generated 154 | public void update() { 155 | __throwIfDetached(); 156 | myDao.update(this); 157 | } 158 | 159 | /** 160 | * Convenient call for {@link org.greenrobot.greendao.AbstractDao#refresh(Object)}. 161 | * Entity must attached to an entity context. 162 | */ 163 | @Generated 164 | public void refresh() { 165 | __throwIfDetached(); 166 | myDao.refresh(this); 167 | } 168 | 169 | @Generated 170 | private void __throwIfDetached() { 171 | if (myDao == null) { 172 | throw new DaoException("Entity is detached from DAO context"); 173 | } 174 | } 175 | 176 | } 177 | -------------------------------------------------------------------------------- /app/src/main/java/com/codingbingo/fastreader/dao/DaoMaster.java: -------------------------------------------------------------------------------- 1 | package com.codingbingo.fastreader.dao; 2 | 3 | import android.content.Context; 4 | import android.database.sqlite.SQLiteDatabase; 5 | import android.database.sqlite.SQLiteDatabase.CursorFactory; 6 | import android.util.Log; 7 | 8 | import org.greenrobot.greendao.AbstractDaoMaster; 9 | import org.greenrobot.greendao.database.StandardDatabase; 10 | import org.greenrobot.greendao.database.Database; 11 | import org.greenrobot.greendao.database.DatabaseOpenHelper; 12 | import org.greenrobot.greendao.identityscope.IdentityScopeType; 13 | 14 | 15 | // THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT. 16 | /** 17 | * Master of DAO (schema version 1): knows all DAOs. 18 | */ 19 | public class DaoMaster extends AbstractDaoMaster { 20 | public static final int SCHEMA_VERSION = 1; 21 | 22 | /** Creates underlying database table using DAOs. */ 23 | public static void createAllTables(Database db, boolean ifNotExists) { 24 | BookDao.createTable(db, ifNotExists); 25 | ChapterDao.createTable(db, ifNotExists); 26 | } 27 | 28 | /** Drops underlying database table using DAOs. */ 29 | public static void dropAllTables(Database db, boolean ifExists) { 30 | BookDao.dropTable(db, ifExists); 31 | ChapterDao.dropTable(db, ifExists); 32 | } 33 | 34 | /** 35 | * WARNING: Drops all table on Upgrade! Use only during development. 36 | * Convenience method using a {@link DevOpenHelper}. 37 | */ 38 | public static DaoSession newDevSession(Context context, String name) { 39 | Database db = new DevOpenHelper(context, name).getWritableDb(); 40 | DaoMaster daoMaster = new DaoMaster(db); 41 | return daoMaster.newSession(); 42 | } 43 | 44 | public DaoMaster(SQLiteDatabase db) { 45 | this(new StandardDatabase(db)); 46 | } 47 | 48 | public DaoMaster(Database db) { 49 | super(db, SCHEMA_VERSION); 50 | registerDaoClass(BookDao.class); 51 | registerDaoClass(ChapterDao.class); 52 | } 53 | 54 | public DaoSession newSession() { 55 | return new DaoSession(db, IdentityScopeType.Session, daoConfigMap); 56 | } 57 | 58 | public DaoSession newSession(IdentityScopeType type) { 59 | return new DaoSession(db, type, daoConfigMap); 60 | } 61 | 62 | /** 63 | * Calls {@link #createAllTables(Database, boolean)} in {@link #onCreate(Database)} - 64 | */ 65 | public static abstract class OpenHelper extends DatabaseOpenHelper { 66 | public OpenHelper(Context context, String name) { 67 | super(context, name, SCHEMA_VERSION); 68 | } 69 | 70 | public OpenHelper(Context context, String name, CursorFactory factory) { 71 | super(context, name, factory, SCHEMA_VERSION); 72 | } 73 | 74 | @Override 75 | public void onCreate(Database db) { 76 | Log.i("greenDAO", "Creating tables for schema version " + SCHEMA_VERSION); 77 | createAllTables(db, false); 78 | } 79 | } 80 | 81 | /** WARNING: Drops all table on Upgrade! Use only during development. */ 82 | public static class DevOpenHelper extends OpenHelper { 83 | public DevOpenHelper(Context context, String name) { 84 | super(context, name); 85 | } 86 | 87 | public DevOpenHelper(Context context, String name, CursorFactory factory) { 88 | super(context, name, factory); 89 | } 90 | 91 | @Override 92 | public void onUpgrade(Database db, int oldVersion, int newVersion) { 93 | Log.i("greenDAO", "Upgrading schema from version " + oldVersion + " to " + newVersion + " by dropping all tables"); 94 | dropAllTables(db, true); 95 | onCreate(db); 96 | } 97 | } 98 | 99 | } 100 | -------------------------------------------------------------------------------- /app/src/main/java/com/codingbingo/fastreader/dao/DaoSession.java: -------------------------------------------------------------------------------- 1 | package com.codingbingo.fastreader.dao; 2 | 3 | import java.util.Map; 4 | 5 | import org.greenrobot.greendao.AbstractDao; 6 | import org.greenrobot.greendao.AbstractDaoSession; 7 | import org.greenrobot.greendao.database.Database; 8 | import org.greenrobot.greendao.identityscope.IdentityScopeType; 9 | import org.greenrobot.greendao.internal.DaoConfig; 10 | 11 | import com.codingbingo.fastreader.dao.Book; 12 | import com.codingbingo.fastreader.dao.Chapter; 13 | 14 | import com.codingbingo.fastreader.dao.BookDao; 15 | import com.codingbingo.fastreader.dao.ChapterDao; 16 | 17 | // THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT. 18 | 19 | /** 20 | * {@inheritDoc} 21 | * 22 | * @see org.greenrobot.greendao.AbstractDaoSession 23 | */ 24 | public class DaoSession extends AbstractDaoSession { 25 | 26 | private final DaoConfig bookDaoConfig; 27 | private final DaoConfig chapterDaoConfig; 28 | 29 | private final BookDao bookDao; 30 | private final ChapterDao chapterDao; 31 | 32 | public DaoSession(Database db, IdentityScopeType type, Map>, DaoConfig> 33 | daoConfigMap) { 34 | super(db); 35 | 36 | bookDaoConfig = daoConfigMap.get(BookDao.class).clone(); 37 | bookDaoConfig.initIdentityScope(type); 38 | 39 | chapterDaoConfig = daoConfigMap.get(ChapterDao.class).clone(); 40 | chapterDaoConfig.initIdentityScope(type); 41 | 42 | bookDao = new BookDao(bookDaoConfig, this); 43 | chapterDao = new ChapterDao(chapterDaoConfig, this); 44 | 45 | registerDao(Book.class, bookDao); 46 | registerDao(Chapter.class, chapterDao); 47 | } 48 | 49 | public void clear() { 50 | bookDaoConfig.clearIdentityScope(); 51 | chapterDaoConfig.clearIdentityScope(); 52 | } 53 | 54 | public BookDao getBookDao() { 55 | return bookDao; 56 | } 57 | 58 | public ChapterDao getChapterDao() { 59 | return chapterDao; 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /app/src/main/java/com/codingbingo/fastreader/jni/FileProcessing.java: -------------------------------------------------------------------------------- 1 | package com.codingbingo.fastreader.jni; 2 | 3 | /** 4 | * Created by bingo on 2017/1/4. 5 | */ 6 | 7 | public class FileProcessing { 8 | 9 | 10 | static { 11 | System.loadLibrary("BookProcessing"); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /app/src/main/java/com/codingbingo/fastreader/manager/SettingManager.java: -------------------------------------------------------------------------------- 1 | package com.codingbingo.fastreader.manager; 2 | 3 | import com.codingbingo.fastreader.Constants; 4 | import com.codingbingo.fastreader.utils.SharedPreferenceUtils; 5 | 6 | /** 7 | * Author: bingo 8 | * Email: codingbingo@gmail.com 9 | * By 2017/2/14. 10 | */ 11 | 12 | public class SettingManager { 13 | 14 | private volatile static SettingManager instance; 15 | private SharedPreferenceUtils sharedPreferenceUtils; 16 | 17 | public static SettingManager getInstance() { 18 | if (instance == null) { 19 | synchronized (SettingManager.class) { 20 | if (instance == null) { 21 | instance = new SettingManager(); 22 | instance.sharedPreferenceUtils = SharedPreferenceUtils.getInstance(); 23 | } 24 | } 25 | } 26 | return instance; 27 | } 28 | 29 | public int getReadFontSize(){ 30 | return instance.sharedPreferenceUtils.getInt("fontSize", Constants.STYLE_NORMAL_FONT_SIZE); 31 | } 32 | 33 | public void setReadFontSize(int fontSize){ 34 | instance.sharedPreferenceUtils.putInt("fontSize", fontSize); 35 | } 36 | 37 | public boolean getReadMode(){ 38 | return instance.sharedPreferenceUtils.getBoolean("nightMode", false); 39 | } 40 | 41 | public void setReadMode(boolean value){ 42 | instance.sharedPreferenceUtils.putBoolean("nightMode", value); 43 | } 44 | 45 | public String getReadBackground(){ 46 | return instance.sharedPreferenceUtils.getString("readBackground", "#FFFFFF"); 47 | } 48 | 49 | public void setReadBackground(String color){ 50 | instance.sharedPreferenceUtils.putString("readBackground", color); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /app/src/main/java/com/codingbingo/fastreader/model/LocalFile.java: -------------------------------------------------------------------------------- 1 | package com.codingbingo.fastreader.model; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * Author: bingo 7 | * Email: codingbingo@gmail.com 8 | * By 2017/1/8. 9 | */ 10 | 11 | public class LocalFile implements Serializable{ 12 | private String fileName; 13 | private String filePath; 14 | private long fileSize; 15 | 16 | public String getFileName() { 17 | return fileName; 18 | } 19 | 20 | public void setFileName(String fileName) { 21 | this.fileName = fileName; 22 | } 23 | 24 | public String getFilePath() { 25 | return filePath; 26 | } 27 | 28 | public void setFilePath(String filePath) { 29 | this.filePath = filePath; 30 | } 31 | 32 | public long getFileSize() { 33 | return fileSize; 34 | } 35 | 36 | public void setFileSize(long fileSize) { 37 | this.fileSize = fileSize; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /app/src/main/java/com/codingbingo/fastreader/model/eventbus/BookReadProgressChangeEvent.java: -------------------------------------------------------------------------------- 1 | package com.codingbingo.fastreader.model.eventbus; 2 | 3 | /** 4 | * Author: bingo 5 | * Email: codingbingo@gmail.com 6 | * By 2017/4/18. 7 | */ 8 | 9 | public class BookReadProgressChangeEvent { 10 | private int progress; 11 | private long bookId; 12 | 13 | public BookReadProgressChangeEvent() { 14 | } 15 | 16 | public int getProgress() { 17 | return progress; 18 | } 19 | 20 | public void setProgress(int progress) { 21 | this.progress = progress; 22 | } 23 | 24 | public long getBookId() { 25 | return bookId; 26 | } 27 | 28 | public void setBookId(long bookId) { 29 | this.bookId = bookId; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /app/src/main/java/com/codingbingo/fastreader/model/eventbus/BookStatusChangeEvent.java: -------------------------------------------------------------------------------- 1 | package com.codingbingo.fastreader.model.eventbus; 2 | 3 | /** 4 | * Author: bingo 5 | * Email: codingbingo@gmail.com 6 | * By 2017/4/17. 7 | */ 8 | 9 | public class BookStatusChangeEvent { 10 | private int progress; 11 | private int status; 12 | private long bookId; 13 | 14 | public BookStatusChangeEvent() { 15 | } 16 | 17 | public BookStatusChangeEvent( int status, int progress,long bookId) { 18 | this.progress = progress; 19 | this.status = status; 20 | this.bookId = bookId; 21 | } 22 | 23 | public long getBookId() { 24 | return bookId; 25 | } 26 | 27 | public void setBookId(long bookId) { 28 | this.bookId = bookId; 29 | } 30 | 31 | public int getProgress() { 32 | return progress; 33 | } 34 | 35 | public void setProgress(int progress) { 36 | this.progress = progress; 37 | } 38 | 39 | public int getStatus() { 40 | return status; 41 | } 42 | 43 | public void setStatus(int status) { 44 | this.status = status; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /app/src/main/java/com/codingbingo/fastreader/model/eventbus/RefreshBookListEvent.java: -------------------------------------------------------------------------------- 1 | package com.codingbingo.fastreader.model.eventbus; 2 | 3 | /** 4 | * Author: bingo 5 | * Email: codingbingo@gmail.com 6 | * By 2017/4/8. 7 | * 刷新首页书籍列表事件 8 | */ 9 | 10 | public class RefreshBookListEvent { 11 | public RefreshBookListEvent() { 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /app/src/main/java/com/codingbingo/fastreader/model/eventbus/StyleChangeEvent.java: -------------------------------------------------------------------------------- 1 | package com.codingbingo.fastreader.model.eventbus; 2 | 3 | /** 4 | * Author: bingo 5 | * Email: codingbingo@gmail.com 6 | * By 2017/4/11. 7 | * 书籍样式改变事件 8 | */ 9 | 10 | public class StyleChangeEvent { 11 | public StyleChangeEvent() { 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /app/src/main/java/com/codingbingo/fastreader/ui/activity/LocalFileListActivity.java: -------------------------------------------------------------------------------- 1 | package com.codingbingo.fastreader.ui.activity; 2 | 3 | import android.Manifest; 4 | import android.content.Intent; 5 | import android.content.pm.PackageManager; 6 | import android.os.Build; 7 | import android.os.Bundle; 8 | import android.support.annotation.NonNull; 9 | import android.support.annotation.Nullable; 10 | import android.support.v4.app.ActivityCompat; 11 | import android.support.v4.content.ContextCompat; 12 | import android.support.v7.widget.LinearLayoutManager; 13 | import android.support.v7.widget.RecyclerView; 14 | import android.view.View; 15 | import android.widget.ImageView; 16 | 17 | import com.codingbingo.fastreader.Constants; 18 | import com.codingbingo.fastreader.R; 19 | import com.codingbingo.fastreader.base.BaseActivity; 20 | import com.codingbingo.fastreader.model.LocalFile; 21 | import com.codingbingo.fastreader.ui.adapter.FileListAdapter; 22 | import com.codingbingo.fastreader.utils.FileUtils; 23 | 24 | 25 | import java.util.List; 26 | 27 | /** 28 | * 本地文本列表 29 | * Author: bingo 30 | * Email: codingbingo@gmail.com 31 | * By 2017/1/5. 32 | */ 33 | 34 | public class LocalFileListActivity extends BaseActivity implements View.OnClickListener, FileListAdapter.OnItemClickListener{ 35 | 36 | private RecyclerView localFileListView; 37 | private ImageView backBtn; 38 | private ImageView reloadBtn; 39 | 40 | private List localFileList; 41 | private FileListAdapter localFileListAdapter; 42 | 43 | @Override 44 | protected void onCreate(@Nullable Bundle savedInstanceState) { 45 | super.onCreate(savedInstanceState); 46 | 47 | setContentView(R.layout.activity_local_file_list); 48 | 49 | initView(); 50 | } 51 | 52 | private void initView(){ 53 | localFileListView = (RecyclerView) findViewById(R.id.file_list); 54 | backBtn = (ImageView) findViewById(R.id.back_btn); 55 | reloadBtn = (ImageView) findViewById(R.id.reload_btn); 56 | 57 | backBtn.setOnClickListener(this); 58 | reloadBtn.setOnClickListener(this); 59 | ifNeedReadePermission(); 60 | } 61 | 62 | private void ifNeedReadePermission(){ 63 | // Here, thisActivity is the current activity 64 | if(Build.VERSION.SDK_INT >= 23) { 65 | if (ContextCompat.checkSelfPermission(LocalFileListActivity.this, 66 | Manifest.permission.READ_EXTERNAL_STORAGE) 67 | != PackageManager.PERMISSION_GRANTED) { 68 | 69 | // Should we show an explanation? 70 | if (ActivityCompat.shouldShowRequestPermissionRationale(LocalFileListActivity.this, 71 | Manifest.permission.READ_EXTERNAL_STORAGE)) { 72 | } else { 73 | ActivityCompat.requestPermissions(LocalFileListActivity.this, 74 | new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, 75 | Manifest.permission.WRITE_EXTERNAL_STORAGE}, 76 | 0); 77 | } 78 | } else { 79 | readLocalFiles(); 80 | } 81 | }else { 82 | readLocalFiles(); 83 | } 84 | } 85 | 86 | private void readLocalFiles(){ 87 | localFileList = FileUtils.getSupportFileList(this, new String[]{"txt"}); 88 | localFileListAdapter = new FileListAdapter(this, localFileList); 89 | localFileListAdapter.setOnItemClickListener(this); 90 | LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this); 91 | localFileListView.setLayoutManager(linearLayoutManager); 92 | localFileListView.setAdapter(localFileListAdapter); 93 | } 94 | 95 | @Override 96 | public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { 97 | switch (requestCode) { 98 | case 0: { 99 | // If request is cancelled, the result arrays are empty. 100 | if (grantResults.length > 0 101 | && grantResults[0] == PackageManager.PERMISSION_GRANTED) { 102 | readLocalFiles(); 103 | } 104 | return; 105 | } 106 | } 107 | super.onRequestPermissionsResult(requestCode, permissions, grantResults); 108 | } 109 | 110 | @Override 111 | public void onClick(View v) { 112 | int id = v.getId(); 113 | switch (id){ 114 | case R.id.back_btn: 115 | finish(); 116 | break; 117 | case R.id.reload_btn: 118 | synchronized (localFileList) { 119 | localFileList.clear(); 120 | localFileList.addAll(FileUtils.getSupportFileList(this, new String[]{"txt"})); 121 | localFileListAdapter.notifyDataSetChanged(); 122 | } 123 | break; 124 | default: 125 | break; 126 | } 127 | } 128 | 129 | @Override 130 | public void OnClick(int position) { 131 | LocalFile localFile = localFileList.get(position); 132 | 133 | Intent intent = new Intent(this, ReadingActivity.class); 134 | intent.putExtra("type", Constants.TYPE_FROM_LOCAL_FILE_ACTIVITY); 135 | intent.putExtra("bookPath", localFile.getFilePath()); 136 | startActivity(intent); 137 | //关闭当前activity 138 | finish(); 139 | } 140 | } 141 | 142 | -------------------------------------------------------------------------------- /app/src/main/java/com/codingbingo/fastreader/ui/activity/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.codingbingo.fastreader.ui.activity; 2 | 3 | import android.content.Intent; 4 | import android.graphics.Color; 5 | import android.graphics.drawable.ColorDrawable; 6 | import android.os.Bundle; 7 | import android.support.design.widget.CoordinatorLayout; 8 | import android.support.v4.widget.NestedScrollView; 9 | import android.support.v7.widget.GridLayoutManager; 10 | import android.support.v7.widget.RecyclerView; 11 | import android.view.Gravity; 12 | import android.view.View; 13 | import android.widget.ImageView; 14 | import android.widget.LinearLayout; 15 | import android.widget.PopupWindow; 16 | import android.widget.RelativeLayout; 17 | import android.widget.TextView; 18 | 19 | import com.codingbingo.fastreader.Constants; 20 | import com.codingbingo.fastreader.R; 21 | import com.codingbingo.fastreader.base.BaseActivity; 22 | import com.codingbingo.fastreader.dao.Book; 23 | import com.codingbingo.fastreader.dao.BookDao; 24 | import com.codingbingo.fastreader.model.eventbus.RefreshBookListEvent; 25 | import com.codingbingo.fastreader.ui.adapter.BookListAdapter; 26 | import com.codingbingo.fastreader.ui.fragment.MainControllerBottomSheetFragment; 27 | import com.codingbingo.fastreader.utils.ScreenUtils; 28 | 29 | import org.greenrobot.eventbus.EventBus; 30 | import org.greenrobot.eventbus.Subscribe; 31 | import org.greenrobot.eventbus.ThreadMode; 32 | 33 | import java.util.List; 34 | 35 | public class MainActivity extends BaseActivity implements 36 | NestedScrollView.OnScrollChangeListener, View.OnClickListener, 37 | BookListAdapter.OnBookListItemClickListener { 38 | 39 | private int normalTopPanelHeight = 0; 40 | private int totalChangeAlphaArea = 0; 41 | //titleBar的颜色0 表示默认白色,1表示灰色,2表示黑色 42 | private int titleBarColor = 0; 43 | 44 | private CoordinatorLayout activityMainLayout; 45 | private ImageView showMenuBtn; 46 | private ImageView goSearchBtn; 47 | private TextView titleText; 48 | private RecyclerView bookListView; 49 | private RelativeLayout bookListTopPanel; 50 | 51 | private NestedScrollView bookIndexScrollview; 52 | private RelativeLayout titleBarLayout; 53 | 54 | private View menuView; 55 | private PopupWindow menuPopupWindow; 56 | private LinearLayout addLocalFile; 57 | private LinearLayout about; 58 | private LinearLayout feedback; 59 | 60 | private BookListAdapter bookListAdapter; 61 | private List bookList; 62 | 63 | private BookDao mBookDao; 64 | 65 | @Override 66 | protected void onCreate(Bundle savedInstanceState) { 67 | super.onCreate(savedInstanceState); 68 | setContentView(R.layout.activity_main); 69 | 70 | init(); 71 | initView(); 72 | } 73 | 74 | @Override 75 | protected void onStart() { 76 | super.onStart(); 77 | if (EventBus.getDefault().isRegistered(this) == false) { 78 | EventBus.getDefault().register(this); 79 | } 80 | } 81 | 82 | @Override 83 | protected void onDestroy() { 84 | super.onDestroy(); 85 | if (EventBus.getDefault().isRegistered(this) == true) { 86 | EventBus.getDefault().unregister(this); 87 | } 88 | } 89 | 90 | private void init() { 91 | mBookDao = getDaoSession().getBookDao(); 92 | 93 | bookList = mBookDao.loadAll(); 94 | } 95 | 96 | private void initView() { 97 | activityMainLayout = (CoordinatorLayout) findViewById(R.id.activity_main); 98 | showMenuBtn = (ImageView) findViewById(R.id.show_menu_btn); 99 | goSearchBtn = (ImageView) findViewById(R.id.go_search_btn); 100 | titleText = (TextView) findViewById(R.id.title_text_view); 101 | bookIndexScrollview = (NestedScrollView) findViewById(R.id.book_index_scrollview); 102 | bookListView = (RecyclerView) findViewById(R.id.book_list); 103 | titleBarLayout = (RelativeLayout) findViewById(R.id.title_bar_layout); 104 | bookListTopPanel = (RelativeLayout) findViewById(R.id.book_list_top_panel); 105 | 106 | /* menu */ 107 | menuView = View.inflate(this, R.layout.main_menu, null); 108 | addLocalFile = (LinearLayout) menuView.findViewById(R.id.add_local_file); 109 | about = (LinearLayout) menuView.findViewById(R.id.about); 110 | feedback = (LinearLayout) menuView.findViewById(R.id.feedback); 111 | menuPopupWindow = new PopupWindow(menuView, CoordinatorLayout.LayoutParams.MATCH_PARENT, CoordinatorLayout.LayoutParams.WRAP_CONTENT); 112 | menuPopupWindow.setFocusable(true); 113 | menuPopupWindow.setBackgroundDrawable(new ColorDrawable(Color.argb(200, 81, 86, 88))); 114 | menuPopupWindow.setAnimationStyle(R.style.PopupAnimation); 115 | 116 | bookListAdapter = new BookListAdapter(this, bookList); 117 | //图书列表点击事件 118 | bookListAdapter.setOnBookListItemClickListener(this); 119 | bookListView.setLayoutManager(new GridLayoutManager(this, 3)); 120 | bookListView.setNestedScrollingEnabled(false); 121 | bookListView.setHasFixedSize(false); 122 | bookListView.setAdapter(bookListAdapter); 123 | 124 | float bookListViewHeight = getResources().getDisplayMetrics().heightPixels 125 | - ScreenUtils.getTitleBarHeight(this) 126 | - ScreenUtils.getStatusBarHeight(this); 127 | bookListView.setMinimumHeight((int) bookListViewHeight); 128 | //保证展示图书列表顶部区域 129 | bookIndexScrollview.smoothScrollTo(0, 0); 130 | 131 | //获取正常情况下,顶部区域的高度 132 | normalTopPanelHeight = ScreenUtils.dp2px(this, 200); 133 | totalChangeAlphaArea = normalTopPanelHeight - ScreenUtils.getTitleBarHeight(this); 134 | 135 | initViewListener(); 136 | } 137 | 138 | private void initViewListener() { 139 | bookIndexScrollview.setOnScrollChangeListener(this); 140 | showMenuBtn.setOnClickListener(this); 141 | goSearchBtn.setOnClickListener(this); 142 | 143 | addLocalFile.setOnClickListener(this); 144 | feedback.setOnClickListener(this); 145 | about.setOnClickListener(this); 146 | } 147 | 148 | /** 149 | * 根据滑动动态调整颜色 150 | */ 151 | private void changeTitleBarLayout(int scrollY) { 152 | float currentDis = totalChangeAlphaArea - scrollY; 153 | int value = (int) ((255 - currentDis * 255 * 1.0 / totalChangeAlphaArea)); 154 | titleBarLayout.getBackground().setAlpha(value > 255 ? 255 : value); 155 | if (value < 160 && titleBarColor != 0) { 156 | showMenuBtn.setImageResource(R.drawable.menu_icon_white); 157 | goSearchBtn.setImageResource(R.drawable.search_icon_white); 158 | titleText.setTextColor(getResources().getColor(R.color.white)); 159 | 160 | titleBarColor = 0; 161 | } else if (160 < value && value < 200 && titleBarColor != 1) { 162 | showMenuBtn.setImageResource(R.drawable.menu_icon_grey); 163 | goSearchBtn.setImageResource(R.drawable.search_icon_grey); 164 | titleText.setTextColor(getResources().getColor(R.color.grey)); 165 | 166 | titleBarColor = 1; 167 | } else if (200 < value && titleBarColor != 2) { 168 | showMenuBtn.setImageResource(R.drawable.menu_icon_black); 169 | goSearchBtn.setImageResource(R.drawable.search_icon_black); 170 | titleText.setTextColor(getResources().getColor(R.color.black)); 171 | 172 | titleBarColor = 2; 173 | } 174 | } 175 | 176 | @Override 177 | public void onBookItemClick(Book book, int position) { 178 | if (book == null) { 179 | //添加书籍 180 | Intent intent = new Intent(MainActivity.this, LocalFileListActivity.class); 181 | startActivity(intent); 182 | } else { 183 | Intent intent = new Intent(MainActivity.this, ReadingActivity.class); 184 | intent.putExtra("type", Constants.TYPE_FROM_MAIN_ACTIVITY); 185 | intent.putExtra("bookId", book.getId()); 186 | startActivity(intent); 187 | } 188 | } 189 | 190 | @Override 191 | public void onBookItemLongClick(Book book, int position) { 192 | MainControllerBottomSheetFragment mainControllerBottomSheetFragment = new MainControllerBottomSheetFragment(); 193 | mainControllerBottomSheetFragment.setBook(book); 194 | mainControllerBottomSheetFragment.show(getSupportFragmentManager(), "Dialog"); 195 | } 196 | 197 | @Override 198 | public void onClick(View v) { 199 | int id = v.getId(); 200 | switch (id) { 201 | case R.id.show_menu_btn: 202 | menuPopupWindow.showAtLocation(activityMainLayout, Gravity.TOP, 0, 0); 203 | break; 204 | case R.id.go_search_btn: 205 | break; 206 | case R.id.add_local_file: 207 | Intent intent = new Intent(this, LocalFileListActivity.class); 208 | startActivity(intent); 209 | menuPopupWindow.dismiss(); 210 | break; 211 | case R.id.about: 212 | break; 213 | case R.id.feedback: 214 | break; 215 | } 216 | } 217 | 218 | @Override 219 | public void onScrollChange(NestedScrollView v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) { 220 | changeTitleBarLayout(scrollY); 221 | } 222 | 223 | @Subscribe(threadMode = ThreadMode.MAIN) 224 | public void onEvent(RefreshBookListEvent refreshBookListEvent){ 225 | bookList.clear(); 226 | bookList.addAll(mBookDao.loadAll()); 227 | bookListAdapter.notifyDataSetChanged(); 228 | } 229 | } 230 | -------------------------------------------------------------------------------- /app/src/main/java/com/codingbingo/fastreader/ui/activity/ReadingActivity.java: -------------------------------------------------------------------------------- 1 | package com.codingbingo.fastreader.ui.activity; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import android.support.annotation.Nullable; 6 | import android.view.KeyEvent; 7 | import android.view.View; 8 | import android.view.WindowManager; 9 | 10 | import com.codingbingo.fastreader.Constants; 11 | import com.codingbingo.fastreader.R; 12 | import com.codingbingo.fastreader.base.BaseActivity; 13 | import com.codingbingo.fastreader.dao.Book; 14 | import com.codingbingo.fastreader.dao.BookDao; 15 | import com.codingbingo.fastreader.ui.fragment.ChapterListFragment; 16 | import com.codingbingo.fastreader.ui.fragment.ReadingFragment; 17 | 18 | import java.util.List; 19 | 20 | 21 | /** 22 | * Author: bingo 23 | * Email: codingbingo@gmail.com 24 | * By 2017/1/11. 25 | */ 26 | 27 | public class ReadingActivity extends BaseActivity implements View.OnClickListener { 28 | private ChapterListFragment mChapterListFragment; 29 | private ReadingFragment mReadingFragment; 30 | 31 | private long bookId = NO_BOOK_ID; 32 | private String bookPath; 33 | 34 | @Override 35 | protected void onCreate(@Nullable Bundle savedInstanceState) { 36 | super.onCreate(savedInstanceState); 37 | //进入activity,先进入全屏状态 38 | WindowManager.LayoutParams params = getWindow().getAttributes(); 39 | params.flags |= WindowManager.LayoutParams.FLAG_FULLSCREEN; 40 | getWindow().setAttributes(params); 41 | getWindow().addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS); 42 | 43 | setContentView(R.layout.activity_reading); 44 | 45 | 46 | init(); 47 | initView(); 48 | } 49 | 50 | private void init() { 51 | Intent intent = getIntent(); 52 | if (intent.hasExtra("type") == false) { 53 | finish(); 54 | return; 55 | } 56 | 57 | switch (intent.getIntExtra("type", Constants.TYPE_FROM_MAIN_ACTIVITY)) { 58 | case Constants.TYPE_FROM_MAIN_ACTIVITY: 59 | //从主页面进来的,说明本地数据已经插入数据库了 60 | bookId = intent.getLongExtra("bookId", 0); 61 | break; 62 | case Constants.TYPE_FROM_LOCAL_FILE_ACTIVITY: 63 | bookPath = intent.getStringExtra("bookPath"); 64 | //防止用户再从文件列表页点击进入 65 | List bookList = getDaoSession().getBookDao().queryBuilder().where(BookDao.Properties.BookPath.eq(bookPath)).list(); 66 | if (bookList.size() != 0) { 67 | bookId = bookList.get(0).getId(); 68 | break; 69 | } 70 | } 71 | } 72 | 73 | private void initView() { 74 | mReadingFragment = new ReadingFragment(); 75 | mReadingFragment.setBookId(bookId); 76 | mReadingFragment.setBookPath(bookPath); 77 | mReadingFragment.setOnClickListener(this); 78 | 79 | mChapterListFragment = new ChapterListFragment(); 80 | mChapterListFragment.setBookId(bookId); 81 | mChapterListFragment.setBookPath(bookPath); 82 | 83 | if (mReadingFragment.isAdded()){ 84 | getFragmentManager() 85 | .beginTransaction() 86 | .show(mReadingFragment) 87 | .commitAllowingStateLoss(); 88 | } else{ 89 | getFragmentManager() 90 | .beginTransaction() 91 | .add(R.id.reading_container, mReadingFragment) 92 | .commitAllowingStateLoss(); 93 | } 94 | } 95 | 96 | @Override 97 | public void onClick(View v) { 98 | int id = v.getId(); 99 | switch (id) { 100 | case R.id.backBtn: 101 | finish(); 102 | break; 103 | case R.id.book_contents: 104 | getFragmentManager() 105 | .beginTransaction() 106 | .replace(R.id.reading_container, mChapterListFragment) 107 | .addToBackStack(null) 108 | .commitAllowingStateLoss(); 109 | break; 110 | } 111 | } 112 | 113 | @Override 114 | public boolean onKeyDown(int keyCode, KeyEvent event) { 115 | if (mReadingFragment.isHidden() == false) { 116 | if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) { 117 | mReadingFragment.nextPage(); 118 | return true; 119 | } else if (keyCode == KeyEvent.KEYCODE_VOLUME_UP) { 120 | mReadingFragment.prePage(); 121 | return true; 122 | } 123 | } 124 | return super.onKeyDown(keyCode, event); 125 | } 126 | 127 | 128 | } 129 | -------------------------------------------------------------------------------- /app/src/main/java/com/codingbingo/fastreader/ui/adapter/BookListAdapter.java: -------------------------------------------------------------------------------- 1 | package com.codingbingo.fastreader.ui.adapter; 2 | 3 | import android.content.Context; 4 | import android.support.v7.widget.RecyclerView; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.ImageView; 9 | import android.widget.TextView; 10 | 11 | import com.codingbingo.fastreader.R; 12 | import com.codingbingo.fastreader.dao.Book; 13 | import com.codingbingo.fastreader.utils.StringUtils; 14 | 15 | import java.util.List; 16 | 17 | /** 18 | * Created by bingo on 2016/12/21. 19 | */ 20 | 21 | public class BookListAdapter extends RecyclerView.Adapter { 22 | 23 | private static final int VIEW_TYPE_ADD_BOOK = 1; 24 | private static final int VIEW_TYPE_NORMAL = 2; 25 | 26 | private Context mContext; 27 | private List bookList; 28 | private OnBookListItemClickListener onBookListItemClickListener; 29 | 30 | public BookListAdapter(Context mContext, List bookList) { 31 | this.mContext = mContext; 32 | this.bookList = bookList; 33 | } 34 | 35 | class BookViewHolder extends RecyclerView.ViewHolder { 36 | 37 | private ImageView novelImage; 38 | private TextView novelTag; 39 | private TextView novelTitle; 40 | 41 | public BookViewHolder(View itemView) { 42 | super(itemView); 43 | 44 | novelImage = (ImageView) itemView.findViewById(R.id.novel_image); 45 | novelTag = (TextView) itemView.findViewById(R.id.novel_tag); 46 | novelTitle = (TextView) itemView.findViewById(R.id.novel_title); 47 | 48 | } 49 | } 50 | 51 | public void setOnBookListItemClickListener(OnBookListItemClickListener onBookListItemClickListener) { 52 | this.onBookListItemClickListener = onBookListItemClickListener; 53 | } 54 | 55 | @Override 56 | public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 57 | View view = LayoutInflater.from(mContext).inflate(R.layout.book_list_item, null); 58 | RecyclerView.ViewHolder viewHolder = new BookViewHolder(view); 59 | return viewHolder; 60 | } 61 | 62 | @Override 63 | public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) { 64 | if (getItemViewType(position) == VIEW_TYPE_NORMAL) { 65 | BookViewHolder bookViewHolder = (BookViewHolder) holder; 66 | 67 | Book book = bookList.get(position); 68 | 69 | String bookName; 70 | String bookTag; 71 | 72 | String fileName = book.getBookName(); 73 | if (fileName.contains(".")) { 74 | String[] s = fileName.split("\\."); 75 | if (s.length == 0) { 76 | bookName = fileName; 77 | bookTag = ""; 78 | } else { 79 | bookName = s[0]; 80 | if (s.length - 1 >= 0) { 81 | bookTag = s[s.length - 1]; 82 | }else{ 83 | bookTag = ""; 84 | } 85 | } 86 | } else { 87 | bookName = fileName; 88 | bookTag = ""; 89 | } 90 | bookViewHolder.novelTitle.setText(bookName); 91 | bookViewHolder.novelTag.setText(bookTag.toUpperCase()); 92 | 93 | if (StringUtils.isBlank(book.getBookImagePath())) { 94 | bookViewHolder.novelImage.setBackgroundColor(mContext.getResources().getColor(R.color.default_book_bg)); 95 | } else { 96 | //加载 97 | } 98 | 99 | holder.itemView.setOnLongClickListener(new View.OnLongClickListener() { 100 | @Override 101 | public boolean onLongClick(View v) { 102 | if (onBookListItemClickListener != null) { 103 | onBookListItemClickListener.onBookItemLongClick(bookList.get(position), position); 104 | return true; 105 | } else { 106 | return false; 107 | } 108 | } 109 | }); 110 | } 111 | 112 | holder.itemView.setOnClickListener(new View.OnClickListener() { 113 | @Override 114 | public void onClick(View v) { 115 | if (onBookListItemClickListener != null) { 116 | if (getItemViewType(position) == VIEW_TYPE_NORMAL) { 117 | onBookListItemClickListener.onBookItemClick(bookList.get(position), position); 118 | } else if (getItemViewType(position) == VIEW_TYPE_ADD_BOOK) { 119 | onBookListItemClickListener.onBookItemClick(null, position); 120 | } 121 | } 122 | } 123 | }); 124 | } 125 | 126 | @Override 127 | public int getItemViewType(int position) { 128 | if (getItemCount() - 1 == position) { 129 | return VIEW_TYPE_ADD_BOOK; 130 | } else { 131 | return VIEW_TYPE_NORMAL; 132 | } 133 | } 134 | 135 | @Override 136 | public int getItemCount() { 137 | return bookList.size() + 1; 138 | } 139 | 140 | /** 141 | * 142 | */ 143 | public interface OnBookListItemClickListener { 144 | void onBookItemClick(Book book, int position); 145 | void onBookItemLongClick(Book book, int position); 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /app/src/main/java/com/codingbingo/fastreader/ui/adapter/ChapterListAdapter.java: -------------------------------------------------------------------------------- 1 | package com.codingbingo.fastreader.ui.adapter; 2 | 3 | import android.content.Context; 4 | import android.graphics.Typeface; 5 | import android.support.v7.widget.RecyclerView; 6 | import android.view.LayoutInflater; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | import android.widget.TextView; 10 | 11 | import com.codingbingo.fastreader.R; 12 | import com.codingbingo.fastreader.dao.Chapter; 13 | import com.codingbingo.fastreader.ui.listener.OnChapterClickListener; 14 | 15 | import java.util.List; 16 | 17 | /** 18 | * Author: bingo 19 | * Email: codingbingo@gmail.com 20 | * By 2017/4/8. 21 | */ 22 | 23 | public class ChapterListAdapter extends RecyclerView.Adapter { 24 | 25 | private Context mContext; 26 | private List chapterList; 27 | private int mCurrentChapter; 28 | 29 | private OnChapterClickListener onChapterClickListener; 30 | 31 | public ChapterListAdapter(Context mContext, List chapterList, int mCurrentChapter) { 32 | this.mContext = mContext; 33 | this.chapterList = chapterList; 34 | this.mCurrentChapter = mCurrentChapter; 35 | } 36 | 37 | public void setmCurrentChapter(int mCurrentChapter) { 38 | this.mCurrentChapter = mCurrentChapter; 39 | } 40 | 41 | public void setOnChapterClickListener(OnChapterClickListener onChapterClickListener) { 42 | this.onChapterClickListener = onChapterClickListener; 43 | } 44 | 45 | @Override 46 | public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 47 | View itemView = LayoutInflater.from(mContext).inflate(R.layout.chapter_list_item, parent, false); 48 | return new ViewHolder(itemView); 49 | } 50 | 51 | @Override 52 | public void onBindViewHolder(ViewHolder holder, final int position) { 53 | Chapter chapter = chapterList.get(position); 54 | 55 | holder.chapterTitle.setText(chapter.getTitle()); 56 | if (position == mCurrentChapter) { 57 | holder.chapterCurrent.setVisibility(View.VISIBLE); 58 | holder.chapterTitle.setTypeface(null, Typeface.BOLD); 59 | } else { 60 | holder.chapterCurrent.setVisibility(View.INVISIBLE); 61 | holder.chapterTitle.setTypeface(null, Typeface.NORMAL); 62 | } 63 | 64 | holder.itemView.setOnClickListener(new View.OnClickListener() { 65 | @Override 66 | public void onClick(View v) { 67 | if (onChapterClickListener != null) { 68 | onChapterClickListener.onChapterClick(position); 69 | } 70 | } 71 | }); 72 | 73 | } 74 | 75 | @Override 76 | public int getItemCount() { 77 | return chapterList.size(); 78 | } 79 | 80 | class ViewHolder extends RecyclerView.ViewHolder { 81 | public View chapterCurrent; 82 | public TextView chapterTitle; 83 | 84 | public ViewHolder(View itemView) { 85 | super(itemView); 86 | 87 | chapterCurrent = itemView.findViewById(R.id.chapter_current); 88 | chapterTitle = (TextView) itemView.findViewById(R.id.chapter_title); 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /app/src/main/java/com/codingbingo/fastreader/ui/adapter/FileListAdapter.java: -------------------------------------------------------------------------------- 1 | package com.codingbingo.fastreader.ui.adapter; 2 | 3 | import android.content.Context; 4 | import android.support.v7.widget.RecyclerView; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.ImageView; 9 | import android.widget.TextView; 10 | 11 | import com.codingbingo.fastreader.R; 12 | import com.codingbingo.fastreader.model.LocalFile; 13 | 14 | import org.greenrobot.greendao.annotation.NotNull; 15 | 16 | import java.util.List; 17 | 18 | /** 19 | * Author: bingo 20 | * Email: codingbingo@gmail.com 21 | * By 2017/1/6. 22 | */ 23 | 24 | public class FileListAdapter extends RecyclerView.Adapter { 25 | 26 | private Context mContext; 27 | private List localFileList; 28 | 29 | private OnItemClickListener onItemClickListener; 30 | 31 | public FileListAdapter(Context mContext, @NotNull List localFileList) { 32 | this.mContext = mContext; 33 | this.localFileList = localFileList; 34 | } 35 | 36 | public void setOnItemClickListener(OnItemClickListener onItemClickListener) { 37 | this.onItemClickListener = onItemClickListener; 38 | } 39 | 40 | public class FileHolder extends RecyclerView.ViewHolder{ 41 | private TextView fileName; 42 | private ImageView fileIcon; 43 | private TextView fileSize; 44 | 45 | public FileHolder(View itemView) { 46 | super(itemView); 47 | 48 | fileIcon = (ImageView) itemView.findViewById(R.id.file_icon); 49 | fileSize = (TextView) itemView.findViewById(R.id.file_size); 50 | fileName = (TextView) itemView.findViewById(R.id.file_name); 51 | } 52 | } 53 | 54 | @Override 55 | public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 56 | View fileItemView = LayoutInflater.from(mContext).inflate(R.layout.file_item, null); 57 | FileHolder fileHolder = new FileHolder(fileItemView); 58 | return fileHolder; 59 | } 60 | 61 | @Override 62 | public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) { 63 | LocalFile localFile = localFileList.get(position); 64 | 65 | FileHolder fileHolder = (FileHolder) holder; 66 | fileHolder.fileName.setText(localFile.getFileName()); 67 | fileHolder.fileSize.setText(localFile.getFileSize() * 1.0 / 1000 + " KB"); 68 | 69 | fileHolder.itemView.setOnClickListener(new View.OnClickListener() { 70 | @Override 71 | public void onClick(View v) { 72 | if (onItemClickListener != null){ 73 | onItemClickListener.OnClick(position); 74 | } 75 | } 76 | }); 77 | } 78 | 79 | @Override 80 | public int getItemCount() { 81 | if (localFileList != null) { 82 | return localFileList.size(); 83 | }else{ 84 | return 0; 85 | } 86 | } 87 | 88 | public interface OnItemClickListener{ 89 | void OnClick(int position); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /app/src/main/java/com/codingbingo/fastreader/ui/adapter/ReadingBackgroundAdapter.java: -------------------------------------------------------------------------------- 1 | package com.codingbingo.fastreader.ui.adapter; 2 | 3 | import android.content.Context; 4 | import android.graphics.Color; 5 | import android.graphics.drawable.GradientDrawable; 6 | import android.support.v7.widget.RecyclerView; 7 | import android.view.LayoutInflater; 8 | import android.view.View; 9 | import android.view.ViewGroup; 10 | 11 | import com.codingbingo.fastreader.R; 12 | import com.codingbingo.fastreader.manager.SettingManager; 13 | import com.codingbingo.fastreader.model.eventbus.StyleChangeEvent; 14 | 15 | import org.greenrobot.eventbus.EventBus; 16 | 17 | import java.util.List; 18 | 19 | /** 20 | * Author: bingo 21 | * Email: codingbingo@gmail.com 22 | * By 2017/4/12. 23 | *

24 | * 阅读背景设置 25 | */ 26 | 27 | public class ReadingBackgroundAdapter extends RecyclerView.Adapter { 28 | 29 | private Context mContext; 30 | private List backgroundColorList; 31 | 32 | public ReadingBackgroundAdapter(Context mContext, List backgroundColorList) { 33 | this.mContext = mContext; 34 | this.backgroundColorList = backgroundColorList; 35 | } 36 | 37 | @Override 38 | public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 39 | View view = LayoutInflater.from(mContext).inflate(R.layout.read_background_item, parent, false); 40 | return new ViewHolder(view); 41 | } 42 | 43 | @Override 44 | public void onBindViewHolder(ViewHolder holder, int position) { 45 | GradientDrawable gradientDrawable = (GradientDrawable) holder.readBackgroundColor.getBackground(); 46 | final String color = backgroundColorList.get(position); 47 | gradientDrawable.setColor(Color.parseColor(color)); 48 | 49 | holder.itemView.setOnClickListener(new View.OnClickListener() { 50 | @Override 51 | public void onClick(View v) { 52 | SettingManager.getInstance().setReadMode(false); 53 | SettingManager.getInstance().setReadBackground(color); 54 | 55 | EventBus.getDefault().post(new StyleChangeEvent()); 56 | } 57 | }); 58 | } 59 | 60 | @Override 61 | public int getItemCount() { 62 | return backgroundColorList.size(); 63 | } 64 | 65 | class ViewHolder extends RecyclerView.ViewHolder{ 66 | View readBackgroundColor; 67 | 68 | public ViewHolder(View itemView) { 69 | super(itemView); 70 | 71 | readBackgroundColor = itemView.findViewById(R.id.read_background_color); 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /app/src/main/java/com/codingbingo/fastreader/ui/fragment/ChapterListFragment.java: -------------------------------------------------------------------------------- 1 | package com.codingbingo.fastreader.ui.fragment; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.Nullable; 5 | import android.support.v7.widget.LinearLayoutManager; 6 | import android.support.v7.widget.RecyclerView; 7 | import android.view.LayoutInflater; 8 | import android.view.View; 9 | import android.view.ViewGroup; 10 | import android.widget.ImageView; 11 | import android.widget.ListAdapter; 12 | 13 | import com.codingbingo.fastreader.Constants; 14 | import com.codingbingo.fastreader.R; 15 | import com.codingbingo.fastreader.base.BaseActivity; 16 | import com.codingbingo.fastreader.base.BaseFragment; 17 | import com.codingbingo.fastreader.dao.Book; 18 | import com.codingbingo.fastreader.dao.BookDao; 19 | import com.codingbingo.fastreader.dao.Chapter; 20 | import com.codingbingo.fastreader.dao.ChapterDao; 21 | import com.codingbingo.fastreader.model.eventbus.BookStatusChangeEvent; 22 | import com.codingbingo.fastreader.ui.activity.ReadingActivity; 23 | import com.codingbingo.fastreader.ui.adapter.ChapterListAdapter; 24 | import com.codingbingo.fastreader.ui.listener.OnChapterClickListener; 25 | import com.codingbingo.fastreader.utils.SimpleDividerItemDecoration; 26 | 27 | import org.greenrobot.eventbus.EventBus; 28 | import org.greenrobot.eventbus.Subscribe; 29 | import org.greenrobot.eventbus.ThreadMode; 30 | 31 | import java.util.ArrayList; 32 | import java.util.List; 33 | 34 | /** 35 | * Author: bingo 36 | * Email: codingbingo@gmail.com 37 | * By 2017/3/30. 38 | */ 39 | 40 | public class ChapterListFragment extends BaseFragment implements View.OnClickListener, OnChapterClickListener { 41 | 42 | private RecyclerView mChapterListView; 43 | private ChapterListAdapter mChapterListAdapter; 44 | private ImageView mBackBtn; 45 | 46 | private String bookPath; 47 | private long bookId; 48 | private List mChapterList; 49 | private int mCurrentChapter; 50 | 51 | public ChapterListFragment() { 52 | } 53 | 54 | public void setBookId(long bookId) { 55 | this.bookId = bookId; 56 | 57 | if (mChapterList == null){ 58 | mChapterList = new ArrayList<>(); 59 | } 60 | if (mChapterList.size() == 0) { 61 | mChapterList.addAll(getDaoSession() 62 | .getChapterDao() 63 | .queryBuilder() 64 | .where(ChapterDao.Properties.BookId.eq(bookId)).list()); 65 | } 66 | if (getDaoSession().getBookDao().load(bookId) != null) { 67 | mCurrentChapter = getDaoSession().getBookDao().load(bookId).getCurrentChapter(); 68 | } else { 69 | mCurrentChapter = 0; 70 | } 71 | 72 | if (mChapterListAdapter != null){ 73 | mChapterListAdapter.setmCurrentChapter(mCurrentChapter); 74 | mChapterListAdapter.notifyDataSetChanged(); 75 | mChapterListView.scrollToPosition(mCurrentChapter); 76 | } 77 | } 78 | 79 | public void setBookPath(String bookPath) { 80 | this.bookPath = bookPath; 81 | } 82 | 83 | @Override 84 | public String getFragmentName() { 85 | return getClass().getSimpleName(); 86 | } 87 | 88 | @Nullable 89 | @Override 90 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) { 91 | View view = inflater.inflate(R.layout.fragment_chapter_list, null); 92 | 93 | switchFullScreen(true); 94 | 95 | initView(view); 96 | 97 | return view; 98 | } 99 | 100 | @Override 101 | public void onResume() { 102 | super.onResume(); 103 | 104 | if (bookId == BaseActivity.NO_BOOK_ID){ 105 | List bookList = getDaoSession().getBookDao().queryBuilder().where(BookDao.Properties.BookPath.eq(bookPath)).list(); 106 | if (bookList.size() > 0){ 107 | bookId = bookList.get(0).getId(); 108 | } 109 | } 110 | 111 | setBookId(bookId); 112 | } 113 | 114 | private void initView(View view) { 115 | mChapterListView = (RecyclerView) view.findViewById(R.id.chapter_list); 116 | mBackBtn = (ImageView) view.findViewById(R.id.back_btn); 117 | 118 | mChapterList = getDaoSession().getChapterDao().queryBuilder().where(ChapterDao.Properties.BookId.eq(bookId)).list();//初始化list 119 | if (mChapterList == null){ 120 | mChapterList = new ArrayList<>(); 121 | } 122 | mChapterListAdapter = new ChapterListAdapter(getActivity(), mChapterList, mCurrentChapter); 123 | mChapterListAdapter.setOnChapterClickListener(this); 124 | mChapterListView.setLayoutManager(new LinearLayoutManager(getActivity())); 125 | mChapterListView.addItemDecoration(new SimpleDividerItemDecoration(getActivity())); 126 | mChapterListView.setAdapter(mChapterListAdapter); 127 | //滑动到当前章节 128 | mChapterListView.scrollToPosition(mCurrentChapter); 129 | 130 | mBackBtn.setOnClickListener(this); 131 | } 132 | 133 | @Override 134 | public void onClick(View v) { 135 | switch (v.getId()){ 136 | case R.id.back_btn: 137 | getFragmentManager().popBackStack(); 138 | break; 139 | } 140 | } 141 | 142 | @Override 143 | public void onChapterClick(int chapter) { 144 | mCurrentChapter = chapter; 145 | 146 | Book book = getDaoSession().getBookDao().load(bookId); 147 | book.setCurrentChapter(chapter); 148 | book.setCurrentPosition(mChapterList.get(chapter).getPosition()); 149 | getDaoSession().getBookDao().update(book); 150 | 151 | EventBus.getDefault().post(new BookStatusChangeEvent(Constants.BOOK_PROCESSED, 100, bookId)); 152 | getFragmentManager().popBackStack(); 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /app/src/main/java/com/codingbingo/fastreader/ui/fragment/MainControllerBottomSheetFragment.java: -------------------------------------------------------------------------------- 1 | package com.codingbingo.fastreader.ui.fragment; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.Nullable; 5 | import android.support.design.widget.BottomSheetDialogFragment; 6 | import android.view.LayoutInflater; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | import android.widget.RelativeLayout; 10 | import android.widget.TextView; 11 | 12 | import com.codingbingo.fastreader.FRApplication; 13 | import com.codingbingo.fastreader.R; 14 | import com.codingbingo.fastreader.dao.Book; 15 | import com.codingbingo.fastreader.dao.BookDao; 16 | import com.codingbingo.fastreader.dao.Chapter; 17 | import com.codingbingo.fastreader.dao.ChapterDao; 18 | import com.codingbingo.fastreader.dao.DaoSession; 19 | import com.codingbingo.fastreader.model.eventbus.RefreshBookListEvent; 20 | 21 | import org.greenrobot.eventbus.EventBus; 22 | 23 | import java.util.List; 24 | 25 | /** 26 | * Author: bingo 27 | * Email: codingbingo@gmail.com 28 | * By 2017/4/18. 29 | */ 30 | 31 | public class MainControllerBottomSheetFragment extends BottomSheetDialogFragment { 32 | 33 | private Book book; 34 | private DaoSession mDaoSession; 35 | 36 | public MainControllerBottomSheetFragment() { 37 | mDaoSession = FRApplication.getInstance().getDaoSession(); 38 | } 39 | 40 | public void setBook(Book book) { 41 | this.book = book; 42 | } 43 | 44 | @Nullable 45 | @Override 46 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 47 | View view = inflater.inflate(R.layout.bottom_sheet_dialog_fragment, container, false); 48 | 49 | initView(view); 50 | 51 | return view; 52 | } 53 | 54 | private void initView(View view){ 55 | TextView novelTitle = (TextView) view.findViewById(R.id.novel_title); 56 | novelTitle.setText(book.getBookName()); 57 | 58 | RelativeLayout deleteLayout = (RelativeLayout) view.findViewById(R.id.delete); 59 | deleteLayout.setOnClickListener(new View.OnClickListener() { 60 | @Override 61 | public void onClick(View v) { 62 | List chapterList = mDaoSession.getChapterDao().queryBuilder().where(ChapterDao.Properties.BookId.eq(book.getId())).list(); 63 | mDaoSession.getChapterDao().deleteInTx(chapterList); 64 | //删除书籍 65 | mDaoSession.getBookDao().delete(book); 66 | 67 | EventBus.getDefault().post(new RefreshBookListEvent()); 68 | 69 | dismiss(); 70 | } 71 | }); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /app/src/main/java/com/codingbingo/fastreader/ui/fragment/ReadingFragment.java: -------------------------------------------------------------------------------- 1 | package com.codingbingo.fastreader.ui.fragment; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.Nullable; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.SeekBar; 9 | 10 | import com.avos.avoscloud.LogUtil; 11 | import com.codingbingo.fastreader.Constants; 12 | import com.codingbingo.fastreader.R; 13 | import com.codingbingo.fastreader.base.BaseActivity; 14 | import com.codingbingo.fastreader.base.BaseFragment; 15 | import com.codingbingo.fastreader.dao.Book; 16 | import com.codingbingo.fastreader.dao.BookDao; 17 | import com.codingbingo.fastreader.dao.Chapter; 18 | import com.codingbingo.fastreader.dao.ChapterDao; 19 | import com.codingbingo.fastreader.model.eventbus.BookStatusChangeEvent; 20 | import com.codingbingo.fastreader.ui.activity.ReadingActivity; 21 | import com.codingbingo.fastreader.ui.listener.OnReadChapterProgressListener; 22 | import com.codingbingo.fastreader.view.loadingview.CatLoadingView; 23 | import com.codingbingo.fastreader.view.readview.PageWidget; 24 | import com.codingbingo.fastreader.view.readview.ReadController; 25 | import com.codingbingo.fastreader.view.readview.interfaces.OnControllerStatusChangeListener; 26 | 27 | import org.greenrobot.eventbus.EventBus; 28 | import org.greenrobot.eventbus.Subscribe; 29 | import org.greenrobot.eventbus.ThreadMode; 30 | 31 | import java.util.List; 32 | 33 | /** 34 | * Author: bingo 35 | * Email: codingbingo@gmail.com 36 | * By 2017/3/30. 37 | */ 38 | 39 | public class ReadingFragment extends BaseFragment implements OnControllerStatusChangeListener, OnReadChapterProgressListener { 40 | 41 | private PageWidget readPageWidget; 42 | private ReadController readController; 43 | private CatLoadingView readLoadingView; 44 | 45 | private View.OnClickListener onClickListener; 46 | 47 | private long bookId; 48 | private String bookPath; 49 | 50 | private Book mBook; 51 | private List mChapterList; 52 | 53 | @Override 54 | public String getFragmentName() { 55 | return ReadingFragment.class.getSimpleName(); 56 | } 57 | 58 | @Nullable 59 | @Override 60 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) { 61 | View view = inflater.inflate(R.layout.fragment_reading, container, false); 62 | 63 | initView(view); 64 | return view; 65 | } 66 | 67 | public void setBookId(long bookId) { 68 | this.bookId = bookId; 69 | } 70 | 71 | public void setBookPath(String bookPath) { 72 | this.bookPath = bookPath; 73 | } 74 | 75 | public void setOnClickListener(View.OnClickListener onClickListener) { 76 | this.onClickListener = onClickListener; 77 | } 78 | 79 | private void initView(View view) { 80 | readController = (ReadController) view.findViewById(R.id.readController); 81 | readController.setOnControllerStatusChangeListener(this); 82 | if (onClickListener != null) { 83 | readController.setOnViewClickListener(onClickListener); 84 | } 85 | 86 | readPageWidget = (PageWidget) view.findViewById(R.id.readPageWidget); 87 | //bookId判断书籍状态种类 88 | if (BaseActivity.NO_BOOK_ID != bookId) { 89 | readPageWidget.setBookId(bookId, false); 90 | mBook = getDaoSession().getBookDao().load(bookId); 91 | } else { 92 | List bookList = getDaoSession() 93 | .getBookDao() 94 | .queryBuilder() 95 | .where(BookDao.Properties.BookPath.eq(bookPath)) 96 | .list(); 97 | if (bookList.size() == 0) { 98 | readPageWidget.setBookPath(bookPath); 99 | } else { 100 | mBook = bookList.get(0); 101 | bookId = mBook.getId(); 102 | readPageWidget.setBookId(mBook.getId(), false); 103 | } 104 | } 105 | //设置readingPage到controller管理 106 | readController.setReadPageWidget(readPageWidget); 107 | 108 | readLoadingView = (CatLoadingView) view.findViewById(R.id.loading); 109 | if (mBook == null || mBook.getProcessStatus() != Constants.BOOK_PROCESSED) { 110 | readLoadingView.setVisibility(View.VISIBLE); 111 | //说明书籍不存在或者还没有处理好 112 | } else { 113 | readLoadingView.setVisibility(View.GONE); 114 | 115 | notifyController(); 116 | } 117 | } 118 | 119 | /** 120 | * 设置控制页面的状态 121 | */ 122 | private void notifyController() { 123 | if (mBook == null) { 124 | mBook = getDaoSession().getBookDao().load(bookId); 125 | } 126 | 127 | mChapterList = getDaoSession() 128 | .getChapterDao() 129 | .queryBuilder() 130 | .where(ChapterDao.Properties.BookId.eq(bookId)).list(); 131 | readController.setTotalChaptersNum(mBook.getCurrentChapter(), mChapterList.size() - 1); 132 | readController.setOnReadChapterProgressListener(this); 133 | } 134 | 135 | public void nextPage() { 136 | readPageWidget.nextPage(); 137 | } 138 | 139 | public void prePage() { 140 | readPageWidget.prePage(); 141 | } 142 | 143 | @Override 144 | public void onPause() { 145 | super.onPause(); 146 | } 147 | 148 | @Override 149 | public void onResume() { 150 | super.onResume(); 151 | 152 | if (EventBus.getDefault().isRegistered(this) == false) { 153 | EventBus.getDefault().register(this); 154 | } 155 | } 156 | 157 | @Override 158 | public void onDestroy() { 159 | super.onDestroy(); 160 | 161 | if (EventBus.getDefault().isRegistered(this) == true) { 162 | EventBus.getDefault().unregister(this); 163 | } 164 | } 165 | 166 | @Subscribe(threadMode = ThreadMode.MAIN) 167 | public void onEvent(BookStatusChangeEvent bookStatusChangeEvent) { 168 | if (bookId != BaseActivity.NO_BOOK_ID && bookId != bookStatusChangeEvent.getBookId()) { 169 | //不处理 170 | LogUtil.log.i("bookId不同,不是同一书籍,不更新。"); 171 | return; 172 | } 173 | if (bookId == BaseActivity.NO_BOOK_ID){ 174 | Book tempBook = getDaoSession().getBookDao().load(bookStatusChangeEvent.getBookId()); 175 | if (tempBook == null || tempBook.getBookPath().equals(bookPath) == false) { 176 | LogUtil.log.i("bookPath不同,不是同一书籍,不更新。"); 177 | return; 178 | } 179 | } 180 | 181 | 182 | switch (bookStatusChangeEvent.getStatus()) { 183 | case Constants.BOOK_PROCESSED: 184 | LogUtil.log.i("*****************************"); 185 | LogUtil.log.i("Current bookId is: " + bookId); 186 | LogUtil.log.i("Current bookPath is: " + bookPath); 187 | LogUtil.log.i("Pass bookId is: " + bookStatusChangeEvent.getBookId()); 188 | LogUtil.log.i("*****************************"); 189 | 190 | readLoadingView.setVisibility(View.GONE); 191 | bookId = bookStatusChangeEvent.getBookId(); 192 | readPageWidget.setBookId(bookId, true); 193 | readPageWidget.postInvalidate(); 194 | notifyController(); 195 | break; 196 | default: 197 | readLoadingView.setVisibility(View.VISIBLE); 198 | 199 | if (bookId == ReadingActivity.NO_BOOK_ID) { 200 | List bookList = getDaoSession() 201 | .getBookDao() 202 | .queryBuilder() 203 | .where(BookDao.Properties.BookPath.eq(bookPath)) 204 | .list(); 205 | if (bookList.size() > 0) { 206 | mBook = bookList.get(0); 207 | bookId = mBook.getId(); 208 | } 209 | } 210 | 211 | if (bookId == bookStatusChangeEvent.getBookId()) { 212 | readLoadingView.setLoadingProgress(bookStatusChangeEvent.getProgress()); 213 | } 214 | break; 215 | } 216 | } 217 | 218 | @Override 219 | public void onControllerStatusChange(boolean isShowing) { 220 | switchFullScreen(!isShowing); 221 | } 222 | 223 | @Override 224 | public void onReadProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { 225 | mBook.setCurrentChapter(progress); 226 | Chapter currentChapter = mChapterList.get(progress); 227 | if (currentChapter != null) { 228 | mBook.setCurrentPosition(currentChapter.getPosition()); 229 | getDaoSession().getBookDao().update(mBook); 230 | 231 | readPageWidget.setBookId(mBook.getId(), false); 232 | readPageWidget.postInvalidate(); 233 | } else { 234 | LogUtil.avlog.e("onReadProgressChanged currentChapter is null, " + "progress -- " + progress); 235 | } 236 | } 237 | } 238 | -------------------------------------------------------------------------------- /app/src/main/java/com/codingbingo/fastreader/ui/listener/OnChapterClickListener.java: -------------------------------------------------------------------------------- 1 | package com.codingbingo.fastreader.ui.listener; 2 | 3 | /** 4 | * Author: bingo 5 | * Email: codingbingo@gmail.com 6 | * By 2017/4/18. 7 | */ 8 | 9 | public interface OnChapterClickListener { 10 | void onChapterClick(int chapter); 11 | } 12 | -------------------------------------------------------------------------------- /app/src/main/java/com/codingbingo/fastreader/ui/listener/OnReadChapterProgressListener.java: -------------------------------------------------------------------------------- 1 | package com.codingbingo.fastreader.ui.listener; 2 | 3 | import android.widget.SeekBar; 4 | 5 | /** 6 | * Author: bingo 7 | * Email: codingbingo@gmail.com 8 | * By 2017/4/23. 9 | */ 10 | 11 | public interface OnReadChapterProgressListener { 12 | void onReadProgressChanged(SeekBar seekBar, int progress, boolean fromUser); 13 | } 14 | -------------------------------------------------------------------------------- /app/src/main/java/com/codingbingo/fastreader/utils/BrightnessUtils.java: -------------------------------------------------------------------------------- 1 | package com.codingbingo.fastreader.utils; 2 | 3 | /** 4 | * Author: bingo 5 | * Email: codingbingo@gmail.com 6 | * By 2017/4/12. 7 | * 8 | * 亮度调节 9 | */ 10 | 11 | public class BrightnessUtils { 12 | } 13 | -------------------------------------------------------------------------------- /app/src/main/java/com/codingbingo/fastreader/utils/CommonUtils.java: -------------------------------------------------------------------------------- 1 | package com.codingbingo.fastreader.utils; 2 | 3 | import android.content.Context; 4 | import android.util.TypedValue; 5 | 6 | import java.lang.reflect.Field; 7 | import java.util.logging.Level; 8 | import java.util.logging.Logger; 9 | 10 | /** 11 | * Created by bingo on 2016/12/25. 12 | */ 13 | 14 | public class CommonUtils { 15 | 16 | 17 | 18 | 19 | } 20 | -------------------------------------------------------------------------------- /app/src/main/java/com/codingbingo/fastreader/utils/FileUtils.java: -------------------------------------------------------------------------------- 1 | package com.codingbingo.fastreader.utils; 2 | 3 | import android.content.Context; 4 | import android.database.Cursor; 5 | import android.net.Uri; 6 | import android.provider.MediaStore; 7 | 8 | import com.avos.avoscloud.LogUtil; 9 | import com.codingbingo.fastreader.model.LocalFile; 10 | import com.codingbingo.fastreader.utils.encode.BytesEncodingDetect; 11 | 12 | import java.io.File; 13 | import java.io.UnsupportedEncodingException; 14 | import java.util.ArrayList; 15 | import java.util.List; 16 | 17 | /** 18 | * Author: bingo 19 | * Email: codingbingo@gmail.com 20 | * By 2017/1/5. 21 | */ 22 | 23 | public class FileUtils { 24 | /** 25 | * 得到文件的编码 26 | * 27 | * @param filePath 文件路径 28 | * @return 文件的编码 29 | */ 30 | public static String getJavaEncode(String filePath) { 31 | BytesEncodingDetect bytesEncodingDetect = new BytesEncodingDetect(); 32 | String fileCode = BytesEncodingDetect.javaname[ 33 | bytesEncodingDetect.detectEncoding(new File(filePath)) 34 | ]; 35 | return fileCode; 36 | } 37 | 38 | /** 39 | * 从媒体库中获取指定后缀的文件列表 40 | * 41 | * @param context 42 | * @param searchFileSuffix 文件后缀列表,eg: new String[]{"epub","mobi","pdf","txt"}; 43 | * @return 44 | */ 45 | public static List getSupportFileList(Context context, String[] searchFileSuffix) { 46 | ArrayList searchFileList = null; 47 | if (null == context || null == searchFileSuffix 48 | || searchFileSuffix.length == 0) { 49 | return null; 50 | } 51 | 52 | String searchPath = ""; 53 | int length = searchFileSuffix.length; 54 | for (int index = 0; index < length; index++) { 55 | searchPath += (MediaStore.Files.FileColumns.DATA + " LIKE '%" + searchFileSuffix[index] + "' "); 56 | if ((index + 1) < length) { 57 | searchPath += "or "; 58 | } 59 | } 60 | searchFileList = new ArrayList<>(); 61 | Uri uri = MediaStore.Files.getContentUri("external"); 62 | Cursor cursor = context.getContentResolver().query( 63 | uri, new String[]{MediaStore.Files.FileColumns.DATA, MediaStore.Files.FileColumns.SIZE}, searchPath, null, null); 64 | 65 | if (cursor == null) { 66 | LogUtil.log.e("Cursor 获取失败!"); 67 | } else { 68 | if (cursor.moveToFirst()) { 69 | do { 70 | String filepath = cursor.getString(cursor.getColumnIndex(MediaStore.Files.FileColumns.DATA)); 71 | if (filepath != null) { 72 | File file = new File(filepath); 73 | if (file.exists()) { 74 | try { 75 | String path = new String(filepath.getBytes("UTF-8")); 76 | 77 | String fileName = path.substring(path.lastIndexOf(File.separator) + 1); 78 | long fileSize = file.getTotalSpace(); 79 | 80 | LocalFile localFile = new LocalFile(); 81 | localFile.setFileName(fileName); 82 | localFile.setFilePath(path); 83 | localFile.setFileSize(fileSize); 84 | 85 | searchFileList.add(localFile); 86 | } catch (UnsupportedEncodingException e) { 87 | LogUtil.log.e("getSupportFileList", e); 88 | } 89 | } 90 | } 91 | } while (cursor.moveToNext()); 92 | } 93 | 94 | if (!cursor.isClosed()) { 95 | cursor.close(); 96 | } 97 | } 98 | 99 | return searchFileList; 100 | } 101 | 102 | /** 103 | * 判断文件是否存在 104 | */ 105 | public static boolean isFileExist(String filePath) { 106 | if (filePath == null) { 107 | return false; 108 | } 109 | 110 | File file = new File(filePath); 111 | return file.exists(); 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /app/src/main/java/com/codingbingo/fastreader/utils/LogUtils.java: -------------------------------------------------------------------------------- 1 | package com.codingbingo.fastreader.utils; 2 | 3 | import android.util.Log; 4 | 5 | /** 6 | * Author: bingo 7 | * Email: codingbingo@gmail.com 8 | * By 2017/2/14. 9 | */ 10 | 11 | public class LogUtils { 12 | 13 | } 14 | -------------------------------------------------------------------------------- /app/src/main/java/com/codingbingo/fastreader/utils/ScreenUtils.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2016 JustWayward Team 3 | *

4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | *

8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | *

10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.codingbingo.fastreader.utils; 17 | 18 | import android.animation.ValueAnimator; 19 | import android.app.Activity; 20 | import android.content.Context; 21 | import android.content.res.Configuration; 22 | import android.provider.Settings; 23 | import android.util.DisplayMetrics; 24 | import android.util.TypedValue; 25 | import android.view.Window; 26 | import android.view.WindowManager; 27 | 28 | import com.avos.avoscloud.LogUtil; 29 | import com.codingbingo.fastreader.base.utils.BaseUtils; 30 | 31 | import java.lang.reflect.Field; 32 | import java.util.logging.Level; 33 | import java.util.logging.Logger; 34 | 35 | /** 36 | * 屏幕亮度工具类 37 | * 38 | * @author yuyh. 39 | * @date 16/4/10. 40 | */ 41 | public class ScreenUtils extends BaseUtils { 42 | 43 | public enum EScreenDensity { 44 | XXHDPI, //超高分辨率 1080×1920 45 | XHDPI, //超高分辨率 720×1280 46 | HDPI, //高分辨率 480×800 47 | MDPI, //中分辨率 320×480 48 | } 49 | 50 | public static EScreenDensity getDisply(Context context) { 51 | EScreenDensity eScreenDensity; 52 | //初始化屏幕密度 53 | DisplayMetrics dm = context.getApplicationContext().getResources().getDisplayMetrics(); 54 | int densityDpi = dm.densityDpi; 55 | 56 | if (densityDpi <= 160) { 57 | eScreenDensity = EScreenDensity.MDPI; 58 | } else if (densityDpi <= 240) { 59 | eScreenDensity = EScreenDensity.HDPI; 60 | } else if (densityDpi < 400) { 61 | eScreenDensity = EScreenDensity.XHDPI; 62 | } else { 63 | eScreenDensity = EScreenDensity.XXHDPI; 64 | } 65 | return eScreenDensity; 66 | } 67 | 68 | /** 69 | * 获取屏幕宽度 70 | * 71 | * @return 72 | */ 73 | public static int getScreenWidth(Context context) { 74 | return context.getResources().getDisplayMetrics().widthPixels; 75 | } 76 | 77 | /** 78 | * 获取屏幕高度 79 | * 80 | * @return 81 | */ 82 | public static int getScreenHeight(Context context) { 83 | return context.getResources().getDisplayMetrics().heightPixels; 84 | } 85 | 86 | /** 87 | * 将dp转换成px 88 | * 89 | * @param dp 90 | * @return 91 | */ 92 | public static int dp2px(Context mContext, int dp) { 93 | return (int) (dp * mContext.getResources().getDisplayMetrics().density + 0.5f); 94 | } 95 | 96 | /** 97 | * 将px转换成dp 98 | * 99 | * @param px 100 | * @return 101 | */ 102 | public static int pxToDpInt(Context mContext, float px) { 103 | return (int) (px / mContext.getResources().getDisplayMetrics().density + 0.5f); 104 | } 105 | 106 | public static int getActionBarSize(Context context) { 107 | TypedValue tv = new TypedValue(); 108 | if (context.getTheme().resolveAttribute(android.R.attr.actionBarSize, tv, true)) { 109 | int actionBarHeight = TypedValue.complexToDimensionPixelSize(tv.data, context.getResources().getDisplayMetrics()); 110 | return actionBarHeight; 111 | } 112 | return 0; 113 | } 114 | 115 | /** 116 | * 获取titleBar的高度 117 | * @param mContext 118 | * @return 119 | */ 120 | public static int getTitleBarHeight(Context mContext) { 121 | int actionBarHeight = 0; 122 | TypedValue tv = new TypedValue(); 123 | if (mContext.getTheme().resolveAttribute(android.R.attr.actionBarSize, tv, true)) { 124 | actionBarHeight = TypedValue.complexToDimensionPixelSize(tv.data, mContext.getResources().getDisplayMetrics()); 125 | } 126 | return actionBarHeight; 127 | } 128 | 129 | /** 130 | * 获取statusBar高度 131 | * @param mContext 132 | * @return 133 | */ 134 | public static int getStatusBarHeight(Context mContext) { 135 | int height = 0; 136 | try { 137 | Class c = Class.forName("com.android.internal.R$dimen"); 138 | Object obj = c.newInstance(); 139 | Field field = c.getField("status_bar_height"); 140 | int x = Integer.parseInt(field.get(obj).toString()); 141 | height = mContext.getResources().getDimensionPixelSize(x); 142 | } catch (Exception e) { 143 | logger.log(Level.WARNING, e.getMessage()); 144 | } 145 | return height; 146 | } 147 | 148 | /** 149 | * 当前是否是横屏 150 | * 151 | * @param context context 152 | * @return boolean 153 | */ 154 | public static final boolean isLandscape(Context context) { 155 | return context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE; 156 | } 157 | 158 | /** 159 | * 当前是否是竖屏 160 | * 161 | * @param context context 162 | * @return boolean 163 | */ 164 | public static final boolean isPortrait(Context context) { 165 | return context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT; 166 | } 167 | 168 | /** 169 | * 调整窗口的透明度 1.0f,0.5f 变暗 170 | * 171 | * @param from from>=0&&from<=1.0f 172 | * @param to to>=0&&to<=1.0f 173 | * @param context 当前的activity 174 | */ 175 | public static void dimBackground(final float from, final float to, Activity context) { 176 | final Window window = context.getWindow(); 177 | ValueAnimator valueAnimator = ValueAnimator.ofFloat(from, to); 178 | valueAnimator.setDuration(500); 179 | valueAnimator.addUpdateListener( 180 | new ValueAnimator.AnimatorUpdateListener() { 181 | @Override 182 | public void onAnimationUpdate(ValueAnimator animation) { 183 | WindowManager.LayoutParams params = window.getAttributes(); 184 | params.alpha = (Float) animation.getAnimatedValue(); 185 | window.setAttributes(params); 186 | } 187 | }); 188 | valueAnimator.start(); 189 | } 190 | 191 | /** 192 | * 判断是否开启了自动亮度调节 193 | * 194 | * @param activity 195 | * @return 196 | */ 197 | public static boolean isAutoBrightness(Activity activity) { 198 | boolean isAutoAdjustBright = false; 199 | try { 200 | isAutoAdjustBright = Settings.System.getInt( 201 | activity.getContentResolver(), 202 | Settings.System.SCREEN_BRIGHTNESS_MODE) == Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC; 203 | } catch (Settings.SettingNotFoundException e) { 204 | LogUtil.log.e("判断是否开启自动调节亮度失败", e); 205 | } 206 | return isAutoAdjustBright; 207 | } 208 | 209 | /** 210 | * 关闭亮度自动调节 211 | * 212 | * @param activity 213 | */ 214 | public static void stopAutoBrightness(Activity activity) { 215 | Settings.System.putInt(activity.getContentResolver(), 216 | Settings.System.SCREEN_BRIGHTNESS_MODE, 217 | Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL); 218 | } 219 | 220 | /** 221 | * 开启亮度自动调节 222 | * 223 | * @param activity 224 | */ 225 | 226 | public static void startAutoBrightness(Activity activity) { 227 | Settings.System.putInt(activity.getContentResolver(), 228 | Settings.System.SCREEN_BRIGHTNESS_MODE, 229 | Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC); 230 | } 231 | 232 | /** 233 | * 获得当前屏幕亮度值 234 | * 235 | * @param mContext 236 | * @return 0~100 237 | */ 238 | public static float getScreenBrightness(Context mContext) { 239 | int screenBrightness = 255; 240 | try { 241 | screenBrightness = Settings.System.getInt(mContext.getContentResolver(), Settings.System.SCREEN_BRIGHTNESS); 242 | } catch (Exception e) { 243 | LogUtil.log.e("getScreenBrightness", e); 244 | } 245 | return screenBrightness / 255.0F * 100; 246 | } 247 | 248 | /** 249 | * 设置当前屏幕亮度值 250 | * 251 | * @param paramInt 0~100 252 | * @param mContext 253 | */ 254 | public static void saveScreenBrightness(int paramInt, Context mContext) { 255 | if (paramInt <= 5) { 256 | paramInt = 5; 257 | } 258 | try { 259 | float f = paramInt / 100.0F * 255; 260 | Settings.System.putInt(mContext.getContentResolver(), Settings.System.SCREEN_BRIGHTNESS, (int) f); 261 | } catch (Exception e) { 262 | LogUtil.log.e("saveScreenBrightness", e); 263 | } 264 | } 265 | 266 | /** 267 | * 设置Activity的亮度 268 | * 269 | * @param paramInt 270 | * @param mActivity 271 | */ 272 | public static void setScreenBrightness(int paramInt, Activity mActivity) { 273 | if (paramInt <= 5) { 274 | paramInt = 5; 275 | } 276 | Window localWindow = mActivity.getWindow(); 277 | WindowManager.LayoutParams localLayoutParams = localWindow.getAttributes(); 278 | float f = paramInt / 100.0F; 279 | localLayoutParams.screenBrightness = f; 280 | localWindow.setAttributes(localLayoutParams); 281 | } 282 | } 283 | -------------------------------------------------------------------------------- /app/src/main/java/com/codingbingo/fastreader/utils/SharedPreferenceUtils.java: -------------------------------------------------------------------------------- 1 | package com.codingbingo.fastreader.utils; 2 | 3 | import android.content.Context; 4 | import android.content.SharedPreferences; 5 | 6 | /** 7 | * Author: bingo 8 | * Email: codingbingo@gmail.com 9 | * By 2017/2/14. 10 | */ 11 | 12 | public class SharedPreferenceUtils { 13 | 14 | private volatile static SharedPreferenceUtils instance; 15 | private SharedPreferences sharedPreferences; 16 | private SharedPreferences.Editor editor; 17 | 18 | public static SharedPreferenceUtils getInstance() { 19 | if (instance == null){ 20 | synchronized (SharedPreferenceUtils.class){ 21 | if (instance == null){ 22 | instance = new SharedPreferenceUtils(); 23 | } 24 | } 25 | } 26 | return instance; 27 | } 28 | 29 | private SharedPreferenceUtils(){} 30 | 31 | /** 32 | * 在Application初始化的时候就要初始化 33 | * @param context 34 | * @param preferenceName 35 | */ 36 | public static void init(Context context, String preferenceName){ 37 | instance = new SharedPreferenceUtils(); 38 | instance.sharedPreferences = context.getSharedPreferences(preferenceName, Context.MODE_PRIVATE); 39 | instance.editor = instance.sharedPreferences.edit(); 40 | } 41 | 42 | public boolean getBoolean(String key, boolean defaultValue){ 43 | return instance.sharedPreferences.getBoolean(key, defaultValue); 44 | } 45 | 46 | public int getInt(String key, int defaultValue){ 47 | return instance.sharedPreferences.getInt(key, defaultValue); 48 | } 49 | 50 | public String getString(String key, String defaultValue){ 51 | return instance.sharedPreferences.getString(key, defaultValue); 52 | } 53 | 54 | public void putString(String key, String value){ 55 | instance.editor.putString(key, value); 56 | instance.editor.commit(); 57 | } 58 | 59 | public void putBoolean(String key, boolean value){ 60 | instance.editor.putBoolean(key, value); 61 | instance.editor.commit(); 62 | } 63 | 64 | public void putInt(String key, int value){ 65 | instance.editor.putInt(key, value); 66 | instance.editor.commit(); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /app/src/main/java/com/codingbingo/fastreader/utils/SimpleDividerItemDecoration.java: -------------------------------------------------------------------------------- 1 | package com.codingbingo.fastreader.utils; 2 | 3 | import android.content.Context; 4 | import android.graphics.Canvas; 5 | import android.graphics.drawable.Drawable; 6 | import android.support.v7.widget.RecyclerView; 7 | import android.view.View; 8 | 9 | import com.codingbingo.fastreader.R; 10 | 11 | /** 12 | * Author: bingo 13 | * Email: codingbingo@gmail.com 14 | * By 2017/4/14. 15 | */ 16 | 17 | public class SimpleDividerItemDecoration extends RecyclerView.ItemDecoration { 18 | private Drawable mDivider; 19 | 20 | public SimpleDividerItemDecoration(Context context) { 21 | mDivider = context.getResources().getDrawable(R.drawable.line_divider); 22 | } 23 | 24 | @Override 25 | public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) { 26 | int left = parent.getPaddingLeft(); 27 | int right = parent.getWidth() - parent.getPaddingRight(); 28 | 29 | int childCount = parent.getChildCount(); 30 | for (int i = 0; i < childCount; i++) { 31 | View child = parent.getChildAt(i); 32 | 33 | RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams(); 34 | 35 | int top = child.getBottom() + params.bottomMargin; 36 | int bottom = top + mDivider.getIntrinsicHeight(); 37 | 38 | mDivider.setBounds(left, top, right, bottom); 39 | mDivider.draw(c); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /app/src/main/java/com/codingbingo/fastreader/utils/StringUtils.java: -------------------------------------------------------------------------------- 1 | package com.codingbingo.fastreader.utils; 2 | 3 | /** 4 | * Created by bingo on 2017/1/4. 5 | */ 6 | 7 | public class StringUtils { 8 | 9 | public static boolean isBlank(String content) { 10 | if (content == null || content.length() == 0) { 11 | return true; 12 | } else { 13 | return false; 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /app/src/main/java/com/codingbingo/fastreader/utils/ThreadPool.java: -------------------------------------------------------------------------------- 1 | package com.codingbingo.fastreader.utils; 2 | 3 | import com.avos.avoscloud.LogUtil; 4 | import com.codingbingo.fastreader.view.readview.PageFactory; 5 | 6 | import java.lang.ref.WeakReference; 7 | import java.util.HashMap; 8 | import java.util.List; 9 | import java.util.Map; 10 | import java.util.concurrent.ExecutorService; 11 | import java.util.concurrent.Executors; 12 | 13 | /** 14 | * Author: bingo 15 | * Email: codingbingo@gmail.com 16 | * By 2017/1/5. 17 | */ 18 | 19 | public class ThreadPool { 20 | private volatile static ThreadPool threadPool; 21 | 22 | public static ThreadPool getInstance() { 23 | if (threadPool == null) { 24 | synchronized (ThreadPool.class) { 25 | if (threadPool == null) { 26 | threadPool = new ThreadPool(); 27 | } 28 | } 29 | } 30 | return threadPool; 31 | } 32 | 33 | public static final int POOL_SIZE = 10; 34 | private ExecutorService executorService; 35 | private Map processMap; 36 | 37 | private ThreadPool() { 38 | executorService = Executors.newFixedThreadPool(POOL_SIZE); 39 | processMap = new HashMap<>(); 40 | } 41 | 42 | public synchronized void submitTask(Runnable runnable) { 43 | for (String key : processMap.keySet()) { 44 | if (processMap.get(key).isFinished() == true) { 45 | processMap.remove(key); 46 | } 47 | 48 | LogUtil.avlog.i("processMap: " + key); 49 | } 50 | 51 | if (runnable instanceof PageFactory.OpenBookTask) { 52 | PageFactory.OpenBookTask openBookTask = (PageFactory.OpenBookTask) runnable; 53 | 54 | if (processMap.get(openBookTask.getFilePath()) != null) { 55 | return; 56 | } else{ 57 | processMap.put(openBookTask.getFilePath(), openBookTask); 58 | } 59 | } 60 | 61 | executorService.submit(runnable); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /app/src/main/java/com/codingbingo/fastreader/utils/encode/Encoding.java: -------------------------------------------------------------------------------- 1 | package com.codingbingo.fastreader.utils.encode; 2 | 3 | /** 4 | * Created by bingo on 2017/1/4. 5 | */ 6 | 7 | public class Encoding { 8 | // Supported Encoding Types 9 | public static int GB2312 = 0; 10 | 11 | public static int GBK = 1; 12 | 13 | public static int GB18030 = 2; 14 | 15 | public static int HZ = 3; 16 | 17 | public static int BIG5 = 4; 18 | 19 | public static int CNS11643 = 5; 20 | 21 | public static int UTF8 = 6; 22 | 23 | public static int UTF8T = 7; 24 | 25 | public static int UTF8S = 8; 26 | 27 | public static int UNICODE = 9; 28 | 29 | public static int UNICODET = 10; 30 | 31 | public static int UNICODES = 11; 32 | 33 | public static int ISO2022CN = 12; 34 | 35 | public static int ISO2022CN_CNS = 13; 36 | 37 | public static int ISO2022CN_GB = 14; 38 | 39 | public static int EUC_KR = 15; 40 | 41 | public static int CP949 = 16; 42 | 43 | public static int ISO2022KR = 17; 44 | 45 | public static int JOHAB = 18; 46 | 47 | public static int SJIS = 19; 48 | 49 | public static int EUC_JP = 20; 50 | 51 | public static int ISO2022JP = 21; 52 | 53 | public static int ASCII = 22; 54 | 55 | public static int OTHER = 23; 56 | 57 | public static int TOTALTYPES = 24; 58 | 59 | public final static int SIMP = 0; 60 | 61 | public final static int TRAD = 1; 62 | 63 | // Names of the encodings as understood by Java 64 | public static String[] javaname; 65 | 66 | // Names of the encodings for human viewing 67 | public static String[] nicename; 68 | 69 | // Names of charsets as used in charset parameter of HTML Meta tag 70 | public static String[] htmlname; 71 | 72 | // Constructor 73 | public Encoding() { 74 | javaname = new String[TOTALTYPES]; 75 | nicename = new String[TOTALTYPES]; 76 | htmlname = new String[TOTALTYPES]; 77 | // Assign encoding names 78 | javaname[GB2312] = "GB2312"; 79 | javaname[GBK] = "GBK"; 80 | javaname[GB18030] = "GB18030"; 81 | javaname[HZ] = "ASCII"; // What to put here? Sun doesn't support HZ 82 | javaname[ISO2022CN_GB] = "ISO2022CN_GB"; 83 | javaname[BIG5] = "BIG5"; 84 | javaname[CNS11643] = "EUC-TW"; 85 | javaname[ISO2022CN_CNS] = "ISO2022CN_CNS"; 86 | javaname[ISO2022CN] = "ISO2022CN"; 87 | javaname[UTF8] = "UTF-8"; 88 | javaname[UTF8T] = "UTF-8"; 89 | javaname[UTF8S] = "UTF-8"; 90 | javaname[UNICODE] = "Unicode"; 91 | javaname[UNICODET] = "Unicode"; 92 | javaname[UNICODES] = "Unicode"; 93 | javaname[EUC_KR] = "EUC_KR"; 94 | javaname[CP949] = "MS949"; 95 | javaname[ISO2022KR] = "ISO2022KR"; 96 | javaname[JOHAB] = "Johab"; 97 | javaname[SJIS] = "SJIS"; 98 | javaname[EUC_JP] = "EUC_JP"; 99 | javaname[ISO2022JP] = "ISO2022JP"; 100 | javaname[ASCII] = "ASCII"; 101 | javaname[OTHER] = "ISO8859_1"; 102 | // Assign encoding names 103 | htmlname[GB2312] = "GB2312"; 104 | htmlname[GBK] = "GBK"; 105 | htmlname[GB18030] = "GB18030"; 106 | htmlname[HZ] = "HZ-GB-2312"; 107 | htmlname[ISO2022CN_GB] = "ISO-2022-CN-EXT"; 108 | htmlname[BIG5] = "BIG5"; 109 | htmlname[CNS11643] = "EUC-TW"; 110 | htmlname[ISO2022CN_CNS] = "ISO-2022-CN-EXT"; 111 | htmlname[ISO2022CN] = "ISO-2022-CN"; 112 | htmlname[UTF8] = "UTF-8"; 113 | htmlname[UTF8T] = "UTF-8"; 114 | htmlname[UTF8S] = "UTF-8"; 115 | htmlname[UNICODE] = "UTF-16"; 116 | htmlname[UNICODET] = "UTF-16"; 117 | htmlname[UNICODES] = "UTF-16"; 118 | htmlname[EUC_KR] = "EUC-KR"; 119 | htmlname[CP949] = "x-windows-949"; 120 | htmlname[ISO2022KR] = "ISO-2022-KR"; 121 | htmlname[JOHAB] = "x-Johab"; 122 | htmlname[SJIS] = "Shift_JIS"; 123 | htmlname[EUC_JP] = "EUC-JP"; 124 | htmlname[ISO2022JP] = "ISO-2022-JP"; 125 | htmlname[ASCII] = "ASCII"; 126 | htmlname[OTHER] = "ISO8859-1"; 127 | // Assign Human readable names 128 | nicename[GB2312] = "GB-2312"; 129 | nicename[GBK] = "GBK"; 130 | nicename[GB18030] = "GB18030"; 131 | nicename[HZ] = "HZ"; 132 | nicename[ISO2022CN_GB] = "ISO2022CN-GB"; 133 | nicename[BIG5] = "Big5"; 134 | nicename[CNS11643] = "CNS11643"; 135 | nicename[ISO2022CN_CNS] = "ISO2022CN-CNS"; 136 | nicename[ISO2022CN] = "ISO2022 CN"; 137 | nicename[UTF8] = "UTF-8"; 138 | nicename[UTF8T] = "UTF-8 (Trad)"; 139 | nicename[UTF8S] = "UTF-8 (Simp)"; 140 | nicename[UNICODE] = "Unicode"; 141 | nicename[UNICODET] = "Unicode (Trad)"; 142 | nicename[UNICODES] = "Unicode (Simp)"; 143 | nicename[EUC_KR] = "EUC-KR"; 144 | nicename[CP949] = "CP949"; 145 | nicename[ISO2022KR] = "ISO 2022 KR"; 146 | nicename[JOHAB] = "Johab"; 147 | nicename[SJIS] = "Shift-JIS"; 148 | nicename[EUC_JP] = "EUC-JP"; 149 | nicename[ISO2022JP] = "ISO 2022 JP"; 150 | nicename[ASCII] = "ASCII"; 151 | nicename[OTHER] = "OTHER"; 152 | } 153 | 154 | } -------------------------------------------------------------------------------- /app/src/main/java/com/codingbingo/fastreader/view/BookNestedScrollView.java: -------------------------------------------------------------------------------- 1 | package com.codingbingo.fastreader.view; 2 | 3 | import android.content.Context; 4 | import android.support.v4.widget.NestedScrollView; 5 | import android.util.AttributeSet; 6 | import android.view.MotionEvent; 7 | import android.view.ViewConfiguration; 8 | 9 | /** 10 | * Created by bingo on 2016/12/21. 11 | */ 12 | 13 | public class BookNestedScrollView extends NestedScrollView { 14 | 15 | private int downY; 16 | private int mTouchSlop; 17 | 18 | public BookNestedScrollView(Context context) { 19 | super(context); 20 | 21 | mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); 22 | } 23 | 24 | public BookNestedScrollView(Context context, AttributeSet attrs) { 25 | super(context, attrs); 26 | 27 | mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); 28 | } 29 | 30 | public BookNestedScrollView(Context context, AttributeSet attrs, int defStyleAttr) { 31 | super(context, attrs, defStyleAttr); 32 | 33 | mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); 34 | } 35 | 36 | @Override 37 | public boolean onInterceptTouchEvent(MotionEvent ev) { 38 | switch (ev.getAction()){ 39 | case MotionEvent.ACTION_DOWN: 40 | downY = (int) ev.getY(); 41 | break; 42 | case MotionEvent.ACTION_MOVE: 43 | int moveY = (int) ev.getRawY(); 44 | if (Math.abs(moveY - downY) > mTouchSlop) { 45 | return true; 46 | } 47 | break; 48 | } 49 | return super.onInterceptTouchEvent(ev); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /app/src/main/java/com/codingbingo/fastreader/view/LoadingDialog.java: -------------------------------------------------------------------------------- 1 | package com.codingbingo.fastreader.view; 2 | 3 | import android.app.Dialog; 4 | import android.content.Context; 5 | import android.os.Bundle; 6 | import android.support.annotation.NonNull; 7 | import android.support.annotation.Nullable; 8 | import android.support.annotation.StyleRes; 9 | import android.view.View; 10 | import android.widget.TextView; 11 | 12 | import com.codingbingo.fastreader.R; 13 | import com.codingbingo.fastreader.view.loadingview.CatLoadingView; 14 | 15 | /** 16 | * Author: bingo 17 | * Email: codingbingo@gmail.com 18 | * By 2017/4/19. 19 | */ 20 | 21 | public class LoadingDialog extends Dialog { 22 | 23 | private TextView loadingProgress; 24 | private String loadingText; 25 | 26 | public LoadingDialog(@NonNull Context context) { 27 | super(context); 28 | } 29 | 30 | public LoadingDialog(@NonNull Context context, @StyleRes int themeResId) { 31 | super(context, themeResId); 32 | } 33 | 34 | public LoadingDialog(@NonNull Context context, boolean cancelable, @Nullable OnCancelListener cancelListener) { 35 | super(context, cancelable, cancelListener); 36 | } 37 | 38 | 39 | public void setLoadingText(String loadingText) { 40 | this.loadingText = loadingText; 41 | } 42 | 43 | @Override 44 | protected void onCreate(Bundle savedInstanceState) { 45 | super.onCreate(savedInstanceState); 46 | 47 | setContentView(new CatLoadingView(getContext())); 48 | 49 | loadingProgress = (TextView) findViewById(R.id.loading_progress); 50 | loadingProgress.setVisibility(View.GONE); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /app/src/main/java/com/codingbingo/fastreader/view/SwitchableSeekBar.java: -------------------------------------------------------------------------------- 1 | package com.codingbingo.fastreader.view; 2 | 3 | import android.content.Context; 4 | import android.support.v7.widget.AppCompatSeekBar; 5 | import android.util.AttributeSet; 6 | import android.view.MotionEvent; 7 | import android.widget.Toast; 8 | 9 | /** 10 | * Author: bingo 11 | * Email: codingbingo@gmail.com 12 | * By 2017/4/12. 13 | */ 14 | 15 | public class SwitchableSeekBar extends AppCompatSeekBar { 16 | 17 | private boolean enable = false; 18 | private Toast toast; 19 | 20 | public SwitchableSeekBar(Context context) { 21 | this(context, null); 22 | } 23 | 24 | public SwitchableSeekBar(Context context, AttributeSet attrs) { 25 | this(context, attrs, android.support.v7.appcompat.R.attr.seekBarStyle); 26 | } 27 | 28 | public SwitchableSeekBar(Context context, AttributeSet attrs, int defStyleAttr) { 29 | super(context, attrs, defStyleAttr); 30 | } 31 | 32 | public void setEnable(boolean enable) { 33 | this.enable = enable; 34 | } 35 | 36 | @Override 37 | public boolean onTouchEvent(MotionEvent event) { 38 | if (enable) { 39 | return super.onTouchEvent(event); 40 | } else { 41 | showToast("书籍未加载完成,暂时不可目录快进"); 42 | return true; 43 | } 44 | } 45 | 46 | private void showToast(String content){ 47 | if (toast == null){ 48 | toast = Toast.makeText(getContext(), content, Toast.LENGTH_SHORT); 49 | }else{ 50 | toast.setText(content); 51 | } 52 | 53 | toast.show(); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /app/src/main/java/com/codingbingo/fastreader/view/loadingview/CatLoadingView.java: -------------------------------------------------------------------------------- 1 | package com.codingbingo.fastreader.view.loadingview; 2 | 3 | import android.content.Context; 4 | import android.graphics.Color; 5 | import android.support.annotation.Nullable; 6 | import android.text.TextUtils; 7 | import android.util.AttributeSet; 8 | import android.view.LayoutInflater; 9 | import android.view.MotionEvent; 10 | import android.view.View; 11 | import android.view.animation.Animation; 12 | import android.view.animation.LinearInterpolator; 13 | import android.view.animation.RotateAnimation; 14 | import android.widget.RelativeLayout; 15 | import android.widget.TextView; 16 | 17 | import com.codingbingo.fastreader.R; 18 | 19 | /** 20 | * Author: bingo 21 | * Email: codingbingo@gmail.com 22 | * By 2017/4/17. 23 | */ 24 | 25 | public class CatLoadingView extends RelativeLayout { 26 | //动画 27 | Animation operatingAnim, eye_left_Anim, eye_right_Anim; 28 | 29 | View mouse, eye_left, eye_right; 30 | 31 | //眼睛 32 | EyelidView eyelid_left, eyelid_right; 33 | 34 | GraduallyTextView mGraduallyTextView; 35 | 36 | TextView mLoadingProgress; 37 | 38 | //loading文字 39 | String text; 40 | 41 | String progress; 42 | 43 | public CatLoadingView(Context context) { 44 | this(context, null, 0); 45 | } 46 | 47 | public CatLoadingView(Context context, @Nullable AttributeSet attrs) { 48 | this(context, attrs, 0); 49 | } 50 | 51 | public CatLoadingView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { 52 | super(context, attrs, defStyleAttr); 53 | 54 | LayoutInflater.from(context).inflate(R.layout.cat_loading, this); 55 | init(); 56 | } 57 | 58 | private void init() { 59 | operatingAnim = new RotateAnimation(360f, 0f, Animation.RELATIVE_TO_SELF, 0.5f, 60 | Animation.RELATIVE_TO_SELF, 0.5f); 61 | operatingAnim.setRepeatCount(Animation.INFINITE); 62 | operatingAnim.setDuration(2000); 63 | 64 | eye_left_Anim = new RotateAnimation(360f, 0f, Animation.RELATIVE_TO_SELF, 0.5f, 65 | Animation.RELATIVE_TO_SELF, 0.5f); 66 | eye_left_Anim.setRepeatCount(Animation.INFINITE); 67 | eye_left_Anim.setDuration(2000); 68 | 69 | eye_right_Anim = new RotateAnimation(360f, 0f, Animation.RELATIVE_TO_SELF, 0.5f, 70 | Animation.RELATIVE_TO_SELF, 0.5f); 71 | eye_right_Anim.setRepeatCount(Animation.INFINITE); 72 | eye_right_Anim.setDuration(2000); 73 | 74 | LinearInterpolator lin = new LinearInterpolator(); 75 | operatingAnim.setInterpolator(lin); 76 | eye_left_Anim.setInterpolator(lin); 77 | eye_right_Anim.setInterpolator(lin); 78 | 79 | mouse = findViewById(R.id.mouse); 80 | 81 | mLoadingProgress = (TextView) findViewById(R.id.loading_progress); 82 | 83 | eye_left = findViewById(R.id.eye_left); 84 | 85 | eye_right = findViewById(R.id.eye_right); 86 | 87 | eyelid_left = (EyelidView) findViewById(R.id.eyelid_left); 88 | 89 | eyelid_left.setColor(Color.parseColor("#d0ced1")); 90 | 91 | eyelid_left.setFromFull(true); 92 | 93 | eyelid_right = (EyelidView) findViewById(R.id.eyelid_right); 94 | 95 | eyelid_right.setColor(Color.parseColor("#d0ced1")); 96 | 97 | eyelid_right.setFromFull(true); 98 | 99 | mGraduallyTextView = (GraduallyTextView) findViewById(R.id.graduallyTextView); 100 | 101 | if (!TextUtils.isEmpty(text)) { 102 | mGraduallyTextView.setText(text); 103 | } 104 | 105 | operatingAnim.setAnimationListener(new Animation.AnimationListener() { 106 | @Override public void onAnimationStart(Animation animation) { 107 | } 108 | 109 | @Override public void onAnimationEnd(Animation animation) { 110 | } 111 | 112 | @Override public void onAnimationRepeat(Animation animation) { 113 | eyelid_left.resetAnimator(); 114 | eyelid_right.resetAnimator(); 115 | } 116 | }); 117 | } 118 | 119 | 120 | @Override 121 | protected void onDetachedFromWindow() { 122 | super.onDetachedFromWindow(); 123 | 124 | operatingAnim.reset(); 125 | eye_left_Anim.reset(); 126 | eye_right_Anim.reset(); 127 | 128 | mouse.clearAnimation(); 129 | eye_left.clearAnimation(); 130 | eye_right.clearAnimation(); 131 | 132 | eyelid_left.stopLoading(); 133 | eyelid_right.stopLoading(); 134 | mGraduallyTextView.stopLoading(); 135 | } 136 | 137 | @Override 138 | protected void onAttachedToWindow() { 139 | super.onAttachedToWindow(); 140 | 141 | mouse.setAnimation(operatingAnim); 142 | eye_left.setAnimation(eye_left_Anim); 143 | eye_right.setAnimation(eye_right_Anim); 144 | eyelid_left.startLoading(); 145 | eyelid_right.startLoading(); 146 | mGraduallyTextView.startLoading(); 147 | } 148 | 149 | public void setText(String str) { 150 | text = str; 151 | } 152 | 153 | public void setLoadingProgress(int loadingProgress){ 154 | progress = loadingProgress + " %"; 155 | 156 | mLoadingProgress.setText(progress); 157 | } 158 | 159 | @Override 160 | public boolean onTouchEvent(MotionEvent event) { 161 | return true; 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /app/src/main/java/com/codingbingo/fastreader/view/loadingview/EyelidView.java: -------------------------------------------------------------------------------- 1 | package com.codingbingo.fastreader.view.loadingview; 2 | 3 | import android.animation.ValueAnimator; 4 | import android.content.Context; 5 | import android.graphics.Canvas; 6 | import android.graphics.Color; 7 | import android.graphics.Paint; 8 | import android.util.AttributeSet; 9 | import android.view.View; 10 | import android.view.animation.AccelerateDecelerateInterpolator; 11 | import android.view.animation.Animation; 12 | 13 | public class EyelidView extends View { 14 | 15 | private float progress; 16 | private boolean isLoading; 17 | private Paint mPaint; 18 | private boolean isStop = true; 19 | private int duration = 1000; 20 | private ValueAnimator valueAnimator; 21 | private boolean isFromFull; 22 | 23 | 24 | public EyelidView(Context context) { 25 | super(context); 26 | init(); 27 | } 28 | 29 | 30 | public EyelidView(Context context, AttributeSet attrs) { 31 | super(context, attrs); 32 | init(); 33 | } 34 | 35 | 36 | public EyelidView(Context context, AttributeSet attrs, int defStyleAttr) { 37 | super(context, attrs, defStyleAttr); 38 | init(); 39 | } 40 | 41 | 42 | public void init() { 43 | mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 44 | mPaint.setColor(Color.BLACK); 45 | mPaint.setStyle(Paint.Style.FILL); 46 | setBackground(null); 47 | setFocusable(false); 48 | setEnabled(false); 49 | setFocusableInTouchMode(false); 50 | 51 | valueAnimator = ValueAnimator.ofFloat(0, 1).setDuration(duration); 52 | valueAnimator.setInterpolator(new AccelerateDecelerateInterpolator()); 53 | valueAnimator.setRepeatCount(Animation.INFINITE); 54 | valueAnimator.setRepeatMode(ValueAnimator.REVERSE); 55 | valueAnimator.addUpdateListener( 56 | new ValueAnimator.AnimatorUpdateListener() { 57 | @Override 58 | public void onAnimationUpdate(ValueAnimator animation) { 59 | progress = (float) animation.getAnimatedValue(); 60 | invalidate(); 61 | } 62 | }); 63 | } 64 | 65 | 66 | public void setColor(int color) { 67 | mPaint.setColor(color); 68 | } 69 | 70 | 71 | public void startLoading() { 72 | if (!isStop) { 73 | return; 74 | } 75 | isLoading = true; 76 | isStop = false; 77 | valueAnimator.start(); 78 | } 79 | 80 | public void resetAnimator(){ 81 | valueAnimator.start(); 82 | } 83 | 84 | 85 | public void stopLoading() { 86 | isLoading = false; 87 | valueAnimator.end(); 88 | valueAnimator.cancel(); 89 | isStop = true; 90 | } 91 | 92 | 93 | public void setDuration(int duration) { 94 | this.duration = duration; 95 | } 96 | 97 | 98 | @Override 99 | protected void onVisibilityChanged(View changedView, int visibility) { 100 | super.onVisibilityChanged(changedView, visibility); 101 | if (!isLoading) { 102 | return; 103 | } 104 | if (visibility == View.VISIBLE) { 105 | valueAnimator.resume(); 106 | } 107 | else { 108 | valueAnimator.pause(); 109 | } 110 | } 111 | 112 | public void setFromFull(boolean fromFull) { 113 | isFromFull = fromFull; 114 | } 115 | 116 | 117 | @Override protected void onDraw(Canvas canvas) { 118 | super.onDraw(canvas); 119 | 120 | if (!isStop) { 121 | float bottom = 0.0f; 122 | if (!isFromFull) { 123 | bottom = progress * getHeight(); 124 | } 125 | else { 126 | bottom = (1.0f - progress) * getHeight(); 127 | } 128 | 129 | bottom = bottom >= (getHeight() / 2) ? (getHeight() / 2) : bottom; 130 | canvas.drawRect(0, 0, getWidth(), bottom, mPaint); 131 | } 132 | } 133 | 134 | 135 | private boolean whenStop() { 136 | return (isLoading == false && progress <= 0.001f); 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /app/src/main/java/com/codingbingo/fastreader/view/loadingview/GraduallyTextView.java: -------------------------------------------------------------------------------- 1 | package com.codingbingo.fastreader.view.loadingview; 2 | 3 | import android.animation.ValueAnimator; 4 | import android.content.Context; 5 | import android.graphics.Canvas; 6 | import android.graphics.Paint; 7 | import android.text.TextUtils; 8 | import android.util.AttributeSet; 9 | import android.view.View; 10 | import android.view.animation.AccelerateDecelerateInterpolator; 11 | import android.view.animation.Animation; 12 | import android.widget.EditText; 13 | 14 | public class GraduallyTextView extends EditText { 15 | 16 | private CharSequence text; 17 | private int startY = 0; 18 | private float progress; 19 | private boolean isLoading; 20 | private Paint mPaint; 21 | private int textLength; 22 | private boolean isStop = true; 23 | private float scaleX; 24 | private int duration = 2000; 25 | private float sigleDuration; 26 | 27 | private ValueAnimator valueAnimator; 28 | 29 | 30 | public GraduallyTextView(Context context) { 31 | super(context); 32 | init(); 33 | } 34 | 35 | 36 | public GraduallyTextView(Context context, AttributeSet attrs) { 37 | super(context, attrs); 38 | init(); 39 | } 40 | 41 | 42 | public GraduallyTextView(Context context, AttributeSet attrs, int defStyleAttr) { 43 | super(context, attrs, defStyleAttr); 44 | init(); 45 | } 46 | 47 | 48 | public void init() { 49 | mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 50 | mPaint.setStyle(Paint.Style.FILL); 51 | setBackground(null); 52 | setCursorVisible(false); 53 | setFocusable(false); 54 | setEnabled(false); 55 | setFocusableInTouchMode(false); 56 | 57 | valueAnimator = ValueAnimator.ofFloat(0, 100).setDuration(duration); 58 | valueAnimator.setInterpolator(new AccelerateDecelerateInterpolator()); 59 | valueAnimator.setRepeatCount(Animation.INFINITE); 60 | valueAnimator.setRepeatMode(ValueAnimator.RESTART); 61 | valueAnimator.addUpdateListener( 62 | new ValueAnimator.AnimatorUpdateListener() { 63 | @Override 64 | public void onAnimationUpdate(ValueAnimator animation) { 65 | progress = (Float) animation.getAnimatedValue(); 66 | GraduallyTextView.this.invalidate(); 67 | } 68 | }); 69 | } 70 | 71 | 72 | public void startLoading() { 73 | if (!isStop) { 74 | return; 75 | } 76 | textLength = getText().length(); 77 | if (TextUtils.isEmpty(getText().toString())) { 78 | return; 79 | } 80 | isLoading = true; 81 | isStop = false; 82 | text = getText(); 83 | 84 | scaleX = getTextScaleX() * 10; 85 | startY = 88; 86 | mPaint.setColor(getCurrentTextColor()); 87 | mPaint.setTextSize(getTextSize()); 88 | setMinWidth(getWidth()); 89 | setText(""); 90 | setHint(""); 91 | valueAnimator.start(); 92 | sigleDuration = 100f / textLength; 93 | } 94 | 95 | 96 | public void stopLoading() { 97 | isLoading = false; 98 | valueAnimator.end(); 99 | valueAnimator.cancel(); 100 | isStop = true; 101 | setText(text); 102 | } 103 | 104 | 105 | public void setDuration(int duration) { 106 | this.duration = duration; 107 | } 108 | 109 | 110 | @Override 111 | protected void onVisibilityChanged(View changedView, int visibility) { 112 | super.onVisibilityChanged(changedView, visibility); 113 | if (!isLoading) { 114 | return; 115 | } 116 | if (visibility == View.VISIBLE) { 117 | valueAnimator.resume(); 118 | } 119 | else { 120 | valueAnimator.pause(); 121 | } 122 | } 123 | 124 | 125 | @Override protected void onDraw(Canvas canvas) { 126 | super.onDraw(canvas); 127 | if (!isStop) { 128 | mPaint.setAlpha(255); 129 | if (progress / sigleDuration >= 1) { 130 | canvas.drawText(String.valueOf(text), 0, 131 | (int) (progress / sigleDuration), scaleX, startY, 132 | mPaint); 133 | } 134 | mPaint.setAlpha( 135 | (int) (255 * ((progress % sigleDuration) / sigleDuration))); 136 | int lastOne = (int) (progress / sigleDuration); 137 | if (lastOne < textLength) { 138 | canvas.drawText(String.valueOf(text.charAt(lastOne)), 0, 1, 139 | scaleX + getPaint().measureText( 140 | text.subSequence(0, lastOne).toString()), 141 | startY, mPaint); 142 | } 143 | } 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /app/src/main/java/com/codingbingo/fastreader/view/readview/BookStatus.java: -------------------------------------------------------------------------------- 1 | package com.codingbingo.fastreader.view.readview; 2 | 3 | /** 4 | * Author: bingo 5 | * Email: codingbingo@gmail.com 6 | * By 2017/2/14. 7 | */ 8 | public enum BookStatus { 9 | 10 | STATUS_OK, 11 | STATUS_DATABASE_ERROR, 12 | STATUS_FILE_NOT_FOUND_ERROR, 13 | 14 | NO_PRE_PAGE, 15 | NO_NEXT_PAGE, 16 | 17 | PRE_CHAPTER_LOAD_FAILURE, 18 | NEXT_CHAPTER_LOAD_FAILURE, 19 | 20 | LOAD_SUCCESS 21 | } 22 | -------------------------------------------------------------------------------- /app/src/main/java/com/codingbingo/fastreader/view/readview/interfaces/OnControllerStatusChangeListener.java: -------------------------------------------------------------------------------- 1 | package com.codingbingo.fastreader.view.readview.interfaces; 2 | 3 | /** 4 | * Author: bingo 5 | * Email: codingbingo@gmail.com 6 | * By 2017/3/11. 7 | */ 8 | public interface OnControllerStatusChangeListener { 9 | void onControllerStatusChange(boolean isShowing); 10 | } 11 | -------------------------------------------------------------------------------- /app/src/main/res/anim/bottom_in_animation.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/anim/bottom_out_animation.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/anim/top_in_animation.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/anim/top_out_animation.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/cat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodingBingo/FastReader/0e252ab46a4bf74d56e6fa8ea12c6c2d0d2bed03/app/src/main/res/drawable-hdpi/cat.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/eyes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodingBingo/FastReader/0e252ab46a4bf74d56e6fa8ea12c6c2d0d2bed03/app/src/main/res/drawable-hdpi/eyes.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/mouse.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodingBingo/FastReader/0e252ab46a4bf74d56e6fa8ea12c6c2d0d2bed03/app/src/main/res/drawable-hdpi/mouse.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/about.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodingBingo/FastReader/0e252ab46a4bf74d56e6fa8ea12c6c2d0d2bed03/app/src/main/res/drawable-xhdpi/about.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/add_book_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodingBingo/FastReader/0e252ab46a4bf74d56e6fa8ea12c6c2d0d2bed03/app/src/main/res/drawable-xhdpi/add_book_normal.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/add_book_pressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodingBingo/FastReader/0e252ab46a4bf74d56e6fa8ea12c6c2d0d2bed03/app/src/main/res/drawable-xhdpi/add_book_pressed.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/arrow_left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodingBingo/FastReader/0e252ab46a4bf74d56e6fa8ea12c6c2d0d2bed03/app/src/main/res/drawable-xhdpi/arrow_left.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/arrow_left_pressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodingBingo/FastReader/0e252ab46a4bf74d56e6fa8ea12c6c2d0d2bed03/app/src/main/res/drawable-xhdpi/arrow_left_pressed.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/arrow_left_white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodingBingo/FastReader/0e252ab46a4bf74d56e6fa8ea12c6c2d0d2bed03/app/src/main/res/drawable-xhdpi/arrow_left_white.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/arrow_right_white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodingBingo/FastReader/0e252ab46a4bf74d56e6fa8ea12c6c2d0d2bed03/app/src/main/res/drawable-xhdpi/arrow_right_white.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/book_tag_bg.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodingBingo/FastReader/0e252ab46a4bf74d56e6fa8ea12c6c2d0d2bed03/app/src/main/res/drawable-xhdpi/book_tag_bg.9.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodingBingo/FastReader/0e252ab46a4bf74d56e6fa8ea12c6c2d0d2bed03/app/src/main/res/drawable-xhdpi/dark.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/feedback.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodingBingo/FastReader/0e252ab46a4bf74d56e6fa8ea12c6c2d0d2bed03/app/src/main/res/drawable-xhdpi/feedback.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/file_import.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodingBingo/FastReader/0e252ab46a4bf74d56e6fa8ea12c6c2d0d2bed03/app/src/main/res/drawable-xhdpi/file_import.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/font_type.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodingBingo/FastReader/0e252ab46a4bf74d56e6fa8ea12c6c2d0d2bed03/app/src/main/res/drawable-xhdpi/font_type.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/lighten.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodingBingo/FastReader/0e252ab46a4bf74d56e6fa8ea12c6c2d0d2bed03/app/src/main/res/drawable-xhdpi/lighten.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/list.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodingBingo/FastReader/0e252ab46a4bf74d56e6fa8ea12c6c2d0d2bed03/app/src/main/res/drawable-xhdpi/list.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/menu_icon_black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodingBingo/FastReader/0e252ab46a4bf74d56e6fa8ea12c6c2d0d2bed03/app/src/main/res/drawable-xhdpi/menu_icon_black.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/menu_icon_grey.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodingBingo/FastReader/0e252ab46a4bf74d56e6fa8ea12c6c2d0d2bed03/app/src/main/res/drawable-xhdpi/menu_icon_grey.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/menu_icon_white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodingBingo/FastReader/0e252ab46a4bf74d56e6fa8ea12c6c2d0d2bed03/app/src/main/res/drawable-xhdpi/menu_icon_white.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/moon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodingBingo/FastReader/0e252ab46a4bf74d56e6fa8ea12c6c2d0d2bed03/app/src/main/res/drawable-xhdpi/moon.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/more.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodingBingo/FastReader/0e252ab46a4bf74d56e6fa8ea12c6c2d0d2bed03/app/src/main/res/drawable-xhdpi/more.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/reload.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodingBingo/FastReader/0e252ab46a4bf74d56e6fa8ea12c6c2d0d2bed03/app/src/main/res/drawable-xhdpi/reload.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/reload_pressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodingBingo/FastReader/0e252ab46a4bf74d56e6fa8ea12c6c2d0d2bed03/app/src/main/res/drawable-xhdpi/reload_pressed.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/search_icon_black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodingBingo/FastReader/0e252ab46a4bf74d56e6fa8ea12c6c2d0d2bed03/app/src/main/res/drawable-xhdpi/search_icon_black.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/search_icon_grey.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodingBingo/FastReader/0e252ab46a4bf74d56e6fa8ea12c6c2d0d2bed03/app/src/main/res/drawable-xhdpi/search_icon_grey.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/search_icon_white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodingBingo/FastReader/0e252ab46a4bf74d56e6fa8ea12c6c2d0d2bed03/app/src/main/res/drawable-xhdpi/search_icon_white.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/sun.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodingBingo/FastReader/0e252ab46a4bf74d56e6fa8ea12c6c2d0d2bed03/app/src/main/res/drawable-xhdpi/sun.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/top_panel_bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodingBingo/FastReader/0e252ab46a4bf74d56e6fa8ea12c6c2d0d2bed03/app/src/main/res/drawable-xhdpi/top_panel_bg.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xhdpi/txt_file_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodingBingo/FastReader/0e252ab46a4bf74d56e6fa8ea12c6c2d0d2bed03/app/src/main/res/drawable-xhdpi/txt_file_icon.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/add_book_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/arrow_left_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/custom_progress.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/dot.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/line_divider.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/main_menu_item_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/rectangle_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/reload_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_local_file_list.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | 14 | 23 | 24 | 32 | 33 | 42 | 43 | 44 | 45 | 50 | 51 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 17 | 18 | 22 | 23 | 24 | 30 | 31 | 32 | 38 | 39 | 40 | 41 | 42 | 47 | 48 | 57 | 58 | 67 | 68 | 77 | 78 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_reading.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/layout/book_list_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 14 | 15 | 27 | 28 | 40 | 41 | -------------------------------------------------------------------------------- /app/src/main/res/layout/bottom_sheet_dialog_fragment.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 14 | 15 | 19 | 20 | 28 | 29 | 30 | 31 | 38 | 39 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /app/src/main/res/layout/cat_loading.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 13 | 14 | 18 | 19 | 25 | 26 | 31 | 32 | 38 | 39 | 46 | 47 | 54 | 55 | 62 | 63 | 70 | 71 | 72 | 73 | 74 | 75 | 84 | 85 | 94 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /app/src/main/res/layout/chapter_list_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 15 | 16 | 17 | 26 | -------------------------------------------------------------------------------- /app/src/main/res/layout/file_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 17 | 18 | 24 | 25 | 31 | 32 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_chapter_list.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 14 | 15 | 24 | 25 | 33 | 34 | 35 | 40 | 41 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_reading.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 11 | 12 | 16 | 17 | 21 | 22 | -------------------------------------------------------------------------------- /app/src/main/res/layout/main_menu.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 16 | 17 | 21 | 22 | 30 | 31 | 32 | 33 | 38 | 39 | 47 | 48 | 52 | 53 | 61 | 62 | 63 | 64 | 69 | 70 | 78 | 79 | 83 | 84 | 92 | 93 | 94 | 95 | -------------------------------------------------------------------------------- /app/src/main/res/layout/read_background_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodingBingo/FastReader/0e252ab46a4bf74d56e6fa8ea12c6c2d0d2bed03/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 64dp 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3F51B5 4 | #303F9F 5 | #FF4081 6 | 7 | #ffffff 8 | #000000 9 | #cdcdcd 10 | 11 | #75DBCD 12 | #B5B2B5 13 | 14 | #2A2A2A 15 | #161A20 16 | #5A656F 17 | #3B3B3B 18 | 19 | 20 | #DFBF8D 21 | #EFE1C5 22 | #C6DFC6 23 | #EBEBEB 24 | #DFC1C1 25 | #6E7F6A 26 | 27 | 28 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 16dp 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 快读 3 | 添加图书 4 | 新添加 5 | 6 | 本地文件 7 | 本地书籍查看及导入 8 | 意见反馈 9 | 关于快读 10 | 11 | 章节列表 12 | 删除 13 | 文件解码中... 14 | L O A D I N G ... 15 | 夜间 16 | 设置 17 | A+ 18 | A- 19 | 20 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | 14 | 15 | -------------------------------------------------------------------------------- /app/src/test/java/com/codingbingo/fastreader/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.codingbingo.fastreader; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * @see Testing documentation 11 | */ 12 | public class ExampleUnitTest { 13 | @Test 14 | public void addition_isCorrect() throws Exception { 15 | assertEquals(4, 2 + 2); 16 | } 17 | } -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | mavenCentral() 7 | //这里是 LeanCloud 的包仓库 8 | maven { 9 | url "http://mvn.leancloud.cn/nexus/content/repositories/public" 10 | } 11 | } 12 | dependencies { 13 | classpath 'com.android.tools.build:gradle:2.2.3' 14 | } 15 | } 16 | 17 | allprojects { 18 | repositories { 19 | jcenter() 20 | //这里是 LeanCloud 的包仓库 21 | maven { 22 | url "http://mvn.leancloud.cn/nexus/content/repositories/public" 23 | } 24 | } 25 | } 26 | 27 | task clean(type: Delete) { 28 | delete rootProject.buildDir 29 | } 30 | -------------------------------------------------------------------------------- /database/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /database/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'java' 2 | 3 | dependencies { 4 | compile fileTree(include: ['*.jar'], dir: 'libs') 5 | compile files('libs/greendao-generator-3.2.0.jar') 6 | compile files('libs/freemarker-2.3.25-incubating.jar') 7 | } 8 | 9 | sourceCompatibility = "1.7" 10 | targetCompatibility = "1.7" 11 | -------------------------------------------------------------------------------- /database/libs/freemarker-2.3.25-incubating.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodingBingo/FastReader/0e252ab46a4bf74d56e6fa8ea12c6c2d0d2bed03/database/libs/freemarker-2.3.25-incubating.jar -------------------------------------------------------------------------------- /database/libs/greendao-generator-3.2.0.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodingBingo/FastReader/0e252ab46a4bf74d56e6fa8ea12c6c2d0d2bed03/database/libs/greendao-generator-3.2.0.jar -------------------------------------------------------------------------------- /database/src/main/java/com/codingbingo/Main.java: -------------------------------------------------------------------------------- 1 | package com.codingbingo; 2 | 3 | import org.greenrobot.greendao.generator.DaoGenerator; 4 | import org.greenrobot.greendao.generator.Entity; 5 | import org.greenrobot.greendao.generator.Property; 6 | import org.greenrobot.greendao.generator.Schema; 7 | 8 | public class Main { 9 | 10 | public static void main(String[] args) throws Exception{ 11 | Schema schema = new Schema(1, "com.codingbingo.fastreader.dao"); 12 | 13 | Entity book = schema.addEntity("Book"); 14 | 15 | book.addIdProperty().primaryKey().autoincrement(); 16 | book.addStringProperty("bookName").notNull(); 17 | book.addStringProperty("bookImagePath"); 18 | book.addStringProperty("description"); 19 | book.addStringProperty("tags"); 20 | book.addStringProperty("writer"); 21 | book.addStringProperty("charSet"); 22 | book.addStringProperty("bookPath"); 23 | 24 | book.addIntProperty("currentChapter"); 25 | book.addIntProperty("currentPosition"); 26 | book.addIntProperty("processStatus").notNull(); 27 | 28 | Entity chapter = schema.addEntity("Chapter"); 29 | 30 | chapter.addIdProperty().primaryKey().autoincrement(); 31 | chapter.addStringProperty("title"); 32 | chapter.addIntProperty("position").notNull(); 33 | chapter.addIntProperty("pageCount"); 34 | chapter.addBooleanProperty("isRead"); 35 | Property bookIdProperty = chapter.addLongProperty("bookId").notNull().getProperty(); 36 | chapter.addToOne(book, bookIdProperty); 37 | 38 | new DaoGenerator().generateAll(schema, "/Users/bingo/Git/FastReader/app/src/main/java"); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /doc/images/FileList.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodingBingo/FastReader/0e252ab46a4bf74d56e6fa8ea12c6c2d0d2bed03/doc/images/FileList.png -------------------------------------------------------------------------------- /doc/images/Loading.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodingBingo/FastReader/0e252ab46a4bf74d56e6fa8ea12c6c2d0d2bed03/doc/images/Loading.png -------------------------------------------------------------------------------- /doc/images/MainView.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodingBingo/FastReader/0e252ab46a4bf74d56e6fa8ea12c6c2d0d2bed03/doc/images/MainView.png -------------------------------------------------------------------------------- /doc/images/ReadingView.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodingBingo/FastReader/0e252ab46a4bf74d56e6fa8ea12c6c2d0d2bed03/doc/images/ReadingView.png -------------------------------------------------------------------------------- /doc/images/ReadingViewWithController.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodingBingo/FastReader/0e252ab46a4bf74d56e6fa8ea12c6c2d0d2bed03/doc/images/ReadingViewWithController.png -------------------------------------------------------------------------------- /doc/images/ReadingViewWithStyleController.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodingBingo/FastReader/0e252ab46a4bf74d56e6fa8ea12c6c2d0d2bed03/doc/images/ReadingViewWithStyleController.png -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | org.gradle.jvmargs=-Xmx1536m 13 | 14 | # When configured, Gradle will run in incubating parallel mode. 15 | # This option should only be used with decoupled projects. More details, visit 16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 17 | # org.gradle.parallel=true -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodingBingo/FastReader/0e252ab46a4bf74d56e6fa8ea12c6c2d0d2bed03/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Mon Dec 28 10:00:20 PST 2015 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app', ':database' 2 | --------------------------------------------------------------------------------