├── .gitignore ├── .idea ├── compiler.xml ├── copyright │ └── profiles_settings.xml ├── inspectionProfiles │ ├── Project_Default.xml │ └── profiles_settings.xml ├── misc.xml ├── modules.xml ├── runConfigurations.xml └── vcs.xml ├── LICENSE ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── delsart │ │ └── bookdownload │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── delsart │ │ │ └── bookdownload │ │ │ ├── MsgType.java │ │ │ ├── MyApplication.java │ │ │ ├── SplashActivity.java │ │ │ ├── Url.java │ │ │ ├── adapter │ │ │ ├── ItemAdapter.java │ │ │ ├── MyItemAdapter.java │ │ │ └── PagerAdapter.java │ │ │ ├── bean │ │ │ ├── DownloadBean.java │ │ │ └── NovelBean.java │ │ │ ├── custom │ │ │ ├── CustomTextView.java │ │ │ ├── MyCustomItem.java │ │ │ ├── MyViewTypeManager.java │ │ │ └── ScrollAwareFABBehavior.java │ │ │ ├── glide │ │ │ └── MyGlideModule.java │ │ │ ├── handler │ │ │ ├── MyCrashHandler.java │ │ │ ├── MyHandler.java │ │ │ └── OnHandleMessageCallback.java │ │ │ ├── service │ │ │ ├── AiXiaService.java │ │ │ ├── BaseService.java │ │ │ ├── BlahService.java │ │ │ ├── DongManZhiJiaService.java │ │ │ ├── EpubeeService.java │ │ │ ├── M360DService.java │ │ │ ├── QiShuService.java │ │ │ ├── ShuYuZheService.java │ │ │ ├── XiaoShuWuService.java │ │ │ ├── ZhiXuanService.java │ │ │ └── ZhouDuService.java │ │ │ ├── ui │ │ │ ├── activity │ │ │ │ ├── AboutActivity.java │ │ │ │ ├── MainActivity.java │ │ │ │ ├── SettingsActivity.java │ │ │ │ └── UsedOpenSource.java │ │ │ └── fragment │ │ │ │ ├── AiXiaFragment.java │ │ │ │ ├── BaseFragment.java │ │ │ │ ├── BlahFragment.java │ │ │ │ ├── DongManZhiJiaFragment.java │ │ │ │ ├── M360DFragment.java │ │ │ │ ├── QiShuFragment.java │ │ │ │ ├── ShuYuZheFragment.java │ │ │ │ ├── XiaoShuWuFragment.java │ │ │ │ ├── ZhiXuanFragment.java │ │ │ │ └── ZhouDuFragment.java │ │ │ └── utils │ │ │ └── StatusBarUtils.java │ └── res │ │ ├── anim │ │ └── enter_anim.xml │ │ ├── layout │ │ ├── activity_main.xml │ │ ├── item_custom.xml │ │ ├── item_list.xml │ │ ├── recycler_view.xml │ │ ├── view_dialog.xml │ │ ├── view_no_found.xml │ │ ├── view_no_search.xml │ │ └── view_searching.xml │ │ ├── menu │ │ └── menu.xml │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_round.png │ │ └── ic_to_top.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ ├── ic_launcher_round.png │ │ ├── ic_no_found.png │ │ └── ic_no_search.png │ │ ├── values-v23 │ │ └── styles.xml │ │ ├── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ │ └── xml │ │ └── settinglayout.xml │ └── test │ └── java │ └── com │ └── delsart │ └── bookdownload │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle └── 更新日志.txt /.gitignore: -------------------------------------------------------------------------------- 1 | # Built application files 2 | *.apk 3 | *.ap_ 4 | 5 | # Files for the ART/Dalvik VM 6 | *.dex 7 | 8 | # Java class files 9 | *.class 10 | 11 | # Generated files 12 | bin/ 13 | gen/ 14 | out/ 15 | 16 | # Gradle files 17 | .gradle/ 18 | build/ 19 | 20 | # Local configuration file (sdk path, etc) 21 | local.properties 22 | 23 | # Proguard folder generated by Eclipse 24 | proguard/ 25 | 26 | # Log Files 27 | *.log 28 | 29 | # Android Studio Navigation editor temp files 30 | .navigation/ 31 | 32 | # Android Studio captures folder 33 | captures/ 34 | 35 | # Intellij 36 | *.iml 37 | .idea/workspace.xml 38 | .idea/tasks.xml 39 | .idea/gradle.xml 40 | .idea/dictionaries 41 | .idea/libraries 42 | 43 | # Keystore files 44 | *.jks 45 | 46 | # External native build folder generated in Android Studio 2.2 and later 47 | .externalNativeBuild 48 | 49 | # Google Services (e.g. APIs or Firebase) 50 | google-services.json 51 | 52 | # Freeline 53 | freeline.py 54 | freeline/ 55 | freeline_project_description.json 56 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 19 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 46 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Bookster 2 | 聚合类书籍搜索软件 3 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 25 5 | buildToolsVersion "26.0.1" 6 | defaultConfig { 7 | applicationId "com.delsart.bookdownload" 8 | minSdkVersion 14 9 | targetSdkVersion 25 10 | versionCode 151 11 | versionName "1.51" 12 | resConfigs "zh" 13 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 14 | } 15 | buildTypes { 16 | release { 17 | minifyEnabled true 18 | shrinkResources true 19 | zipAlignEnabled true 20 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 21 | } 22 | } 23 | } 24 | 25 | dependencies { 26 | compile fileTree(dir: 'libs', include: ['*.jar']) 27 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { 28 | exclude group: 'com.android.support', module: 'support-annotations' 29 | }) 30 | compile 'com.android.support:appcompat-v7:25.3.1' 31 | compile 'com.android.support:design:25.3.1' 32 | compile 'org.jsoup:jsoup:1.10.1' 33 | compile 'com.github.daniel-stoneuk:material-about-library:2.1.0' 34 | compile 'com.mikepenz:iconics-core:2.8.2@aar' 35 | compile 'com.mikepenz:community-material-typeface:1.7.22.1@aar' 36 | compile 'com.android.support:support-v4:25.3.1' 37 | compile 'moe.feng:AlipayZeroSdk:1.1' 38 | compile 'com.github.bumptech.glide:glide:4.0.0-RC1' 39 | annotationProcessor 'com.github.bumptech.glide:compiler:4.0.0-RC1' 40 | compile 'com.github.CymChad:BaseRecyclerViewAdapterHelper:2.9.22' 41 | testCompile 'junit:junit:4.12' 42 | // debugCompile 'com.squareup.leakcanary:leakcanary-android:1.5.1' 43 | // releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.1' 44 | // testCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.1' 45 | } 46 | -------------------------------------------------------------------------------- /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 C:\Users\star\AppData\Local\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 | # Uncomment this to preserve the line number information for 20 | # debugging stack traces. 21 | #-keepattributes SourceFile,LineNumberTable 22 | 23 | # If you keep the line number information, uncomment this to 24 | # hide the original source file name. 25 | #-renamesourcefileattribute SourceFile 26 | 27 | 28 | -optimizationpasses 5 29 | -dontusemixedcaseclassnames 30 | -dontskipnonpubliclibraryclasses 31 | -dontskipnonpubliclibraryclassmembers 32 | -dontpreverify 33 | -verbose 34 | -printmapping proguardMapping.txt 35 | -optimizations !code/simplification/cast,!field/*,!class/merging/* 36 | -keepattributes *Annotation*,InnerClasses 37 | -keepattributes Signature 38 | -keepattributes SourceFile,LineNumberTable 39 | 40 | -ignorewarnings 41 | 42 | 43 | # fresco 44 | # Keep our interfaces so they can be used by other ProGuard rules. 45 | # See http://sourceforge.net/p/proguard/bugs/466/ 46 | -keep,allowobfuscation @interface com.facebook.common.internal.DoNotStrip 47 | 48 | # Do not strip any method/class that is annotated with @DoNotStrip 49 | -keep @com.facebook.common.internal.DoNotStrip class * 50 | -keepclassmembers class * { 51 | @com.facebook.common.internal.DoNotStrip *; 52 | } 53 | 54 | # Keep native methods 55 | -keepclassmembers class * { 56 | native ; 57 | } 58 | 59 | -dontwarn okio.** 60 | -dontwarn com.squareup.okhttp.** 61 | -dontwarn okhttp3.** 62 | -dontwarn javax.annotation.** 63 | -dontwarn com.android.volley.toolbox.** 64 | -dontwarn com.facebook.infer.** 65 | 66 | # MeiZuFingerprint 67 | -keep class com.fingerprints.service.** { *; } 68 | 69 | # SmsungFingerprint 70 | -keep class com.samsung.android.sdk.** { *; } 71 | 72 | #jsoup 73 | -keep class org.jsoup.** { *; } 74 | 75 | #okio 76 | -dontwarn okio.** 77 | 78 | #okhttp 79 | -dontwarn javax.annotation.Nullable 80 | -dontwarn javax.annotation.ParametersAreNonnullByDefault 81 | 82 | #retrofit 83 | -dontwarn retrofit2.** 84 | -keep class retrofit2.** { *; } 85 | # Platform calls Class.forName on types which do not exist on Android to determine platform. 86 | -dontnote retrofit2.Platform 87 | # Platform used when running on Java 8 VMs. Will not be used at runtime. 88 | -dontwarn retrofit2.Platform$Java8 89 | # Retain generic type information for use by reflection by converters and adapters. 90 | -keepattributes Signature 91 | # Retain declared checked exceptions for use by a Proxy instance. 92 | -keepattributes Exceptions 93 | 94 | #Glide 95 | -keep public class * implements com.bumptech.glide.module.GlideModule 96 | -keep public class * extends com.bumptech.glide.AppGlideModule 97 | -keep public enum com.bumptech.glide.load.resource.bitmap.ImageHeaderParser$** { 98 | **[] $VALUES; 99 | public *; 100 | } 101 | 102 | #evenbus 103 | -keepclassmembers class ** { 104 | @org.greenrobot.eventbus.Subscribe ; 105 | } 106 | -keep enum org.greenrobot.eventbus.ThreadMode { *; } 107 | 108 | -keep public class * extends android.app.Activity 109 | -keep public class * extends android.app.Application 110 | -keep public class * extends android.app.Service 111 | -keep public class * extends android.content.BroadcastReceiver 112 | -keep public class * extends android.content.ContentProvider 113 | -keep public class * extends android.app.backup.BackupAgentHelper 114 | -keep public class * extends android.preference.Preference 115 | -keep public class * extends android.view.View 116 | -keep public class com.android.vending.licensing.ILicensingService 117 | -keep class android.support.** {*;} 118 | 119 | -keepclasseswithmembernames class * { 120 | native ; 121 | } 122 | -keepclassmembers class * extends android.app.Activity{ 123 | public void *(android.view.View); 124 | } 125 | -keepclassmembers enum * { 126 | public static **[] values(); 127 | public static ** valueOf(java.lang.String); 128 | } 129 | -keep public class * extends android.view.View{ 130 | *** get*(); 131 | void set*(***); 132 | public (android.content.Context); 133 | public (android.content.Context, android.util.AttributeSet); 134 | public (android.content.Context, android.util.AttributeSet, int); 135 | } 136 | -keepclasseswithmembers class * { 137 | public (android.content.Context, android.util.AttributeSet); 138 | public (android.content.Context, android.util.AttributeSet, int); 139 | } 140 | -keep class * implements android.os.Parcelable { 141 | public static final android.os.Parcelable$Creator *; 142 | } 143 | -keepclassmembers class * implements java.io.Serializable { 144 | static final long serialVersionUID; 145 | private static final java.io.ObjectStreamField[] serialPersistentFields; 146 | private void writeObject(java.io.ObjectOutputStream); 147 | private void readObject(java.io.ObjectInputStream); 148 | java.lang.Object writeReplace(); 149 | java.lang.Object readResolve(); 150 | } 151 | -keep class **.R$* { 152 | *; 153 | } 154 | -keepclassmembers class * { 155 | void *(**On*Event); 156 | } -------------------------------------------------------------------------------- /app/src/androidTest/java/com/delsart/bookdownload/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.delsart.bookdownload; 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.delsart.bookdownload", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 16 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 29 | 30 | 31 | 35 | 39 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /app/src/main/java/com/delsart/bookdownload/MsgType.java: -------------------------------------------------------------------------------- 1 | package com.delsart.bookdownload; 2 | 3 | 4 | public interface MsgType { 5 | int ERROR = 0; 6 | int SUCCESS = 1; 7 | int RESULT = 1; 8 | int LOAD_MORE_VIEW = 2; 9 | } 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/java/com/delsart/bookdownload/MyApplication.java: -------------------------------------------------------------------------------- 1 | package com.delsart.bookdownload; 2 | 3 | import android.annotation.SuppressLint; 4 | import android.app.Application; 5 | import android.content.Context; 6 | import android.preference.PreferenceManager; 7 | 8 | import com.delsart.bookdownload.handler.MyCrashHandler; 9 | 10 | /** 11 | * Created by Delsart on 2017/7/30. 12 | */ 13 | public class MyApplication extends Application { 14 | @SuppressLint("StaticFieldLeak") 15 | private static Context context; 16 | 17 | public static Context getContext() { 18 | return context; 19 | } 20 | 21 | @Override 22 | public void onCreate() { 23 | // LeakCanary.install(this); 24 | context = getApplicationContext(); 25 | // MyCrashHandler myCrashHandler = MyCrashHandler.getInstance(); 26 | // myCrashHandler.init(getApplicationContext()); 27 | } 28 | } -------------------------------------------------------------------------------- /app/src/main/java/com/delsart/bookdownload/SplashActivity.java: -------------------------------------------------------------------------------- 1 | package com.delsart.bookdownload; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import android.support.v7.app.AppCompatActivity; 6 | 7 | import com.delsart.bookdownload.ui.activity.MainActivity; 8 | 9 | /** 10 | * Created by Delsart on 2017/8/11. 11 | */ 12 | 13 | public class SplashActivity extends AppCompatActivity { 14 | @Override 15 | protected void onCreate(Bundle savedInstanceState) { 16 | 17 | super.onCreate(savedInstanceState); 18 | 19 | startActivity(new Intent(this, MainActivity.class)); 20 | 21 | finish(); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /app/src/main/java/com/delsart/bookdownload/Url.java: -------------------------------------------------------------------------------- 1 | package com.delsart.bookdownload; 2 | 3 | 4 | public interface Url { 5 | String PC_AGENT = "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.78 Safari/537.36"; 6 | String MOBBILE_AGENT = "Mozilla/5.0 (iPhone; CPU iPhone OS 8_0 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) Version/8.0 Mobile/12A365 Safari/600.1.4"; 7 | 8 | String ZHIXUAN = "http://www.zxcs8.com/?keyword="; 9 | String ZHOUDU = "http://www.ireadweek.com/index.php/Index/bookList.html?keyword="; 10 | String M360D = "http://www.360dxs.com/list.html?keyword="; 11 | String SHUYUZHE = "https://book.shuyuzhe.com/search/"; 12 | String XIAOSHUWU = "http://mebook.cc/page/0?s="; 13 | String QISHU = "http://zhannei.baidu.com/cse/search?s=2672242722776283010&nsid=&q="; 14 | String AIXIA = "http://m.ixdzs.com/search?k="; 15 | String BLAH = "http://blah.me/search?q="; 16 | String DONGMANZHIJIA="http://s.acg.dmzj.com/lnovelsum/search.php?s="; 17 | } 18 | 19 | 20 | -------------------------------------------------------------------------------- /app/src/main/java/com/delsart/bookdownload/adapter/ItemAdapter.java: -------------------------------------------------------------------------------- 1 | package com.delsart.bookdownload.adapter; 2 | 3 | import android.support.v7.widget.RecyclerView; 4 | import android.view.LayoutInflater; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | import android.widget.TextView; 8 | 9 | import com.delsart.bookdownload.R; 10 | import com.delsart.bookdownload.bean.NovelBean; 11 | 12 | import java.util.ArrayList; 13 | import java.util.List; 14 | 15 | 16 | public class ItemAdapter extends RecyclerView.Adapter { 17 | 18 | private List mList; 19 | 20 | public ItemAdapter() { 21 | mList = new ArrayList<>(); 22 | } 23 | 24 | @Override 25 | public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 26 | return new MyViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_list, parent, false)); 27 | } 28 | 29 | @Override 30 | public void onBindViewHolder(MyViewHolder holder, int position) { 31 | NovelBean bean = mList.get(position); 32 | holder.mTextViewName.setText(bean.getName()); 33 | holder.mTextViewInfo.setText(bean.getShowText()); 34 | } 35 | 36 | @Override 37 | public int getItemCount() { 38 | return mList.size(); 39 | } 40 | 41 | public void clear() { 42 | int size = mList.size(); 43 | mList.clear(); 44 | notifyItemRangeRemoved(0, size); 45 | } 46 | 47 | public void add(List beans) { 48 | int size = mList.size(); 49 | mList.addAll(beans); 50 | notifyItemRangeInserted(size, beans.size()); 51 | } 52 | 53 | static class MyViewHolder extends RecyclerView.ViewHolder { 54 | private TextView mTextViewName; 55 | private TextView mTextViewInfo; 56 | 57 | public MyViewHolder(View itemView) { 58 | super(itemView); 59 | mTextViewInfo = (TextView) itemView.findViewById(R.id.text_view_info); 60 | mTextViewName = (TextView) itemView.findViewById(R.id.text_view_name); 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /app/src/main/java/com/delsart/bookdownload/adapter/MyItemAdapter.java: -------------------------------------------------------------------------------- 1 | package com.delsart.bookdownload.adapter; 2 | 3 | import com.chad.library.adapter.base.BaseQuickAdapter; 4 | import com.chad.library.adapter.base.BaseViewHolder; 5 | import com.delsart.bookdownload.R; 6 | import com.delsart.bookdownload.bean.NovelBean; 7 | 8 | /** 9 | * Created by Delsart on 2017/8/1. 10 | */ 11 | 12 | public class MyItemAdapter extends BaseQuickAdapter { 13 | private int color; 14 | public MyItemAdapter(int color) { 15 | super(R.layout.item_list); 16 | this.color=color; 17 | } 18 | 19 | @Override 20 | protected void convert(BaseViewHolder viewHolder, NovelBean bean) { 21 | viewHolder.setText(R.id.text_view_name, bean.getName()) 22 | .setText(R.id.text_view_info, bean.getShowText()) 23 | .setBackgroundColor(R.id.text_view_name,color) 24 | .setBackgroundColor(R.id.text_view_info,color); 25 | } 26 | } -------------------------------------------------------------------------------- /app/src/main/java/com/delsart/bookdownload/adapter/PagerAdapter.java: -------------------------------------------------------------------------------- 1 | package com.delsart.bookdownload.adapter; 2 | 3 | import android.support.v4.app.Fragment; 4 | import android.support.v4.app.FragmentManager; 5 | import android.support.v4.app.FragmentStatePagerAdapter; 6 | 7 | import com.delsart.bookdownload.ui.fragment.BaseFragment; 8 | 9 | import java.util.List; 10 | 11 | public class PagerAdapter extends FragmentStatePagerAdapter { 12 | private final List mFragments; 13 | private final List mFragmentTitles; 14 | 15 | public PagerAdapter(FragmentManager fm, List fragments, List titles) { 16 | super(fm); 17 | this.mFragments = fragments; 18 | this.mFragmentTitles = titles; 19 | } 20 | 21 | public void setTop(int pos) { 22 | mFragments.get(pos).toTop(); 23 | } 24 | 25 | @Override 26 | public Fragment getItem(int position) { 27 | return mFragments.get(position); 28 | } 29 | 30 | @Override 31 | public int getCount() { 32 | return mFragments.size(); 33 | } 34 | 35 | public void remove() { 36 | if (mFragments.size() > 0) { 37 | mFragments.remove(0); 38 | mFragmentTitles.remove(0); 39 | notifyDataSetChanged(); 40 | } 41 | } 42 | 43 | public List getFragments() { 44 | return mFragments; 45 | } 46 | 47 | @Override 48 | public CharSequence getPageTitle(int position) { 49 | return mFragmentTitles.get(position); 50 | } 51 | } -------------------------------------------------------------------------------- /app/src/main/java/com/delsart/bookdownload/bean/DownloadBean.java: -------------------------------------------------------------------------------- 1 | package com.delsart.bookdownload.bean; 2 | 3 | /** 4 | * Created by Delsart on 2017/8/2. 5 | */ 6 | 7 | public class DownloadBean { 8 | String type; 9 | 10 | String url; 11 | 12 | public DownloadBean(String type, String url) { 13 | this.type = type; 14 | this.url = url; 15 | } 16 | 17 | public DownloadBean() { 18 | } 19 | 20 | public String getType() { 21 | return type; 22 | } 23 | 24 | public String getUrl() { 25 | return url; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /app/src/main/java/com/delsart/bookdownload/bean/NovelBean.java: -------------------------------------------------------------------------------- 1 | package com.delsart.bookdownload.bean; 2 | 3 | public class NovelBean { 4 | private String name; 5 | private String time; 6 | private String info; 7 | private String category; 8 | private String status; 9 | private String author; 10 | private String words; 11 | private String pic; 12 | private String showText; 13 | private String downloadFromUrl; 14 | 15 | public NovelBean(String name, String time, String info, String category, String status, String author, String words, String pic, String downloadFromUrl) { 16 | this.name = name; 17 | this.time = time; 18 | this.info = info; 19 | this.category = category; 20 | this.status = status; 21 | this.author = author; 22 | this.words = words; 23 | this.pic = pic; 24 | this.downloadFromUrl = downloadFromUrl; 25 | 26 | this.showText = (author.equals("") ? "" : author + "\n") + 27 | (category.equals("") ? "" : category + "\n") + 28 | (words.equals("") ? "" : words + "\n") + 29 | (status.equals("") ? "" : status + "\n") + 30 | (time.equals("") ? "" : time + "\n") + 31 | (info.equals("") ? "\n" + "无简介" : "\n" + info); 32 | } 33 | 34 | public String getDownloadFromUrl() { 35 | return downloadFromUrl; 36 | } 37 | 38 | public String getName() { 39 | return name; 40 | } 41 | 42 | public String getTime() { 43 | return time; 44 | } 45 | 46 | public String getInfo() { 47 | return info; 48 | } 49 | 50 | public String getCategory() { 51 | return category; 52 | } 53 | 54 | public String getStatus() { 55 | return status; 56 | } 57 | 58 | public String getAuthor() { 59 | return author; 60 | } 61 | 62 | public String getWords() { 63 | return words; 64 | } 65 | 66 | public String getPic() { 67 | return pic; 68 | } 69 | 70 | 71 | public String getShowText() { 72 | return showText; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /app/src/main/java/com/delsart/bookdownload/custom/CustomTextView.java: -------------------------------------------------------------------------------- 1 | package com.delsart.bookdownload.custom; 2 | 3 | import android.content.Context; 4 | import android.graphics.Canvas; 5 | import android.graphics.Paint; 6 | import android.support.annotation.ColorInt; 7 | import android.util.AttributeSet; 8 | import android.util.Log; 9 | 10 | /** 11 | * Created by Delsart on 2017/7/28. 12 | */ 13 | 14 | public class CustomTextView extends android.support.v7.widget.AppCompatTextView { 15 | 16 | private Paint mPaint; 17 | private int mColor; 18 | 19 | @Override 20 | public void setBackgroundColor(@ColorInt int color) { 21 | mColor =color; 22 | mPaint.setColor(mColor); 23 | } 24 | 25 | public CustomTextView(Context context) { 26 | super(context); 27 | initPaint(context); 28 | } 29 | 30 | public CustomTextView(Context context, AttributeSet attrs) { 31 | super(context, attrs); 32 | initPaint(context); 33 | } 34 | 35 | public CustomTextView(Context context, AttributeSet attrs, int defStyleAttr) { 36 | super(context, attrs, defStyleAttr); 37 | initPaint(context); 38 | } 39 | 40 | private void initPaint(Context context) { 41 | mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); 42 | mPaint.setStrokeWidth(2.5f); 43 | mPaint.setColor(mColor); 44 | } 45 | 46 | 47 | @Override 48 | protected void onDraw(Canvas canvas) { 49 | int w = getWidth(); 50 | int h = getHeight(); 51 | canvas.clipRect(0, 0, w, h); 52 | super.onDraw(canvas); 53 | canvas.drawLine(0, h, w, h, mPaint); 54 | canvas.drawLine(w, h / 1.8f, w, h, mPaint); 55 | canvas.drawLine(0, h / 1.2f, 0, h, mPaint); 56 | 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /app/src/main/java/com/delsart/bookdownload/custom/MyCustomItem.java: -------------------------------------------------------------------------------- 1 | package com.delsart.bookdownload.custom; 2 | 3 | import android.content.Context; 4 | import android.graphics.drawable.Drawable; 5 | import android.os.Build; 6 | import android.support.annotation.DrawableRes; 7 | import android.support.annotation.IntDef; 8 | import android.support.annotation.StringRes; 9 | import android.text.Html; 10 | import android.util.TypedValue; 11 | import android.view.Gravity; 12 | import android.view.View; 13 | import android.widget.ImageView; 14 | import android.widget.LinearLayout; 15 | import android.widget.TextView; 16 | 17 | import com.danielstone.materialaboutlibrary.holders.MaterialAboutItemViewHolder; 18 | import com.danielstone.materialaboutlibrary.items.MaterialAboutItem; 19 | import com.delsart.bookdownload.R; 20 | 21 | import java.lang.annotation.Retention; 22 | import java.lang.annotation.RetentionPolicy; 23 | 24 | import static android.view.View.GONE; 25 | 26 | /** 27 | * Created by Delsart on 2017/7/24. 28 | */ 29 | 30 | public class MyCustomItem extends MaterialAboutItem { 31 | 32 | public static final int GRAVITY_TOP = 0; 33 | public static final int GRAVITY_MIDDLE = 1; 34 | public static final int GRAVITY_BOTTOM = 2; 35 | private CharSequence text = null; 36 | private int textRes = 0; 37 | private CharSequence subText = null; 38 | private int subTextRes = 0; 39 | private Drawable icon = null; 40 | private int iconRes = 0; 41 | private boolean showIcon = true; 42 | private int iconGravity = GRAVITY_MIDDLE; 43 | private MyCustomItem.OnClickListener onClickListener = null; 44 | private MyCustomItem(Builder builder) { 45 | this.text = builder.text; 46 | this.textRes = builder.textRes; 47 | 48 | this.subText = builder.subText; 49 | this.subTextRes = builder.subTextRes; 50 | 51 | this.icon = builder.icon; 52 | this.iconRes = builder.iconRes; 53 | 54 | this.showIcon = builder.showIcon; 55 | 56 | this.iconGravity = builder.iconGravity; 57 | 58 | this.onClickListener = builder.onClickListener; 59 | } 60 | 61 | public MyCustomItem(CharSequence text, CharSequence subText, Drawable icon, OnClickListener onClickListener) { 62 | this.text = text; 63 | this.subText = subText; 64 | this.icon = icon; 65 | this.onClickListener = onClickListener; 66 | } 67 | 68 | public MyCustomItem(CharSequence text, CharSequence subText, Drawable icon) { 69 | this.text = text; 70 | this.subText = subText; 71 | this.icon = icon; 72 | } 73 | 74 | public MyCustomItem(int textRes, int subTextRes, int iconRes, OnClickListener onClickListener) { 75 | this.textRes = textRes; 76 | this.subTextRes = subTextRes; 77 | this.iconRes = iconRes; 78 | this.onClickListener = onClickListener; 79 | } 80 | 81 | public MyCustomItem(int textRes, int subTextRes, int iconRes) { 82 | this.textRes = textRes; 83 | this.subTextRes = subTextRes; 84 | this.iconRes = iconRes; 85 | } 86 | 87 | public static MaterialAboutItemViewHolder getViewHolder(View view) { 88 | return new MyCustomItemViewHolder(view); 89 | } 90 | 91 | public static void setupItem(MyCustomItemViewHolder holder, MyCustomItem item, Context context) { 92 | CharSequence text = item.getText(); 93 | int textRes = item.getTextRes(); 94 | 95 | holder.text.setVisibility(View.VISIBLE); 96 | if (text != null) { 97 | holder.text.setText(text); 98 | } else if (textRes != 0) { 99 | holder.text.setText(textRes); 100 | } else { 101 | holder.text.setVisibility(GONE); 102 | } 103 | 104 | CharSequence subText = item.getSubText(); 105 | int subTextRes = item.getSubTextRes(); 106 | 107 | holder.subText.setVisibility(View.VISIBLE); 108 | if (subText != null) { 109 | holder.subText.setText(subText); 110 | } else if (subTextRes != 0) { 111 | holder.subText.setText(subTextRes); 112 | } else { 113 | holder.subText.setVisibility(GONE); 114 | } 115 | 116 | if (item.shouldShowIcon()) { 117 | holder.icon.setVisibility(View.VISIBLE); 118 | Drawable drawable = item.getIcon(); 119 | int drawableRes = item.getIconRes(); 120 | if (drawable != null) { 121 | holder.icon.setImageDrawable(drawable); 122 | } else if (drawableRes != 0) { 123 | holder.icon.setImageResource(drawableRes); 124 | } 125 | } else { 126 | holder.icon.setVisibility(GONE); 127 | } 128 | 129 | LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) holder.icon.getLayoutParams(); 130 | switch (item.getIconGravity()) { 131 | case MyCustomItem.GRAVITY_TOP: 132 | params.gravity = Gravity.TOP; 133 | break; 134 | case MyCustomItem.GRAVITY_MIDDLE: 135 | params.gravity = Gravity.CENTER_VERTICAL; 136 | break; 137 | case MyCustomItem.GRAVITY_BOTTOM: 138 | params.gravity = Gravity.BOTTOM; 139 | break; 140 | } 141 | holder.icon.setLayoutParams(params); 142 | 143 | int pL = 0, pT = 0, pR = 0, pB = 0; 144 | if (Build.VERSION.SDK_INT < 21) { 145 | pL = holder.view.getPaddingLeft(); 146 | pT = holder.view.getPaddingTop(); 147 | pR = holder.view.getPaddingRight(); 148 | pB = holder.view.getPaddingBottom(); 149 | } 150 | 151 | if (item.getOnClickListener() != null) { 152 | TypedValue outValue = new TypedValue(); 153 | context.getTheme().resolveAttribute(R.attr.selectableItemBackground, outValue, true); 154 | holder.view.setBackgroundResource(outValue.resourceId); 155 | holder.onClickListener = item.getOnClickListener(); 156 | holder.view.setSoundEffectsEnabled(true); 157 | } else { 158 | TypedValue outValue = new TypedValue(); 159 | context.getTheme().resolveAttribute(R.attr.selectableItemBackground, outValue, false); 160 | holder.view.setBackgroundResource(outValue.resourceId); 161 | holder.onClickListener = null; 162 | holder.view.setSoundEffectsEnabled(false); 163 | } 164 | 165 | if (Build.VERSION.SDK_INT < 21) { 166 | holder.view.setPadding(pL, pT, pR, pB); 167 | } 168 | } 169 | 170 | @Override 171 | public int getType() { 172 | return MyViewTypeManager.CUSTOM_ITEM; 173 | } 174 | 175 | public CharSequence getText() { 176 | return text; 177 | } 178 | 179 | public int getTextRes() { 180 | return textRes; 181 | } 182 | 183 | public CharSequence getSubText() { 184 | return subText; 185 | } 186 | 187 | public int getSubTextRes() { 188 | return subTextRes; 189 | } 190 | 191 | public Drawable getIcon() { 192 | return icon; 193 | } 194 | 195 | public int getIconRes() { 196 | return iconRes; 197 | } 198 | 199 | public boolean shouldShowIcon() { 200 | return showIcon; 201 | } 202 | 203 | @IconGravity 204 | public int getIconGravity() { 205 | return iconGravity; 206 | } 207 | 208 | public MyCustomItem.OnClickListener getOnClickListener() { 209 | return onClickListener; 210 | } 211 | 212 | public interface OnClickListener { 213 | void onClick(); 214 | 215 | } 216 | 217 | @Retention(RetentionPolicy.SOURCE) 218 | @IntDef({GRAVITY_TOP, GRAVITY_MIDDLE, GRAVITY_BOTTOM}) 219 | public @interface IconGravity { 220 | } 221 | 222 | public static class MyCustomItemViewHolder extends MaterialAboutItemViewHolder implements View.OnClickListener { 223 | public final View view; 224 | public final ImageView icon; 225 | public final TextView text; 226 | public final TextView subText; 227 | public MyCustomItem.OnClickListener onClickListener; 228 | 229 | MyCustomItemViewHolder(View view) { 230 | super(view); 231 | this.view = view; 232 | icon = (ImageView) view.findViewById(R.id.mal_item_image); 233 | text = (TextView) view.findViewById(R.id.mal_item_text); 234 | subText = (TextView) view.findViewById(R.id.mal_action_item_subtext); 235 | 236 | view.setOnClickListener(this); 237 | onClickListener = null; 238 | } 239 | 240 | @Override 241 | public void onClick(View v) { 242 | if (onClickListener != null) { 243 | onClickListener.onClick(); 244 | } 245 | } 246 | } 247 | 248 | public static class Builder { 249 | 250 | MyCustomItem.OnClickListener onClickListener; 251 | private CharSequence text = null; 252 | @StringRes 253 | private int textRes = 0; 254 | private CharSequence subText = null; 255 | @StringRes 256 | private int subTextRes = 0; 257 | private Drawable icon = null; 258 | @DrawableRes 259 | private int iconRes = 0; 260 | private boolean showIcon = true; 261 | @IconGravity 262 | private int iconGravity = GRAVITY_MIDDLE; 263 | 264 | public Builder text(CharSequence text) { 265 | this.text = text; 266 | this.textRes = 0; 267 | return this; 268 | } 269 | 270 | public Builder text(@StringRes int text) { 271 | this.textRes = text; 272 | this.text = null; 273 | return this; 274 | } 275 | 276 | public Builder subText(CharSequence subText) { 277 | this.subText = subText; 278 | this.subTextRes = 0; 279 | return this; 280 | } 281 | 282 | public Builder subText(@StringRes int subTextRes) { 283 | this.subText = null; 284 | this.subTextRes = subTextRes; 285 | return this; 286 | } 287 | 288 | public Builder subTextHtml(String subTextHtml) { 289 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { 290 | this.subText = Html.fromHtml(subTextHtml, Html.FROM_HTML_MODE_LEGACY); 291 | } else { 292 | //noinspection deprecation 293 | this.subText = Html.fromHtml(subTextHtml); 294 | } 295 | this.subTextRes = 0; 296 | return this; 297 | } 298 | 299 | public Builder icon(Drawable icon) { 300 | this.icon = icon; 301 | this.iconRes = 0; 302 | return this; 303 | } 304 | 305 | public Builder icon(@DrawableRes int iconRes) { 306 | this.icon = null; 307 | this.iconRes = iconRes; 308 | return this; 309 | } 310 | 311 | public Builder showIcon(boolean showIcon) { 312 | this.showIcon = showIcon; 313 | return this; 314 | } 315 | 316 | public Builder setIconGravity(@IconGravity int iconGravity) { 317 | this.iconGravity = iconGravity; 318 | return this; 319 | } 320 | 321 | public Builder setOnClickListener(MyCustomItem.OnClickListener onClickListener) { 322 | this.onClickListener = onClickListener; 323 | return this; 324 | } 325 | 326 | public MyCustomItem build() { 327 | return new MyCustomItem(this); 328 | } 329 | } 330 | } -------------------------------------------------------------------------------- /app/src/main/java/com/delsart/bookdownload/custom/MyViewTypeManager.java: -------------------------------------------------------------------------------- 1 | package com.delsart.bookdownload.custom; 2 | 3 | import android.content.Context; 4 | import android.view.View; 5 | 6 | import com.danielstone.materialaboutlibrary.holders.MaterialAboutItemViewHolder; 7 | import com.danielstone.materialaboutlibrary.items.MaterialAboutActionItem; 8 | import com.danielstone.materialaboutlibrary.items.MaterialAboutItem; 9 | import com.danielstone.materialaboutlibrary.items.MaterialAboutTitleItem; 10 | import com.danielstone.materialaboutlibrary.util.ViewTypeManager; 11 | import com.delsart.bookdownload.R; 12 | 13 | 14 | /** 15 | * Created by Delsart on 2017/7/24. 16 | */ 17 | public class MyViewTypeManager extends ViewTypeManager { 18 | public static final int ACTION_ITEM = ViewTypeManager.ItemType.ACTION_ITEM; 19 | public static final int TITLE_ITEM = ViewTypeManager.ItemType.TITLE_ITEM; 20 | public static final int CUSTOM_ITEM = 10; 21 | public static final int ACTION_LAYOUT = ViewTypeManager.ItemLayout.ACTION_LAYOUT; 22 | public static final int TITLE_LAYOUT = ViewTypeManager.ItemLayout.TITLE_LAYOUT; 23 | public static final int CUSTOM_LAYOUT = R.layout.item_custom; 24 | 25 | 26 | public int getLayout(int itemType) { 27 | switch (itemType) { 28 | case ACTION_ITEM: 29 | return ACTION_LAYOUT; 30 | case TITLE_ITEM: 31 | return TITLE_LAYOUT; 32 | case CUSTOM_ITEM: 33 | return CUSTOM_LAYOUT; 34 | default: 35 | return -1; 36 | } 37 | } 38 | 39 | public MaterialAboutItemViewHolder getViewHolder(int itemType, View view) { 40 | switch (itemType) { 41 | case ACTION_ITEM: 42 | return MaterialAboutActionItem.getViewHolder(view); 43 | case TITLE_ITEM: 44 | return MaterialAboutTitleItem.getViewHolder(view); 45 | case CUSTOM_ITEM: 46 | return MyCustomItem.getViewHolder(view); 47 | default: 48 | return null; 49 | } 50 | } 51 | 52 | public void setupItem(int itemType, MaterialAboutItemViewHolder holder, MaterialAboutItem item, Context context) { 53 | switch (itemType) { 54 | case ACTION_ITEM: 55 | MaterialAboutActionItem.setupItem((MaterialAboutActionItem.MaterialAboutActionItemViewHolder) holder, (MaterialAboutActionItem) item, context); 56 | break; 57 | case TITLE_ITEM: 58 | MaterialAboutTitleItem.setupItem((MaterialAboutTitleItem.MaterialAboutTitleItemViewHolder) holder, (MaterialAboutTitleItem) item, context); 59 | break; 60 | case CUSTOM_ITEM: 61 | MyCustomItem.setupItem((MyCustomItem.MyCustomItemViewHolder) holder, (MyCustomItem) item, context); 62 | break; 63 | } 64 | } 65 | } -------------------------------------------------------------------------------- /app/src/main/java/com/delsart/bookdownload/custom/ScrollAwareFABBehavior.java: -------------------------------------------------------------------------------- 1 | package com.delsart.bookdownload.custom; 2 | 3 | import android.content.Context; 4 | import android.support.annotation.NonNull; 5 | import android.support.design.widget.CoordinatorLayout; 6 | import android.support.design.widget.FloatingActionButton; 7 | import android.support.v4.view.ViewCompat; 8 | import android.support.v4.view.ViewPropertyAnimatorListener; 9 | import android.support.v4.view.animation.FastOutSlowInInterpolator; 10 | import android.util.AttributeSet; 11 | import android.view.View; 12 | import android.view.ViewGroup; 13 | import android.view.animation.Interpolator; 14 | 15 | public class ScrollAwareFABBehavior extends FloatingActionButton.Behavior { 16 | private static final Interpolator INTERPOLATOR = new FastOutSlowInInterpolator(); 17 | private boolean mIsAnimatingOut = false; 18 | 19 | public ScrollAwareFABBehavior(Context context, AttributeSet attrs) { 20 | super(); 21 | } 22 | 23 | @Override 24 | public boolean onStartNestedScroll(@NonNull final CoordinatorLayout coordinatorLayout, final FloatingActionButton child, 25 | @NonNull final View directTargetChild, @NonNull final View target, final int nestedScrollAxes) { 26 | return nestedScrollAxes == ViewCompat.SCROLL_AXIS_VERTICAL 27 | || super.onStartNestedScroll(coordinatorLayout, child, directTargetChild, target, nestedScrollAxes); 28 | } 29 | 30 | @Override 31 | public void onNestedScroll(@NonNull final CoordinatorLayout coordinatorLayout, final FloatingActionButton child, 32 | @NonNull final View target, final int dxConsumed, final int dyConsumed, 33 | final int dxUnconsumed, final int dyUnconsumed) { 34 | super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed); 35 | if (dyConsumed > 0 && !this.mIsAnimatingOut && child.getVisibility() == View.VISIBLE) { 36 | animateOut(child); 37 | } else if (dyConsumed < 0 && child.getVisibility() != View.VISIBLE) { 38 | animateIn(child); 39 | } 40 | } 41 | 42 | private void animateOut(final FloatingActionButton button) { 43 | ViewCompat.animate(button).translationY(button.getHeight() + getMarginBottom(button)).setInterpolator(INTERPOLATOR).withLayer() 44 | .setListener(new ViewPropertyAnimatorListener() { 45 | public void onAnimationStart(View view) { 46 | ScrollAwareFABBehavior.this.mIsAnimatingOut = true; 47 | } 48 | 49 | public void onAnimationCancel(View view) { 50 | ScrollAwareFABBehavior.this.mIsAnimatingOut = false; 51 | } 52 | 53 | public void onAnimationEnd(View view) { 54 | ScrollAwareFABBehavior.this.mIsAnimatingOut = false; 55 | view.setVisibility(View.INVISIBLE); 56 | } 57 | }).start(); 58 | } 59 | 60 | private void animateIn(FloatingActionButton button) { 61 | button.setVisibility(View.VISIBLE); 62 | ViewCompat.animate(button).translationY(0) 63 | .setInterpolator(INTERPOLATOR).withLayer().setListener(null) 64 | .start(); 65 | } 66 | 67 | private int getMarginBottom(View v) { 68 | int marginBottom = 0; 69 | final ViewGroup.LayoutParams layoutParams = v.getLayoutParams(); 70 | if (layoutParams instanceof ViewGroup.MarginLayoutParams) { 71 | marginBottom = ((ViewGroup.MarginLayoutParams) layoutParams).bottomMargin; 72 | } 73 | return marginBottom; 74 | } 75 | } -------------------------------------------------------------------------------- /app/src/main/java/com/delsart/bookdownload/glide/MyGlideModule.java: -------------------------------------------------------------------------------- 1 | package com.delsart.bookdownload.glide; 2 | 3 | import android.content.Context; 4 | 5 | import com.bumptech.glide.GlideBuilder; 6 | import com.bumptech.glide.annotation.GlideModule; 7 | import com.bumptech.glide.load.engine.cache.ExternalCacheDiskCacheFactory; 8 | import com.bumptech.glide.module.AppGlideModule; 9 | 10 | @GlideModule 11 | public class MyGlideModule extends AppGlideModule { 12 | @Override 13 | public void applyOptions(Context context, GlideBuilder builder) { 14 | int diskCacheSizeBytes = 1024 * 1024 * 16; 15 | builder.setDiskCache(new ExternalCacheDiskCacheFactory(context, diskCacheSizeBytes)); 16 | } 17 | 18 | @Override 19 | public boolean isManifestParsingEnabled() { 20 | return false; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /app/src/main/java/com/delsart/bookdownload/handler/MyCrashHandler.java: -------------------------------------------------------------------------------- 1 | package com.delsart.bookdownload.handler; 2 | 3 | import android.content.ClipboardManager; 4 | import android.content.Context; 5 | import android.os.Looper; 6 | import android.support.v7.app.AlertDialog; 7 | import android.widget.Toast; 8 | 9 | import com.delsart.bookdownload.MyApplication; 10 | import com.delsart.bookdownload.ui.activity.MainActivity; 11 | 12 | /** 13 | * Created by Delsart on 2017/8/7. 14 | */ 15 | 16 | public class MyCrashHandler implements Thread.UncaughtExceptionHandler { 17 | 18 | private static MyCrashHandler instance; 19 | Thread.UncaughtExceptionHandler mDefaultHandler; 20 | public static MyCrashHandler getInstance() { 21 | if (instance == null) { 22 | instance = new MyCrashHandler(); 23 | } 24 | return instance; 25 | } 26 | 27 | public void init(Context ctx) { 28 | mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler(); 29 | Thread.setDefaultUncaughtExceptionHandler(this); 30 | } 31 | 32 | @Override 33 | public void uncaughtException(Thread t, Throwable e) { 34 | Looper.prepare(); 35 | StringBuffer sb=new StringBuffer(); 36 | StackTraceElement[] stackTrace = e.getStackTrace(); 37 | for (StackTraceElement stackTraceElement : stackTrace) { 38 | sb.append(stackTraceElement.toString()); 39 | sb.append("\nfile: "); 40 | sb.append(stackTraceElement.getFileName()); 41 | sb.append("\nclass: "); 42 | sb.append(stackTraceElement.getClassName()); 43 | sb.append("\nmethod: "); 44 | sb.append(stackTraceElement.getMethodName()); 45 | sb.append("\nline: "); 46 | sb.append(stackTraceElement.getLineNumber()); 47 | sb.append("\n—————————————————\n"); 48 | } 49 | Toast.makeText(MyApplication.getContext(),"Oops!出现错误!\n已将错误日志复制到粘贴板,请向作者反馈\n\n"+sb,Toast.LENGTH_LONG).show(); 50 | Toast.makeText(MyApplication.getContext(),"Oops!出现错误!\n已将错误日志复制到粘贴板,请向作者反馈\n\n"+sb,Toast.LENGTH_LONG).show(); 51 | ClipboardManager cmb = (ClipboardManager)MyApplication.getContext().getSystemService(Context.CLIPBOARD_SERVICE); 52 | cmb.setText(sb); 53 | 54 | //android.os.Process.killProcess(android.os.Process.myPid()); 55 | //System.exit(0); 56 | Looper.loop(); 57 | 58 | 59 | 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /app/src/main/java/com/delsart/bookdownload/handler/MyHandler.java: -------------------------------------------------------------------------------- 1 | package com.delsart.bookdownload.handler; 2 | 3 | import android.os.Handler; 4 | import android.os.Message; 5 | 6 | import java.lang.ref.WeakReference; 7 | 8 | 9 | public class MyHandler extends Handler { 10 | 11 | private final WeakReference mReference; 12 | private OnHandleMessageCallback onHandleMessageCallback; 13 | 14 | public MyHandler(T t) { 15 | mReference = new WeakReference<>(t); 16 | } 17 | 18 | public void setOnHandleMessageCallback(OnHandleMessageCallback onHandleMessageCallback) { 19 | this.onHandleMessageCallback = onHandleMessageCallback; 20 | } 21 | 22 | @Override 23 | public void handleMessage(Message msg) { 24 | T t = mReference.get(); 25 | if (t != null && onHandleMessageCallback != null) { 26 | onHandleMessageCallback.handleMessage(t, msg); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /app/src/main/java/com/delsart/bookdownload/handler/OnHandleMessageCallback.java: -------------------------------------------------------------------------------- 1 | package com.delsart.bookdownload.handler; 2 | 3 | 4 | import android.os.Message; 5 | 6 | public interface OnHandleMessageCallback { 7 | void handleMessage(T t, Message msg); 8 | } 9 | -------------------------------------------------------------------------------- /app/src/main/java/com/delsart/bookdownload/service/AiXiaService.java: -------------------------------------------------------------------------------- 1 | package com.delsart.bookdownload.service; 2 | 3 | import android.os.Handler; 4 | import android.os.Message; 5 | 6 | import com.delsart.bookdownload.MsgType; 7 | import com.delsart.bookdownload.Url; 8 | import com.delsart.bookdownload.bean.DownloadBean; 9 | import com.delsart.bookdownload.bean.NovelBean; 10 | 11 | import org.jsoup.Jsoup; 12 | import org.jsoup.nodes.Document; 13 | import org.jsoup.nodes.Element; 14 | import org.jsoup.select.Elements; 15 | 16 | import java.io.IOException; 17 | import java.util.ArrayList; 18 | import java.util.concurrent.CountDownLatch; 19 | 20 | public class AiXiaService extends BaseService { 21 | private final Handler mHandler; 22 | private int mPage; 23 | private String mBaseUrl; 24 | private CountDownLatch latch; 25 | private ArrayList list = new ArrayList<>(); 26 | 27 | public AiXiaService(Handler handler, String keywords) { 28 | super(handler, keywords); 29 | this.mHandler = handler; 30 | mPage = 1; 31 | mBaseUrl = Url.AIXIA + keywords + "&page="; 32 | } 33 | 34 | @Override 35 | public void get() { 36 | new Thread(new Runnable() { 37 | @Override 38 | public void run() { 39 | try { 40 | list.clear(); 41 | Elements select = Jsoup.connect(mBaseUrl + mPage) 42 | .timeout(10000) 43 | .ignoreContentType(true) 44 | .ignoreHttpErrors(true) 45 | .userAgent(Url.MOBBILE_AGENT) 46 | .get() 47 | .select("body > div.list > li > a"); 48 | latch = new CountDownLatch(select.size()); 49 | for (Element element : select) { 50 | runInSameTime(element); 51 | } 52 | latch.await(); 53 | mPage++; 54 | Message msg = mHandler.obtainMessage(); 55 | msg.what = MsgType.SUCCESS; 56 | msg.obj = list; 57 | mHandler.sendMessage(msg); 58 | } catch (IOException e) { 59 | e.printStackTrace(); 60 | Message msg = mHandler.obtainMessage(); 61 | msg.what = MsgType.ERROR; 62 | mHandler.sendMessage(msg); 63 | } catch (InterruptedException e) { 64 | e.printStackTrace(); 65 | } 66 | } 67 | }).start(); 68 | } 69 | 70 | private void runInSameTime(final Element element) throws IOException { 71 | mExecutorService.submit(new Runnable() { 72 | @Override 73 | public void run() { 74 | String url = element.attr("abs:href"); 75 | try { 76 | Document document = Jsoup.connect(url) 77 | .ignoreContentType(true) 78 | .ignoreHttpErrors(true) 79 | .userAgent(Url.MOBBILE_AGENT) 80 | .get(); 81 | String name = document.select("body > div:nth-child(2) > h1").text(); 82 | String time = document.select("body > div:nth-child(3) > li:nth-child(6)").text(); 83 | String info = document.select("body > div.intro > li").text(); 84 | String category = document.select("body > div:nth-child(3) > li:nth-child(2)").text(); 85 | String status = document.select("body > div:nth-child(3) > li:nth-child(5)").text(); 86 | String author = document.select("body > div:nth-child(3) > li:nth-child(1)").text(); 87 | String words = document.select("body > div:nth-child(3) > li:nth-child(3)").text(); 88 | String pic = ""; 89 | NovelBean no = new NovelBean(name, time, info, category, status, author, words, pic, url); 90 | list.add(no); 91 | } catch (IOException e) { 92 | e.printStackTrace(); 93 | } 94 | latch.countDown(); 95 | } 96 | }); 97 | } 98 | 99 | 100 | @Override 101 | public ArrayList getDownloadurls(final String url) throws InterruptedException { 102 | latch = new CountDownLatch(1); 103 | final ArrayList urls = new ArrayList<>(); 104 | mExecutorService.submit(new Runnable() { 105 | @Override 106 | public void run() { 107 | try { 108 | Elements elements = Jsoup.connect(url) 109 | .timeout(10000) 110 | .ignoreContentType(true) 111 | .ignoreHttpErrors(true) 112 | .userAgent(Url.MOBBILE_AGENT) 113 | .get() 114 | .select("body > div:nth-child(5)"); 115 | String u1 = elements.select("li:nth-child(2) > a").attr("abs:href"); 116 | String u1n = elements.select("li:nth-child(2) > a").text(); 117 | String u2 = elements.select("li:nth-child(3) > a").attr("abs:href"); 118 | String u2n = elements.select("li:nth-child(3) > a").text(); 119 | urls.add(new DownloadBean(u1n, u1)); 120 | urls.add(new DownloadBean(u2n, u2)); 121 | } catch (IOException e) { 122 | e.printStackTrace(); 123 | } 124 | latch.countDown(); 125 | } 126 | }); 127 | latch.await(); 128 | return urls; 129 | } 130 | 131 | } 132 | -------------------------------------------------------------------------------- /app/src/main/java/com/delsart/bookdownload/service/BaseService.java: -------------------------------------------------------------------------------- 1 | package com.delsart.bookdownload.service; 2 | 3 | 4 | import android.os.Handler; 5 | 6 | import com.delsart.bookdownload.bean.DownloadBean; 7 | 8 | import java.io.UnsupportedEncodingException; 9 | import java.util.ArrayList; 10 | import java.util.concurrent.ExecutorService; 11 | import java.util.concurrent.Executors; 12 | 13 | public abstract class BaseService { 14 | public ExecutorService mExecutorService= Executors.newFixedThreadPool(4); 15 | public BaseService(Handler handler, String keywords) { 16 | } 17 | 18 | public static String toUtf8(String str) { 19 | String result = null; 20 | try { 21 | result = new String(str.getBytes("UTF-8"), "UTF-8"); 22 | } catch (UnsupportedEncodingException e) { 23 | // TODO Auto-generated catch block 24 | e.printStackTrace(); 25 | } 26 | return result; 27 | } 28 | 29 | public void reLoad(){ 30 | get(); 31 | } 32 | public abstract void get(); 33 | 34 | public abstract ArrayList getDownloadurls(String url) throws InterruptedException; 35 | } 36 | -------------------------------------------------------------------------------- /app/src/main/java/com/delsart/bookdownload/service/BlahService.java: -------------------------------------------------------------------------------- 1 | package com.delsart.bookdownload.service; 2 | 3 | import android.os.Handler; 4 | import android.os.Message; 5 | 6 | import com.delsart.bookdownload.MsgType; 7 | import com.delsart.bookdownload.Url; 8 | import com.delsart.bookdownload.bean.DownloadBean; 9 | import com.delsart.bookdownload.bean.NovelBean; 10 | 11 | import org.jsoup.Jsoup; 12 | import org.jsoup.nodes.Document; 13 | import org.jsoup.nodes.Element; 14 | import org.jsoup.select.Elements; 15 | 16 | import java.io.IOException; 17 | import java.util.ArrayList; 18 | import java.util.List; 19 | import java.util.concurrent.CountDownLatch; 20 | 21 | public class BlahService extends BaseService { 22 | private static String TAG = "test"; 23 | private final Handler mHandler; 24 | private int mPage; 25 | private String mBaseUrl; 26 | private CountDownLatch latch; 27 | private ArrayList list = new ArrayList<>(); 28 | 29 | public BlahService(Handler handler, String keywords) { 30 | super(handler, keywords); 31 | this.mHandler = handler; 32 | mPage = 1; 33 | mBaseUrl = Url.BLAH + keywords + "&page="; 34 | } 35 | String lasts=""; 36 | @Override 37 | public void get() { 38 | new Thread(new Runnable() { 39 | @Override 40 | public void run() { 41 | try { 42 | list.clear(); 43 | Elements select = Jsoup.connect(mBaseUrl + mPage) 44 | .timeout(10000) 45 | .ignoreContentType(true) 46 | .ignoreHttpErrors(true) 47 | .userAgent(Url.MOBBILE_AGENT) 48 | .get() 49 | .select("div.ok-book-item").select("a.okShowInfoModal"); 50 | latch = new CountDownLatch(select.size()); 51 | for (int i = 0; i < select.size(); i++) { 52 | runInSameTime(select.get(i)); 53 | } 54 | latch.await(); 55 | if (select.toString().equals(lasts)) 56 | list.clear(); 57 | lasts=select.toString(); 58 | 59 | mPage++; 60 | Message msg = mHandler.obtainMessage(); 61 | msg.what = MsgType.SUCCESS; 62 | msg.obj = list; 63 | mHandler.sendMessage(msg); 64 | } catch (IOException e) { 65 | e.printStackTrace(); 66 | Message msg = mHandler.obtainMessage(); 67 | msg.what = MsgType.ERROR; 68 | mHandler.sendMessage(msg); 69 | } catch (InterruptedException e) { 70 | e.printStackTrace(); 71 | } 72 | } 73 | }).start(); 74 | } 75 | 76 | private void runInSameTime(final Element element) throws IOException { 77 | mExecutorService.submit(new Runnable() { 78 | @Override 79 | public void run() { 80 | String url = element.attr("abs:href"); 81 | try { 82 | Document document = Jsoup.connect(url) 83 | .ignoreContentType(true) 84 | .ignoreHttpErrors(true) 85 | .userAgent(Url.MOBBILE_AGENT) 86 | .get(); 87 | 88 | String name = document.select("#okBookShow > div.ok-book-base-info > div.row > div.col-sm-8.ok-book-info > div.ok-book-meta > h1").text(); 89 | String time = ""; 90 | String info = ""; 91 | Elements elements = document.select("#okBookShow > div.ok-book-base-info > div.row > div.col-sm-8.ok-book-info > div.ok-book-meta > div.ok-book-desc > div.ok-book-meta-content").select("p"); 92 | for (int i = 0; i < elements.size(); i++) { 93 | 94 | 95 | if (!elements.get(i).text().equals("")) 96 | info = info + elements.get(i).text() + "\n\n"; 97 | 98 | 99 | } 100 | String category = document.select("#okBookShow > div.ok-book-base-info > div.row > div.col-sm-8.ok-book-info > div.ok-book-meta > div.ok-book-subjects").text(); 101 | String status = ""; 102 | String author = document.select("#okBookShow > div.ok-book-base-info > div.row > div.col-sm-8.ok-book-info > div.ok-book-meta > div.row > div > div").text(); 103 | String words = ""; 104 | String pic = document.select("#okBookShow > div.ok-book-base-info > div.row > div.col-sm-4 > div > img").attr("abs:src"); 105 | NovelBean no = new NovelBean(name, time, info, category, status, author, words, pic, url); 106 | list.add(no); 107 | } catch (IOException e) { 108 | e.printStackTrace(); 109 | } 110 | 111 | latch.countDown(); 112 | } 113 | }); 114 | } 115 | 116 | 117 | @Override 118 | public ArrayList getDownloadurls(final String url) throws InterruptedException { 119 | latch = new CountDownLatch(1); 120 | final ArrayList urls = new ArrayList<>(); 121 | mExecutorService.submit(new Runnable() { 122 | @Override 123 | public void run() { 124 | try { 125 | Document document = Jsoup.connect(url) 126 | .timeout(10000) 127 | .ignoreContentType(true) 128 | .ignoreHttpErrors(true) 129 | .userAgent(Url.MOBBILE_AGENT) 130 | .get(); 131 | 132 | Elements elements = document.select("#okBookShow > div.ok-book-base-info > div.row > div.col-sm-8.ok-book-info > div.ok-book-opt > div > div.col-md-5.ok-book-download > div a"); 133 | if (elements != null) { 134 | for (Element element : elements) { 135 | urls.add(new DownloadBean(element.text(), element.attr("abs:href"))); 136 | } 137 | } 138 | 139 | } catch (IOException e) { 140 | e.printStackTrace(); 141 | } 142 | 143 | latch.countDown(); 144 | } 145 | }); 146 | latch.await(); 147 | return urls; 148 | } 149 | 150 | } 151 | -------------------------------------------------------------------------------- /app/src/main/java/com/delsart/bookdownload/service/DongManZhiJiaService.java: -------------------------------------------------------------------------------- 1 | package com.delsart.bookdownload.service; 2 | 3 | import android.os.Handler; 4 | import android.os.Message; 5 | import android.util.Log; 6 | 7 | import com.delsart.bookdownload.MsgType; 8 | import com.delsart.bookdownload.Url; 9 | import com.delsart.bookdownload.bean.DownloadBean; 10 | import com.delsart.bookdownload.bean.NovelBean; 11 | 12 | import org.json.JSONArray; 13 | import org.json.JSONException; 14 | import org.json.JSONObject; 15 | import org.jsoup.Jsoup; 16 | import org.jsoup.select.Elements; 17 | 18 | import java.io.IOException; 19 | import java.util.ArrayList; 20 | import java.util.concurrent.CountDownLatch; 21 | import java.util.regex.Matcher; 22 | import java.util.regex.Pattern; 23 | 24 | public class DongManZhiJiaService extends BaseService { 25 | private final Handler mHandler; 26 | private int mPage; 27 | private String mBaseUrl; 28 | private CountDownLatch latch; 29 | private ArrayList list = new ArrayList<>(); 30 | final String MAINURL = "http://q.dmzj.com"; 31 | 32 | public DongManZhiJiaService(Handler handler, String keywords) { 33 | super(handler, keywords); 34 | this.mHandler = handler; 35 | mPage = 1; 36 | mBaseUrl = Url.DONGMANZHIJIA + keywords; 37 | } 38 | 39 | @Override 40 | public void get() { 41 | new Thread(new Runnable() { 42 | @Override 43 | public void run() { 44 | try { 45 | list.clear(); 46 | String select = Jsoup.connect(mBaseUrl) 47 | .timeout(10000) 48 | .ignoreContentType(true) 49 | .ignoreHttpErrors(true) 50 | .userAgent(Url.MOBBILE_AGENT) 51 | .get().toString(); 52 | if (select.contains("[")) { 53 | select = select.substring(select.indexOf("["), select.length()); 54 | JSONArray jsonArray = new JSONArray(select); 55 | latch = new CountDownLatch(jsonArray.length()); 56 | for (int i = 0; i < jsonArray.length(); i++) { 57 | runInSameTime(jsonArray.getJSONObject(i)); 58 | } 59 | latch.await(); 60 | Message msg = mHandler.obtainMessage(); 61 | msg.what = MsgType.SUCCESS; 62 | msg.obj = list; 63 | mHandler.sendMessage(msg); 64 | } 65 | else 66 | { 67 | Message msg = mHandler.obtainMessage(); 68 | msg.what = MsgType.ERROR; 69 | mHandler.sendMessage(msg); 70 | } 71 | } catch (IOException e) { 72 | e.printStackTrace(); 73 | Message msg = mHandler.obtainMessage(); 74 | msg.what = MsgType.ERROR; 75 | mHandler.sendMessage(msg); 76 | } catch (JSONException e) { 77 | e.printStackTrace(); 78 | } catch (InterruptedException e) { 79 | e.printStackTrace(); 80 | } 81 | } 82 | }).start(); 83 | } 84 | 85 | private void runInSameTime(final JSONObject jsonObject) throws IOException { 86 | mExecutorService.submit(new Runnable() { 87 | @Override 88 | public void run() { 89 | try { 90 | String name = jsonObject.getString("full_name"); 91 | String time = ""; 92 | String info = jsonObject.getString("description"); 93 | String category = "类型:" + jsonObject.getString("types"); 94 | String status = "状态:" + jsonObject.getString("status"); 95 | String author = "作者:" + jsonObject.getString("author"); 96 | String words = "最新章节:" + jsonObject.getString("last_chapter_name"); 97 | String pic = jsonObject.getString("image_url"); 98 | String url = MAINURL + jsonObject.getString("lnovel_url").replace("..", ""); 99 | NovelBean no = new NovelBean(name, time, info, category, status, author, words, pic, url); 100 | list.add(no); 101 | } catch (JSONException e) { 102 | e.printStackTrace(); 103 | } 104 | latch.countDown(); 105 | } 106 | }); 107 | } 108 | 109 | 110 | @Override 111 | public ArrayList getDownloadurls(final String url) throws InterruptedException { 112 | latch = new CountDownLatch(1); 113 | final ArrayList urls = new ArrayList<>(); 114 | mExecutorService.submit(new Runnable() { 115 | @Override 116 | public void run() { 117 | try { 118 | Elements elements = Jsoup.connect(url) 119 | .timeout(10000) 120 | .ignoreContentType(true) 121 | .ignoreHttpErrors(true) 122 | .userAgent(Url.MOBBILE_AGENT) 123 | .get() 124 | .getElementsByTag("script"); 125 | Matcher m = Pattern.compile("
[^a-z]+
.+[^a-z]+").matcher(elements.toString()); 126 | while (m.find()) { 127 | String name=""; 128 | String path=""; 129 | Matcher matcher = Pattern.compile("
([^a-z]+)
").matcher(m.group()); 130 | if (matcher.find()) { 131 | name = matcher.group(1); 132 | } 133 | matcher = Pattern.compile("[^a-z]+").matcher(m.group()); 134 | if (matcher.find()) { 135 | path = matcher.group(1); 136 | 137 | } 138 | urls.add(new DownloadBean(name, path)); 139 | } 140 | 141 | } catch (IOException e) { 142 | e.printStackTrace(); 143 | } 144 | latch.countDown(); 145 | } 146 | }); 147 | latch.await(); 148 | return urls; 149 | } 150 | 151 | } 152 | -------------------------------------------------------------------------------- /app/src/main/java/com/delsart/bookdownload/service/EpubeeService.java: -------------------------------------------------------------------------------- 1 | package com.delsart.bookdownload.service; 2 | 3 | import android.os.Handler; 4 | import android.os.Message; 5 | 6 | import com.delsart.bookdownload.MsgType; 7 | import com.delsart.bookdownload.Url; 8 | import com.delsart.bookdownload.bean.DownloadBean; 9 | import com.delsart.bookdownload.bean.NovelBean; 10 | 11 | import org.jsoup.Jsoup; 12 | import org.jsoup.nodes.Document; 13 | import org.jsoup.nodes.Element; 14 | import org.jsoup.select.Elements; 15 | 16 | import java.io.IOException; 17 | import java.util.ArrayList; 18 | import java.util.concurrent.CountDownLatch; 19 | 20 | public class EpubeeService extends BaseService { 21 | private final Handler mHandler; 22 | private int mPage; 23 | private String mBaseUrl; 24 | private CountDownLatch latch; 25 | private ArrayList list = new ArrayList<>(); 26 | 27 | public EpubeeService(Handler handler, String keywords) { 28 | super(handler, keywords); 29 | this.mHandler = handler; 30 | mPage = 1; 31 | mBaseUrl = Url.AIXIA + keywords + "&page="; 32 | } 33 | 34 | @Override 35 | public void get() { 36 | new Thread(new Runnable() { 37 | @Override 38 | public void run() { 39 | try { 40 | list.clear(); 41 | Elements select = Jsoup.connect(mBaseUrl + mPage) 42 | .timeout(10000) 43 | .ignoreContentType(true) 44 | .ignoreHttpErrors(true) 45 | .userAgent(Url.MOBBILE_AGENT) 46 | .get() 47 | .select("body > div.list > li > a"); 48 | latch = new CountDownLatch(select.size()); 49 | for (Element element : select) { 50 | runInSameTime(element); 51 | } 52 | latch.await(); 53 | mPage++; 54 | Message msg = mHandler.obtainMessage(); 55 | msg.what = MsgType.SUCCESS; 56 | msg.obj = list; 57 | mHandler.sendMessage(msg); 58 | } catch (IOException e) { 59 | e.printStackTrace(); 60 | Message msg = mHandler.obtainMessage(); 61 | msg.what = MsgType.ERROR; 62 | mHandler.sendMessage(msg); 63 | } catch (InterruptedException e) { 64 | e.printStackTrace(); 65 | } 66 | } 67 | }).start(); 68 | } 69 | 70 | private void runInSameTime(final Element element) throws IOException { 71 | mExecutorService.submit(new Runnable() { 72 | @Override 73 | public void run() { 74 | String url = element.attr("abs:href"); 75 | try { 76 | Document document = Jsoup.connect(url) 77 | .ignoreContentType(true) 78 | .ignoreHttpErrors(true) 79 | .userAgent(Url.MOBBILE_AGENT) 80 | .get(); 81 | String name = document.select("body > div:nth-child(2) > h1").text(); 82 | String time = document.select("body > div:nth-child(3) > li:nth-child(6)").text(); 83 | String info = document.select("body > div.intro > li").text(); 84 | String category = document.select("body > div:nth-child(3) > li:nth-child(2)").text(); 85 | String status = document.select("body > div:nth-child(3) > li:nth-child(5)").text(); 86 | String author = document.select("body > div:nth-child(3) > li:nth-child(1)").text(); 87 | String words = document.select("body > div:nth-child(3) > li:nth-child(3)").text(); 88 | String pic = ""; 89 | NovelBean no = new NovelBean(name, time, info, category, status, author, words, pic, url); 90 | list.add(no); 91 | } catch (IOException e) { 92 | e.printStackTrace(); 93 | } 94 | latch.countDown(); 95 | } 96 | }); 97 | } 98 | 99 | 100 | @Override 101 | public ArrayList getDownloadurls(final String url) throws InterruptedException { 102 | latch = new CountDownLatch(1); 103 | final ArrayList urls = new ArrayList<>(); 104 | mExecutorService.submit(new Runnable() { 105 | @Override 106 | public void run() { 107 | try { 108 | Elements elements = Jsoup.connect(url) 109 | .timeout(10000) 110 | .ignoreContentType(true) 111 | .ignoreHttpErrors(true) 112 | .userAgent(Url.MOBBILE_AGENT) 113 | .get() 114 | .select("body > div:nth-child(5)"); 115 | String u1 = elements.select("li:nth-child(2) > a").attr("abs:href"); 116 | String u1n = elements.select("li:nth-child(2) > a").text(); 117 | String u2 = elements.select("li:nth-child(3) > a").attr("abs:href"); 118 | String u2n = elements.select("li:nth-child(3) > a").text(); 119 | urls.add(new DownloadBean(u1n, u1)); 120 | urls.add(new DownloadBean(u2n, u2)); 121 | } catch (IOException e) { 122 | e.printStackTrace(); 123 | } 124 | latch.countDown(); 125 | } 126 | }); 127 | latch.await(); 128 | return urls; 129 | } 130 | 131 | } 132 | -------------------------------------------------------------------------------- /app/src/main/java/com/delsart/bookdownload/service/M360DService.java: -------------------------------------------------------------------------------- 1 | package com.delsart.bookdownload.service; 2 | 3 | import android.os.Handler; 4 | import android.os.Message; 5 | 6 | import com.delsart.bookdownload.MsgType; 7 | import com.delsart.bookdownload.Url; 8 | import com.delsart.bookdownload.bean.DownloadBean; 9 | import com.delsart.bookdownload.bean.NovelBean; 10 | 11 | import org.jsoup.Jsoup; 12 | import org.jsoup.nodes.Document; 13 | import org.jsoup.nodes.Element; 14 | import org.jsoup.select.Elements; 15 | 16 | import java.io.IOException; 17 | import java.util.ArrayList; 18 | import java.util.concurrent.CountDownLatch; 19 | 20 | public class M360DService extends BaseService { 21 | private static String TAG = "test"; 22 | private final Handler mHandler; 23 | private int mPage; 24 | private String mBaseUrl; 25 | private CountDownLatch latch; 26 | private ArrayList urls = new ArrayList<>(); 27 | private ArrayList list = new ArrayList<>(); 28 | 29 | public M360DService(Handler handler, String keywords) { 30 | super(handler, keywords); 31 | this.mHandler = handler; 32 | mPage = 1; 33 | mBaseUrl = Url.M360D + keywords + "&page="; 34 | } 35 | 36 | @Override 37 | public void get() { 38 | new Thread(new Runnable() { 39 | @Override 40 | public void run() { 41 | try { 42 | list.clear(); 43 | Elements select = Jsoup.connect(mBaseUrl + mPage) 44 | .timeout(10000) 45 | .ignoreContentType(true) 46 | .ignoreHttpErrors(true) 47 | .userAgent(Url.MOBBILE_AGENT) 48 | .get() 49 | .select("div[itemtype=http://schema.org/Novel].am-thumbnail"); 50 | latch = new CountDownLatch(select.size()); 51 | for (int i = 0; i < select.size(); i++) { 52 | runInSameTime(select.get(i)); 53 | } 54 | latch.await(); 55 | mPage++; 56 | Message msg = mHandler.obtainMessage(); 57 | msg.what = MsgType.SUCCESS; 58 | msg.obj = list; 59 | mHandler.sendMessage(msg); 60 | } catch (IOException e) { 61 | e.printStackTrace(); 62 | Message msg = mHandler.obtainMessage(); 63 | msg.what = MsgType.ERROR; 64 | mHandler.sendMessage(msg); 65 | } catch (InterruptedException e) { 66 | e.printStackTrace(); 67 | } 68 | } 69 | }).start(); 70 | } 71 | 72 | private void runInSameTime(final Element element) throws IOException { 73 | mExecutorService.submit(new Runnable() { 74 | @Override 75 | public void run() { 76 | String name = element.select("a[itemprop=name]").text(); 77 | String durl = element.select("a[itemprop=name]").attr("abs:href"); 78 | String time = "最后更新:" + element.select("span[itemprop=dateModified]").text(); 79 | String info = element.select("div[itemprop=description]").text(); 80 | String category = "分类:" + element.select("a[itemprop=genre]").text(); 81 | String status = "状态:" + element.select("span[itemprop=updataStatus]").text(); 82 | String author = "作者:" + element.select("a[itemprop=author]").text(); 83 | String words = ""; 84 | String pic = "http://www.360dxs.com/static/books/logo/" + durl.substring(durl.indexOf("_") + 1, durl.indexOf(".html")) + "s.jpg"; 85 | NovelBean no = new NovelBean(name, time, info, category, status, author, words, pic, durl); 86 | list.add(no); 87 | latch.countDown(); 88 | } 89 | }); 90 | 91 | } 92 | 93 | @Override 94 | public ArrayList getDownloadurls(final String url) throws InterruptedException { 95 | latch = new CountDownLatch(1); 96 | final ArrayList urls = new ArrayList<>(); 97 | mExecutorService.submit(new Runnable() { 98 | @Override 99 | public void run() { 100 | try { 101 | Document document = Jsoup.connect(url) 102 | .timeout(10000) 103 | .ignoreContentType(true) 104 | .ignoreHttpErrors(true) 105 | .userAgent(Url.MOBBILE_AGENT) 106 | .get(); 107 | Document document2 = Jsoup.connect(document.select("a:contains(全文下载)").attr("abs:href")).get(); 108 | Elements elements = document2.select("div.am-u-sm-12").get(1).select("a"); 109 | for (Element element : elements) { 110 | urls.add(new DownloadBean("全文下载: " + element.text(), element.attr("abs:href"))); 111 | } 112 | document = Jsoup.connect(document.select("a:contains(分卷下载)").attr("abs:href")).get(); 113 | Elements elements1 = document.select("div.am-u-sm-12").get(1).select("h3.am-text-center"); 114 | Elements elements2 = document.select("div.am-u-sm-12").get(1).select("ul"); 115 | for (int i = 0; i < elements2.size(); i++) { 116 | Elements elements3 = elements2.get(i).select("a"); 117 | for (Element element : elements3) { 118 | urls.add(new DownloadBean(elements1.get(i).text() + ":" + element.text(), element.attr("abs:href"))); 119 | } 120 | } 121 | } catch (IOException e) { 122 | e.printStackTrace(); 123 | } 124 | latch.countDown(); 125 | } 126 | }); 127 | latch.await(); 128 | return urls; 129 | } 130 | 131 | } 132 | -------------------------------------------------------------------------------- /app/src/main/java/com/delsart/bookdownload/service/QiShuService.java: -------------------------------------------------------------------------------- 1 | package com.delsart.bookdownload.service; 2 | 3 | import android.os.Handler; 4 | import android.os.Message; 5 | import android.util.Log; 6 | 7 | import com.delsart.bookdownload.MsgType; 8 | import com.delsart.bookdownload.Url; 9 | import com.delsart.bookdownload.bean.DownloadBean; 10 | import com.delsart.bookdownload.bean.NovelBean; 11 | 12 | import org.jsoup.Jsoup; 13 | import org.jsoup.nodes.Document; 14 | import org.jsoup.nodes.Element; 15 | import org.jsoup.select.Elements; 16 | 17 | import java.io.IOException; 18 | import java.util.ArrayList; 19 | import java.util.concurrent.CountDownLatch; 20 | 21 | public class QiShuService extends BaseService { 22 | private static String TAG = "test"; 23 | private final Handler mHandler; 24 | private int mPage; 25 | private String mBaseUrl; 26 | private CountDownLatch latch; 27 | private ArrayList list = new ArrayList<>(); 28 | 29 | public QiShuService(Handler handler, String keywords) { 30 | super(handler, keywords); 31 | this.mHandler = handler; 32 | mPage = 0; 33 | mBaseUrl = Url.QISHU + toUtf8(keywords) + "&p="; 34 | } 35 | String lasts=""; 36 | @Override 37 | public void get() { 38 | new Thread(new Runnable() { 39 | @Override 40 | public void run() { 41 | try { 42 | list.clear(); 43 | Elements select = Jsoup.connect(mBaseUrl + mPage) 44 | .timeout(10000) 45 | //.ignoreContentType(true) 46 | .ignoreHttpErrors(true) 47 | .userAgent(Url.PC_AGENT) 48 | .get() 49 | .select("div#results").select("h3.c-title").select("a"); 50 | latch = new CountDownLatch(select.size()); 51 | for (int i = 0; i < select.size(); i++) { 52 | runInSameTime(select.get(i)); 53 | } 54 | latch.await(); 55 | if (select.toString().equals(lasts)) 56 | list.clear(); 57 | lasts=select.toString(); 58 | mPage++; 59 | Message msg = mHandler.obtainMessage(); 60 | msg.what = MsgType.SUCCESS; 61 | msg.obj = list; 62 | mHandler.sendMessage(msg); 63 | } catch (Exception e) { 64 | e.printStackTrace(); 65 | Message msg = mHandler.obtainMessage(); 66 | msg.what = MsgType.ERROR; 67 | mHandler.sendMessage(msg); 68 | } 69 | } 70 | }).start(); 71 | } 72 | 73 | private void runInSameTime(final Element element) throws IOException { 74 | mExecutorService.submit(new Runnable() { 75 | @Override 76 | public void run() { 77 | String url = element.attr("abs:href"); 78 | if (!url.contains(".html")) { 79 | latch.countDown(); 80 | return; 81 | } try { 82 | Document document = Jsoup.connect(url) 83 | .ignoreContentType(true) 84 | .ignoreHttpErrors(true) 85 | .get(); 86 | Elements a = document.select("div.detail"); 87 | if (a.select("li").size() < 7) { 88 | Log.d(TAG, "run:qishu错误 " + url); 89 | latch.countDown(); 90 | return; 91 | } 92 | String name = a.select("h1").text(); 93 | String time = a.select("li.small").get(4).text(); 94 | String info = document.select("body > div:nth-child(4) > div.show > div:nth-child(2) > div.showInfo").text(); 95 | String category = a.select("li.small").get(3).text(); 96 | String status = a.select("li.small").get(5).text(); 97 | String author = a.select("li.small").get(6).text(); 98 | String words = a.select("li.small").get(2).text(); 99 | String pic = a.select("img").attr("abs:src"); 100 | NovelBean no = new NovelBean(name, time, info, category, status, author, words, pic, url); 101 | list.add(no); 102 | } catch (IOException e) { 103 | e.printStackTrace(); 104 | } 105 | latch.countDown(); 106 | } 107 | }); 108 | } 109 | 110 | 111 | @Override 112 | public ArrayList getDownloadurls(final String url) throws InterruptedException { 113 | latch = new CountDownLatch(1); 114 | final ArrayList urls = new ArrayList<>(); 115 | mExecutorService.submit(new Runnable() { 116 | @Override 117 | public void run() { 118 | try { 119 | Document document = Jsoup.connect(url) 120 | .timeout(10000) 121 | .ignoreContentType(true) 122 | .ignoreHttpErrors(true) 123 | .userAgent(Url.MOBBILE_AGENT) 124 | .get(); 125 | 126 | String u1 = document.select("body > div:nth-child(4) > div.show > div:nth-child(4) > div.showDown > ul > li:nth-child(1) > a").attr("abs:href"); 127 | String u1n = document.select("body > div:nth-child(4) > div.show > div:nth-child(4) > div.showDown > ul > li:nth-child(1) > a").text(); 128 | String u2 = document.select("body > div:nth-child(4) > div.show > div:nth-child(4) > div.showDown > ul > li:nth-child(2) > a").attr("abs:href"); 129 | String u2n = document.select("body > div:nth-child(4) > div.show > div:nth-child(4) > div.showDown > ul > li:nth-child(2) > a").text(); 130 | String u3 = document.select("body > div:nth-child(4) > div.show > div:nth-child(4) > div.showDown > ul > li:nth-child(3) > a").attr("abs:href"); 131 | String u3n = document.select("body > div:nth-child(4) > div.show > div:nth-child(4) > div.showDown > ul > li:nth-child(3) > a").text(); 132 | urls.add(new DownloadBean(u1n, u1)); 133 | urls.add(new DownloadBean(u2n, u2)); 134 | urls.add(new DownloadBean(u3n, u3)); 135 | } catch (IOException e) { 136 | e.printStackTrace(); 137 | } 138 | latch.countDown(); 139 | } 140 | }); 141 | latch.await(); 142 | return urls; 143 | } 144 | 145 | } 146 | -------------------------------------------------------------------------------- /app/src/main/java/com/delsart/bookdownload/service/ShuYuZheService.java: -------------------------------------------------------------------------------- 1 | package com.delsart.bookdownload.service; 2 | 3 | import android.icu.text.LocaleDisplayNames; 4 | import android.os.Handler; 5 | import android.os.Message; 6 | import android.util.Log; 7 | 8 | import com.delsart.bookdownload.MsgType; 9 | import com.delsart.bookdownload.Url; 10 | import com.delsart.bookdownload.bean.DownloadBean; 11 | import com.delsart.bookdownload.bean.NovelBean; 12 | 13 | import org.jsoup.Jsoup; 14 | import org.jsoup.nodes.Document; 15 | import org.jsoup.nodes.Element; 16 | import org.jsoup.select.Elements; 17 | 18 | import java.io.IOException; 19 | import java.util.ArrayList; 20 | import java.util.concurrent.CountDownLatch; 21 | import java.util.jar.Attributes; 22 | import java.util.regex.Matcher; 23 | import java.util.regex.Pattern; 24 | 25 | public class ShuYuZheService extends BaseService { 26 | private static String TAG = "test"; 27 | private final Handler mHandler; 28 | private int mPage; 29 | private String mBaseUrl; 30 | private CountDownLatch latch; 31 | private ArrayList list = new ArrayList<>(); 32 | 33 | public ShuYuZheService(Handler handler, String keywords) { 34 | super(handler, keywords); 35 | this.mHandler = handler; 36 | mPage = 1; 37 | mBaseUrl = Url.SHUYUZHE + keywords; 38 | } 39 | 40 | @Override 41 | public void get() { 42 | new Thread(new Runnable() { 43 | @Override 44 | public void run() { 45 | try { 46 | list.clear(); 47 | Log.d(TAG, "run: "+mBaseUrl + "/"+mPage); 48 | Elements select = Jsoup.connect(mBaseUrl + "/"+mPage) 49 | .timeout(10000) 50 | .ignoreContentType(true) 51 | .ignoreHttpErrors(true) 52 | .userAgent(Url.PC_AGENT) 53 | .get() 54 | .select("body > div.container > div > div > div.panel.panel-success > div.panel-body > table > tbody > tr"); 55 | latch = new CountDownLatch(select.size() - 1); 56 | for (int i = 1; i < select.size(); i++) { 57 | runInSameTime(select.get(i)); 58 | } 59 | 60 | Log.d(TAG, "run: "+select.size()); 61 | latch.await(); 62 | mPage++; 63 | 64 | 65 | 66 | 67 | Message msg = mHandler.obtainMessage(); 68 | msg.what = MsgType.SUCCESS; 69 | msg.obj = list; 70 | mHandler.sendMessage(msg); 71 | 72 | } catch (IOException e) { 73 | e.printStackTrace(); 74 | Message msg = mHandler.obtainMessage(); 75 | msg.what = MsgType.ERROR; 76 | mHandler.sendMessage(msg); 77 | } catch (InterruptedException e) { 78 | e.printStackTrace(); 79 | } 80 | } 81 | }).start(); 82 | } 83 | 84 | private void runInSameTime(final Element element) throws IOException { 85 | mExecutorService.execute(new Runnable() { 86 | @Override 87 | public void run() { 88 | try { 89 | Document document = Jsoup.connect(element.select("td:nth-child(1) > a").attr("abs:href")) 90 | .ignoreContentType(true) 91 | .userAgent(Url.PC_AGENT) 92 | .get(); 93 | Elements elements = document.select("ul.list-group"); 94 | String name = elements.select("li").get(2).text().replace("文件名称:Book.ShuYuZhe.com书语者_",""); 95 | String status = elements.select("li").get(4).text(); 96 | 97 | String time = elements.select("li").get(6).text(); 98 | 99 | String info = ""; 100 | 101 | String category = elements.select("li").get(5).text(); 102 | 103 | 104 | 105 | String author = ""; 106 | 107 | String words = elements.select("li").get(3).text(); 108 | 109 | 110 | String url = document.select("a:contains(下载此书)").attr("href"); 111 | String pic = ""; 112 | list.add(new NovelBean(name, time, info, category, status, author, words, pic, url)); 113 | } catch (IOException e) { 114 | e.printStackTrace(); 115 | } 116 | latch.countDown(); 117 | } 118 | }); 119 | } 120 | 121 | 122 | @Override 123 | public ArrayList getDownloadurls(final String url) throws InterruptedException { 124 | latch = new CountDownLatch(1); 125 | final ArrayList urls = new ArrayList<>(); 126 | mExecutorService.submit(new Runnable() { 127 | @Override 128 | public void run() { 129 | urls.add(new DownloadBean("全文下载", url)); 130 | latch.countDown(); 131 | } 132 | }); 133 | latch.await(); 134 | return urls; 135 | } 136 | 137 | } 138 | -------------------------------------------------------------------------------- /app/src/main/java/com/delsart/bookdownload/service/XiaoShuWuService.java: -------------------------------------------------------------------------------- 1 | package com.delsart.bookdownload.service; 2 | 3 | import android.os.Handler; 4 | import android.os.Message; 5 | 6 | import com.delsart.bookdownload.MsgType; 7 | import com.delsart.bookdownload.Url; 8 | import com.delsart.bookdownload.bean.DownloadBean; 9 | import com.delsart.bookdownload.bean.NovelBean; 10 | 11 | import org.jsoup.Jsoup; 12 | import org.jsoup.nodes.Document; 13 | import org.jsoup.nodes.Element; 14 | import org.jsoup.select.Elements; 15 | 16 | import java.io.IOException; 17 | import java.util.ArrayList; 18 | import java.util.concurrent.CountDownLatch; 19 | import java.util.regex.Matcher; 20 | import java.util.regex.Pattern; 21 | 22 | public class XiaoShuWuService extends BaseService { 23 | private static String TAG = "test"; 24 | private final Handler mHandler; 25 | private int mPage; 26 | private String mBaseUrl; 27 | private CountDownLatch latch; 28 | private ArrayList list = new ArrayList<>(); 29 | 30 | public XiaoShuWuService(Handler handler, String keywords) { 31 | super(handler, keywords); 32 | this.mHandler = handler; 33 | mPage = 1; 34 | mBaseUrl = Url.XIAOSHUWU + keywords; 35 | } 36 | 37 | @Override 38 | public void get() { 39 | new Thread(new Runnable() { 40 | @Override 41 | public void run() { 42 | try { 43 | list.clear(); 44 | Elements select = Jsoup.connect(mBaseUrl.replace("0", mPage + "")) 45 | .timeout(10000) 46 | .ignoreContentType(true) 47 | .ignoreHttpErrors(true) 48 | .userAgent(Url.MOBBILE_AGENT) 49 | .get() 50 | .select("div#posts-list").select("a"); 51 | latch = new CountDownLatch(select.size()); 52 | for (int i = 0; i < select.size(); i++) { 53 | runInSameTime(select.get(i)); 54 | } 55 | latch.await(); 56 | mPage++; 57 | Message msg = mHandler.obtainMessage(); 58 | msg.what = MsgType.SUCCESS; 59 | msg.obj = list; 60 | mHandler.sendMessage(msg); 61 | } catch (IOException e) { 62 | e.printStackTrace(); 63 | Message msg = mHandler.obtainMessage(); 64 | msg.what = MsgType.ERROR; 65 | mHandler.sendMessage(msg); 66 | } catch (InterruptedException e) { 67 | e.printStackTrace(); 68 | } 69 | } 70 | }).start(); 71 | } 72 | 73 | private void runInSameTime(final Element element) throws IOException { 74 | mExecutorService.submit(new Runnable() { 75 | @Override 76 | public void run() { 77 | String url = element.attr("abs:href"); 78 | Document document = null; 79 | try { 80 | document = Jsoup.connect(url) 81 | .ignoreContentType(true) 82 | .ignoreHttpErrors(true) 83 | .userAgent(Url.MOBBILE_AGENT) 84 | .get(); 85 | 86 | String t = document.select("#post-title").text(); 87 | String name = document.select("#post-title").text(); 88 | Matcher m = Pattern.compile("《.+》").matcher(t); 89 | if (m.find()) { 90 | name = m.group(0); 91 | } 92 | 93 | String time = document.select("#container > div > div.post_content > div > p:nth-child(5)").text().replace("作者信息", "\n作者信息"); 94 | String info = ""; 95 | Elements elements = document.select("#container > div > div.post_content > p"); 96 | for (int i = 0; i < elements.size(); i++) { 97 | if (!elements.get(i).text().equals("")) 98 | info = info + elements.get(i).text() + "\n\n"; 99 | 100 | 101 | } 102 | String category = document.select("#container > div > div.post_detail > ul:nth-child(1) > li:nth-child(1)").text() + "\n" + document.select("#container > div > div.post_detail > ul:nth-child(1) > li:nth-child(2)").text(); 103 | 104 | String status = ""; 105 | m = Pattern.compile("([^a-z]+).+").matcher(t); 106 | if (m.find()) { 107 | status = "文件格式:" + m.group(0).replaceAll("([^a-z]+)", ""); 108 | } 109 | 110 | String author = ""; 111 | m = Pattern.compile("》.+([^a-z]+)").matcher(t); 112 | if (m.find()) { 113 | author = "书籍作者:" + m.group(0).replaceAll("([^a-z]+)", "").replace("》", ""); 114 | } 115 | 116 | String words = ""; 117 | String pic = document.select("#container > div > div.post_content > p:nth-child(1) > img").attr("abs:src"); 118 | String durl = document.select("#container > div > div.post_content > div > p.downlink > strong > a").attr("abs:href"); 119 | NovelBean no = new NovelBean(name, time, info, category, status, author, words, pic, durl); 120 | list.add(no); 121 | } catch (IOException e) { 122 | e.printStackTrace(); 123 | } 124 | latch.countDown(); 125 | } 126 | }); 127 | } 128 | 129 | 130 | @Override 131 | public ArrayList getDownloadurls(final String url) throws InterruptedException { 132 | latch = new CountDownLatch(1); 133 | final ArrayList urls = new ArrayList<>(); 134 | mExecutorService.submit(new Runnable() { 135 | @Override 136 | public void run() { 137 | Document document = null; 138 | try { 139 | document = Jsoup.connect(url) 140 | .timeout(10000) 141 | .ignoreContentType(true) 142 | .ignoreHttpErrors(true) 143 | .userAgent(Url.MOBBILE_AGENT) 144 | .get(); 145 | 146 | String u1 = ""; 147 | String u1n = document.select("body > div:nth-child(4) > p:nth-child(7)").text(); 148 | Elements elements = document.select("body > div.list").select("a"); 149 | urls.add(new DownloadBean(u1n, u1)); 150 | for (Element element : elements) { 151 | urls.add(new DownloadBean(element.text(), element.attr("abs:href"))); 152 | } 153 | } catch (IOException e) { 154 | e.printStackTrace(); 155 | } 156 | latch.countDown(); 157 | } 158 | }); 159 | latch.await(); 160 | return urls; 161 | } 162 | 163 | } 164 | -------------------------------------------------------------------------------- /app/src/main/java/com/delsart/bookdownload/service/ZhiXuanService.java: -------------------------------------------------------------------------------- 1 | package com.delsart.bookdownload.service; 2 | 3 | import android.os.Handler; 4 | import android.os.Message; 5 | 6 | import com.delsart.bookdownload.MsgType; 7 | import com.delsart.bookdownload.Url; 8 | import com.delsart.bookdownload.bean.DownloadBean; 9 | import com.delsart.bookdownload.bean.NovelBean; 10 | 11 | import org.jsoup.Jsoup; 12 | import org.jsoup.nodes.Document; 13 | import org.jsoup.nodes.Element; 14 | import org.jsoup.select.Elements; 15 | 16 | import java.io.IOException; 17 | import java.util.ArrayList; 18 | import java.util.concurrent.CountDownLatch; 19 | import java.util.regex.Matcher; 20 | import java.util.regex.Pattern; 21 | 22 | public class ZhiXuanService extends BaseService { 23 | private static String TAG = "test"; 24 | private final Handler mHandler; 25 | private int mPage; 26 | private String mBaseUrl; 27 | private CountDownLatch latch; 28 | private ArrayList list = new ArrayList<>(); 29 | 30 | public ZhiXuanService(Handler handler, String keywords) { 31 | super(handler, keywords); 32 | this.mHandler = handler; 33 | mPage = 1; 34 | mBaseUrl = Url.ZHIXUAN + keywords + "&page="; 35 | } 36 | String lasts=""; 37 | @Override 38 | public void get() { 39 | new Thread(new Runnable() { 40 | @Override 41 | public void run() { 42 | try { 43 | list.clear(); 44 | Elements select = Jsoup.connect(mBaseUrl + mPage) 45 | .timeout(10000) 46 | .ignoreContentType(true) 47 | .ignoreHttpErrors(true) 48 | .userAgent(Url.MOBBILE_AGENT) 49 | .get() 50 | .select("div.info"); 51 | latch = new CountDownLatch(select.size()); 52 | for (int i = 0; i < select.size(); i++) { 53 | runInSameTime(select.get(i)); 54 | } 55 | latch.await(); 56 | if (select.toString().equals(lasts)) 57 | list.clear(); 58 | lasts=select.toString(); 59 | mPage++; 60 | Message msg = mHandler.obtainMessage(); 61 | msg.what = MsgType.SUCCESS; 62 | msg.obj = list; 63 | mHandler.sendMessage(msg); 64 | } catch (IOException e) { 65 | e.printStackTrace(); 66 | Message msg = mHandler.obtainMessage(); 67 | msg.what = MsgType.ERROR; 68 | mHandler.sendMessage(msg); 69 | } catch (InterruptedException e) { 70 | e.printStackTrace(); 71 | } 72 | } 73 | }).start(); 74 | } 75 | 76 | private void runInSameTime(final Element element) throws IOException { 77 | mExecutorService.submit(new Runnable() { 78 | @Override 79 | public void run() { 80 | String url = element.select("a").attr("abs:href"); 81 | Document document = null; 82 | try { 83 | document = Jsoup.connect(url) 84 | .ignoreContentType(true) 85 | .ignoreHttpErrors(true) 86 | .userAgent(Url.MOBBILE_AGENT) 87 | .get(); 88 | 89 | String t = document.select("#m > div.postcont > p:nth-child(4)").text(); 90 | String name = document.select("#m > div.posttitle").text().replace("(校对版全本)", "").replace("《", "").replace("》", ""); 91 | String time = "收录日期:" + element.select("span").text(); 92 | String info = ""; 93 | Matcher m = Pattern.compile("【内容简介】.+").matcher(t); 94 | if (m.find()) 95 | info = m.group(0).replace("  ", "\n").replace("      ", "\n").replace("【内容简介】: \n", ""); 96 | String category = document.select("#m > div.postcont > div.pagefujian > div.filecont > p.fileinfo > span:nth-child(1)").text(); 97 | String status = ""; 98 | String author = ""; 99 | if (name.contains("作者")) { 100 | author = name.substring(name.indexOf("作者"), name.length()); 101 | name = name.replace(author, ""); 102 | } 103 | String words = ""; 104 | if (t.contains("【内容简介")) 105 | words = t.substring(0, t.indexOf("【内容简介")).replace("【", "").replace("】", ""); 106 | String pic = document.select("img[title=点击查看原图]").attr("abs:src"); 107 | String durl=document.select("#m > div.postcont > div.pagefujian > div.filecont > p.filetit > a").attr("abs:href"); 108 | NovelBean no = new NovelBean(name, time, info, category, status, author, words, pic, durl); 109 | list.add(no); 110 | } catch (IOException e) { 111 | e.printStackTrace(); 112 | } 113 | latch.countDown(); 114 | } 115 | }); 116 | } 117 | 118 | 119 | @Override 120 | public ArrayList getDownloadurls(final String url) throws InterruptedException { 121 | latch = new CountDownLatch(1); 122 | final ArrayList urls = new ArrayList<>(); 123 | mExecutorService.execute(new Runnable() { 124 | @Override 125 | public void run() { 126 | Document document = null; 127 | try { 128 | document = Jsoup.connect(url) 129 | .timeout(10000) 130 | .ignoreContentType(true) 131 | .ignoreHttpErrors(true) 132 | .userAgent(Url.MOBBILE_AGENT) 133 | .get(); 134 | Elements elements=document.select("body > div.wrap > div.content > div:nth-child(4) > div.panel-body a"); 135 | for (Element element : elements) { 136 | urls.add(new DownloadBean(element.text(), element.attr("abs:href"))); 137 | } 138 | } catch (IOException e) { 139 | e.printStackTrace(); 140 | } 141 | latch.countDown(); 142 | } 143 | }); 144 | latch.await(); 145 | return urls; 146 | } 147 | 148 | } 149 | -------------------------------------------------------------------------------- /app/src/main/java/com/delsart/bookdownload/service/ZhouDuService.java: -------------------------------------------------------------------------------- 1 | package com.delsart.bookdownload.service; 2 | 3 | import android.os.Handler; 4 | import android.os.Message; 5 | 6 | import com.delsart.bookdownload.MsgType; 7 | import com.delsart.bookdownload.Url; 8 | import com.delsart.bookdownload.bean.DownloadBean; 9 | import com.delsart.bookdownload.bean.NovelBean; 10 | 11 | import org.jsoup.Jsoup; 12 | import org.jsoup.nodes.Document; 13 | import org.jsoup.nodes.Element; 14 | import org.jsoup.select.Elements; 15 | 16 | import java.io.IOException; 17 | import java.util.ArrayList; 18 | import java.util.concurrent.CountDownLatch; 19 | 20 | public class ZhouDuService extends BaseService { 21 | private static String TAG = "test"; 22 | private final Handler mHandler; 23 | private int mPage; 24 | private String mBaseUrl; 25 | private CountDownLatch latch; 26 | private ArrayList list = new ArrayList<>(); 27 | 28 | public ZhouDuService(Handler handler, String keywords) { 29 | super(handler, keywords); 30 | this.mHandler = handler; 31 | mPage = 1; 32 | mBaseUrl = Url.ZHOUDU + keywords + "&page="; 33 | } 34 | 35 | @Override 36 | public void get() { 37 | new Thread(new Runnable() { 38 | @Override 39 | public void run() { 40 | try { 41 | list.clear(); 42 | Elements select = Jsoup.connect(mBaseUrl + mPage) 43 | .timeout(10000) 44 | .ignoreContentType(true) 45 | .ignoreHttpErrors(true) 46 | .get() 47 | .select("body > div > div > ul > a"); 48 | latch = new CountDownLatch(select.size()); 49 | for (int i = 0; i < select.size(); i++) { 50 | runInSameTime(select.get(i)); 51 | } 52 | latch.await(); 53 | mPage++; 54 | Message msg = mHandler.obtainMessage(); 55 | msg.what = MsgType.SUCCESS; 56 | msg.obj = list; 57 | mHandler.sendMessage(msg); 58 | } catch (IOException e) { 59 | e.printStackTrace(); 60 | Message msg = mHandler.obtainMessage(); 61 | msg.what = MsgType.ERROR; 62 | mHandler.sendMessage(msg); 63 | } catch (InterruptedException e) { 64 | e.printStackTrace(); 65 | } 66 | } 67 | }).start(); 68 | } 69 | 70 | private void runInSameTime(final Element element) throws IOException { 71 | mExecutorService.submit(new Runnable() { 72 | @Override 73 | public void run() { 74 | try { 75 | Document document = Jsoup.connect(element.attr("abs:href")) 76 | .ignoreContentType(true) 77 | .ignoreHttpErrors(true) 78 | .get(); 79 | 80 | String t = document.select("body > div > div > div.hanghang-za > div.hanghang-shu-content > div.hanghang-shu-content-font").text(); 81 | if (t.length() < 5) { 82 | latch.countDown(); 83 | return; 84 | } 85 | String name = document.select("body > div > div > div.hanghang-za > div:nth-child(1)").text(); 86 | String status = ""; 87 | String time = ""; 88 | String info = t.substring(t.indexOf("简介"), t.length()); 89 | String category = document.select("body > div > div > div.hanghang-za > div.hanghang-shu-content > div.hanghang-shu-content-font > p:nth-child(2)").text(); 90 | String author = document.select("body > div > div > div.hanghang-za > div.hanghang-shu-content > div.hanghang-shu-content-font > p:nth-child(1)").text(); 91 | String words = ""; 92 | String url = document.select("body > div > div > div.hanghang-za > div.hanghang-box > div.hanghang-shu-content-btn > a").attr("href"); 93 | String pic = document.select("body > div > div > div.hanghang-za > div.hanghang-shu-content > div.hanghang-shu-content-img > img").attr("abs:src"); 94 | NovelBean no = new NovelBean(name, time, info, category, status, author, words, pic, url); 95 | list.add(no); 96 | } catch (IOException e) { 97 | e.printStackTrace(); 98 | } 99 | 100 | 101 | latch.countDown(); 102 | 103 | } 104 | }); 105 | } 106 | 107 | 108 | @Override 109 | public ArrayList getDownloadurls(final String url) throws InterruptedException { 110 | latch = new CountDownLatch(1); 111 | final ArrayList urls = new ArrayList<>(); 112 | mExecutorService.submit(new Runnable() { 113 | @Override 114 | public void run() { 115 | urls.add(new DownloadBean("百度云", url)); 116 | latch.countDown(); 117 | } 118 | }); 119 | latch.await(); 120 | return urls; 121 | } 122 | 123 | } 124 | -------------------------------------------------------------------------------- /app/src/main/java/com/delsart/bookdownload/ui/activity/AboutActivity.java: -------------------------------------------------------------------------------- 1 | package com.delsart.bookdownload.ui.activity; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | import android.content.Intent; 6 | import android.content.pm.PackageManager; 7 | import android.net.Uri; 8 | import android.os.Bundle; 9 | import android.os.PersistableBundle; 10 | import android.preference.PreferenceManager; 11 | import android.support.annotation.NonNull; 12 | import android.support.annotation.Nullable; 13 | import android.support.v4.content.ContextCompat; 14 | import android.util.AttributeSet; 15 | import android.view.View; 16 | import android.widget.Toast; 17 | 18 | import com.danielstone.materialaboutlibrary.ConvenienceBuilder; 19 | import com.danielstone.materialaboutlibrary.MaterialAboutActivity; 20 | import com.danielstone.materialaboutlibrary.items.MaterialAboutActionItem; 21 | import com.danielstone.materialaboutlibrary.items.MaterialAboutItemOnClickAction; 22 | import com.danielstone.materialaboutlibrary.items.MaterialAboutTitleItem; 23 | import com.danielstone.materialaboutlibrary.model.MaterialAboutCard; 24 | import com.danielstone.materialaboutlibrary.model.MaterialAboutList; 25 | import com.danielstone.materialaboutlibrary.util.ViewTypeManager; 26 | import com.delsart.bookdownload.MyApplication; 27 | import com.delsart.bookdownload.R; 28 | import com.delsart.bookdownload.Url; 29 | import com.delsart.bookdownload.custom.MyViewTypeManager; 30 | import com.mikepenz.community_material_typeface_library.CommunityMaterial; 31 | import com.mikepenz.iconics.IconicsDrawable; 32 | 33 | import java.net.URL; 34 | 35 | import moe.feng.alipay.zerosdk.AlipayZeroSdk; 36 | 37 | /** 38 | * Created by Delsart on 2017/7/24. 39 | */ 40 | 41 | public class AboutActivity extends MaterialAboutActivity { 42 | public static final String THEME_EXTRA = ""; 43 | public static final int THEME_LIGHT_LIGHTBAR = 0; 44 | public static final int THEME_LIGHT_DARKBAR = 1; 45 | public static final int THEME_DARK_LIGHTBAR = 2; 46 | public static final int THEME_DARK_DARKBAR = 3; 47 | public static final int THEME_CUSTOM_CARDVIEW = 4; 48 | 49 | protected int colorIcon = R.color.DayColor; 50 | 51 | @Override 52 | protected void onCreate(@Nullable Bundle savedInstanceState) { 53 | if (PreferenceManager.getDefaultSharedPreferences(this).getBoolean("dark_theme", false)) { 54 | setTheme(R.style.DarkTheme_aboutTheme); 55 | colorIcon = R.color.DarkColor; 56 | } 57 | else 58 | setTheme(R.style.aboutTheme); 59 | super.onCreate(savedInstanceState); 60 | } 61 | 62 | 63 | @NonNull 64 | @Override 65 | protected MaterialAboutList getMaterialAboutList(@NonNull final Context c) { 66 | final Activity activity = this; 67 | MaterialAboutCard.Builder appCardBuilder = new MaterialAboutCard.Builder(); 68 | // Add items to card 69 | appCardBuilder.addItem(new MaterialAboutTitleItem.Builder() 70 | .text(R.string.app_name) 71 | .desc("© 2017 Delsart") 72 | .icon(R.mipmap.ic_launcher) 73 | .build()); 74 | 75 | try { 76 | 77 | appCardBuilder.addItem(ConvenienceBuilder.createVersionActionItem(c, 78 | new IconicsDrawable(c) 79 | .icon(CommunityMaterial.Icon.cmd_information_outline) 80 | .color(ContextCompat.getColor(c, colorIcon)) 81 | .sizeDp(18), 82 | "版本", 83 | false)); 84 | 85 | } catch (PackageManager.NameNotFoundException e) { 86 | e.printStackTrace(); 87 | } 88 | 89 | appCardBuilder.addItem(new MaterialAboutActionItem.Builder() 90 | .text("更新日志") 91 | .icon(new IconicsDrawable(c) 92 | .icon(CommunityMaterial.Icon.cmd_history) 93 | .color(ContextCompat.getColor(c, colorIcon)) 94 | .sizeDp(18)) 95 | .setOnClickAction(ConvenienceBuilder.createWebViewDialogOnClickAction(c, "", "https://github.com/Delsart/Bookster/blob/master/%E6%9B%B4%E6%96%B0%E6%97%A5%E5%BF%97.txt", true, false)) 96 | .build()); 97 | 98 | 99 | MaterialAboutCard.Builder authorCardBuilder = new MaterialAboutCard.Builder(); 100 | authorCardBuilder.title("作者相关"); 101 | // authorCardBuilder.titleColor(ContextCompat.getColor(c, R.color.colorAccent)); 102 | 103 | authorCardBuilder.addItem(new MaterialAboutActionItem.Builder() 104 | .text("Delsart") 105 | .subText("作者 , 中国") 106 | .icon(new IconicsDrawable(c) 107 | .icon(CommunityMaterial.Icon.cmd_account) 108 | .color(ContextCompat.getColor(c, colorIcon)) 109 | .sizeDp(18)) 110 | .setOnClickAction( 111 | ConvenienceBuilder.createWebsiteOnClickAction(c, Uri.parse("https://www.coolapk.com/u/473036"))) 112 | .build()); 113 | 114 | 115 | authorCardBuilder.addItem(new MaterialAboutActionItem.Builder() 116 | .text("Archie") 117 | .subText("图标设计者 , 中国") 118 | .icon(new IconicsDrawable(c) 119 | .icon(CommunityMaterial.Icon.cmd_account) 120 | .color(ContextCompat.getColor(c, colorIcon)) 121 | .sizeDp(18)) 122 | .setOnClickAction(ConvenienceBuilder.createWebsiteOnClickAction(c, Uri.parse("https://www.coolapk.com/u/801526"))) 123 | .build()); 124 | 125 | authorCardBuilder.addItem(new MaterialAboutActionItem.Builder() 126 | .text("Fairyex") 127 | .subText("空视图设计者 , 中国") 128 | .icon(new IconicsDrawable(c) 129 | .icon(CommunityMaterial.Icon.cmd_account) 130 | .color(ContextCompat.getColor(c, colorIcon)) 131 | .sizeDp(18)) 132 | .setOnClickAction(ConvenienceBuilder.createWebsiteOnClickAction(c, Uri.parse("http://www.coolapk.com/u/466253"))) 133 | .build()); 134 | 135 | authorCardBuilder.addItem(new MaterialAboutActionItem.Builder() 136 | .text("Used-open-sources") 137 | .icon(new IconicsDrawable(c) 138 | .icon(CommunityMaterial.Icon.cmd_android_debug_bridge) 139 | .color(ContextCompat.getColor(c, colorIcon)) 140 | .sizeDp(18)) 141 | .setOnClickAction(new MaterialAboutItemOnClickAction() { 142 | @Override 143 | public void onClick() { 144 | Intent intent = new Intent(c, UsedOpenSource.class); 145 | intent.putExtra(AboutActivity.THEME_EXTRA, getIntent().getIntExtra(THEME_EXTRA, THEME_LIGHT_DARKBAR)); 146 | c.startActivity(intent); 147 | } 148 | }) 149 | .build()); 150 | 151 | authorCardBuilder.addItem(new MaterialAboutActionItem.Builder() 152 | .text("Fork on GitHub") 153 | .icon(new IconicsDrawable(c) 154 | .icon(CommunityMaterial.Icon.cmd_github_circle) 155 | .color(ContextCompat.getColor(c, colorIcon)) 156 | .sizeDp(18)) 157 | .setOnClickAction(ConvenienceBuilder.createWebsiteOnClickAction(c, Uri.parse("https://github.com/Delsart/Bookster"))) 158 | .build()); 159 | 160 | 161 | MaterialAboutCard.Builder convenienceCardBuilder = new MaterialAboutCard.Builder(); 162 | convenienceCardBuilder.title("更多"); 163 | convenienceCardBuilder.addItem(ConvenienceBuilder.createWebsiteActionItem(c, 164 | new IconicsDrawable(c) 165 | .icon(CommunityMaterial.Icon.cmd_earth) 166 | .color(ContextCompat.getColor(c, colorIcon)) 167 | .sizeDp(18), 168 | "访问我们的主页", 169 | true, 170 | Uri.parse("https://hereacg.org"))); 171 | 172 | convenienceCardBuilder.addItem(ConvenienceBuilder.createRateActionItem(c, 173 | new IconicsDrawable(c) 174 | .icon(CommunityMaterial.Icon.cmd_star) 175 | .color(ContextCompat.getColor(c, colorIcon)) 176 | .sizeDp(18), 177 | "为这个应用评分", 178 | null 179 | )); 180 | 181 | convenienceCardBuilder.addItem(ConvenienceBuilder.createEmailItem(c, 182 | new IconicsDrawable(c) 183 | .icon(CommunityMaterial.Icon.cmd_email) 184 | .color(ContextCompat.getColor(c, colorIcon)) 185 | .sizeDp(18), 186 | "发送邮件", 187 | true, 188 | "2289582155@qq.com", 189 | "Question concerning MaterialAboutLibrary")); 190 | 191 | convenienceCardBuilder.addItem(new MaterialAboutActionItem.Builder() 192 | .text("捐赠,请作者女装(误)喝杯果汁(支付宝)") 193 | .icon(new IconicsDrawable(c) 194 | .icon(CommunityMaterial.Icon.cmd_coffee) 195 | .color(ContextCompat.getColor(c, colorIcon)) 196 | .sizeDp(18)) 197 | .setOnClickAction(new MaterialAboutItemOnClickAction() { 198 | @Override 199 | public void onClick() { 200 | if (AlipayZeroSdk.hasInstalledAlipayClient(MyApplication.getContext())) 201 | AlipayZeroSdk.startAlipayClient(activity, "a6x02835mi3wh18ivz0mbdb"); 202 | else 203 | Toast.makeText(getApplicationContext(), "没有安装支付宝", Toast.LENGTH_SHORT).show(); 204 | } 205 | }) 206 | .build()); 207 | 208 | convenienceCardBuilder.addItem(new MaterialAboutActionItem.Builder() 209 | .text("捐赠,请作者女装(误)喝杯果汁(微信)") 210 | .icon(new IconicsDrawable(c) 211 | .icon(CommunityMaterial.Icon.cmd_coffee) 212 | .color(ContextCompat.getColor(c, colorIcon)) 213 | .sizeDp(18)) 214 | .setOnClickAction(new MaterialAboutItemOnClickAction() { 215 | @Override 216 | public void onClick() { 217 | Uri uri = Uri.parse("http://a3.qpic.cn/psb?/V10dNxbX00vsuB/eKAX6FA4sv5Y3Tnb.lrqpj6OjMWE6QuHyv2Z*h2MBtk!/b/dGoBAAAAAAAA&bo=.AJSA*gCUgMDCSw!&rf=viewer_4"); 218 | startActivity(new Intent(Intent.ACTION_VIEW, uri)); 219 | } 220 | }) 221 | .build()); 222 | 223 | MaterialAboutCard.Builder otherCardBuilder = new MaterialAboutCard.Builder(); 224 | otherCardBuilder.title("来源"); 225 | otherCardBuilder.addItem(ConvenienceBuilder.createWebsiteActionItem(c, 226 | new IconicsDrawable(c) 227 | .icon(CommunityMaterial.Icon.cmd_earth) 228 | .color(ContextCompat.getColor(c, colorIcon)) 229 | .sizeDp(18), 230 | "爱下小说", 231 | true, 232 | Uri.parse("http://m.ixdzs.com"))); 233 | 234 | otherCardBuilder.addItem(ConvenienceBuilder.createWebsiteActionItem(c, 235 | new IconicsDrawable(c) 236 | .icon(CommunityMaterial.Icon.cmd_earth) 237 | .color(ContextCompat.getColor(c, colorIcon)) 238 | .sizeDp(18), 239 | "知轩藏书", 240 | true, 241 | Uri.parse("http://www.zxcs8.com"))); 242 | 243 | otherCardBuilder.addItem(ConvenienceBuilder.createWebsiteActionItem(c, 244 | new IconicsDrawable(c) 245 | .icon(CommunityMaterial.Icon.cmd_earth) 246 | .color(ContextCompat.getColor(c, colorIcon)) 247 | .sizeDp(18), 248 | "周读", 249 | true, 250 | Uri.parse("http://www.ireadweek.com"))); 251 | 252 | otherCardBuilder.addItem(ConvenienceBuilder.createWebsiteActionItem(c, 253 | new IconicsDrawable(c) 254 | .icon(CommunityMaterial.Icon.cmd_earth) 255 | .color(ContextCompat.getColor(c, colorIcon)) 256 | .sizeDp(18), 257 | "书语者", 258 | true, 259 | Uri.parse("https://book.shuyuzhe.com"))); 260 | 261 | otherCardBuilder.addItem(ConvenienceBuilder.createWebsiteActionItem(c, 262 | new IconicsDrawable(c) 263 | .icon(CommunityMaterial.Icon.cmd_earth) 264 | .color(ContextCompat.getColor(c, colorIcon)) 265 | .sizeDp(18), 266 | "动漫之家", 267 | true, 268 | Uri.parse("https://www.dmzj.com/"))); 269 | 270 | otherCardBuilder.addItem(ConvenienceBuilder.createWebsiteActionItem(c, 271 | new IconicsDrawable(c) 272 | .icon(CommunityMaterial.Icon.cmd_earth) 273 | .color(ContextCompat.getColor(c, colorIcon)) 274 | .sizeDp(18), 275 | "360℃", 276 | true, 277 | Uri.parse("http://www.360dxs.com"))); 278 | otherCardBuilder.addItem(ConvenienceBuilder.createWebsiteActionItem(c, 279 | new IconicsDrawable(c) 280 | .icon(CommunityMaterial.Icon.cmd_earth) 281 | .color(ContextCompat.getColor(c, colorIcon)) 282 | .sizeDp(18), 283 | "我的小书屋", 284 | true, 285 | Uri.parse("http://mebook.cc"))); 286 | otherCardBuilder.addItem(ConvenienceBuilder.createWebsiteActionItem(c, 287 | new IconicsDrawable(c) 288 | .icon(CommunityMaterial.Icon.cmd_earth) 289 | .color(ContextCompat.getColor(c, colorIcon)) 290 | .sizeDp(18), 291 | "奇书网", 292 | true, 293 | Uri.parse("http://www.qisuu.com"))); 294 | otherCardBuilder.addItem(ConvenienceBuilder.createWebsiteActionItem(c, 295 | new IconicsDrawable(c) 296 | .icon(CommunityMaterial.Icon.cmd_earth) 297 | .color(ContextCompat.getColor(c, colorIcon)) 298 | .sizeDp(18), 299 | "Blah", 300 | true, 301 | Uri.parse("http://blah.me"))); 302 | return new MaterialAboutList(appCardBuilder.build(), authorCardBuilder.build(), convenienceCardBuilder.build(), otherCardBuilder.build()); 303 | } 304 | 305 | 306 | @Override 307 | protected CharSequence getActivityTitle() { 308 | return "关于"; 309 | } 310 | 311 | @NonNull 312 | @Override 313 | protected ViewTypeManager getViewTypeManager() { 314 | return new MyViewTypeManager(); 315 | } 316 | } 317 | 318 | -------------------------------------------------------------------------------- /app/src/main/java/com/delsart/bookdownload/ui/activity/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.delsart.bookdownload.ui.activity; 2 | 3 | 4 | import android.content.DialogInterface; 5 | import android.content.Intent; 6 | import android.content.SharedPreferences; 7 | import android.content.pm.PackageInfo; 8 | import android.content.pm.PackageManager; 9 | import android.net.Uri; 10 | import android.os.Bundle; 11 | import android.preference.PreferenceManager; 12 | import android.support.design.widget.FloatingActionButton; 13 | import android.support.design.widget.TabLayout; 14 | import android.support.v4.view.MenuItemCompat; 15 | import android.support.v4.view.ViewPager; 16 | import android.support.v7.app.AlertDialog; 17 | import android.support.v7.app.AppCompatActivity; 18 | import android.support.v7.widget.SearchView; 19 | import android.support.v7.widget.Toolbar; 20 | import android.util.Log; 21 | import android.view.KeyEvent; 22 | import android.view.Menu; 23 | import android.view.MenuItem; 24 | import android.view.View; 25 | import android.widget.Toast; 26 | 27 | import com.delsart.bookdownload.MyApplication; 28 | import com.delsart.bookdownload.R; 29 | import com.delsart.bookdownload.adapter.PagerAdapter; 30 | import com.delsart.bookdownload.ui.fragment.AiXiaFragment; 31 | import com.delsart.bookdownload.ui.fragment.BaseFragment; 32 | import com.delsart.bookdownload.ui.fragment.BlahFragment; 33 | import com.delsart.bookdownload.ui.fragment.DongManZhiJiaFragment; 34 | import com.delsart.bookdownload.ui.fragment.M360DFragment; 35 | import com.delsart.bookdownload.ui.fragment.QiShuFragment; 36 | import com.delsart.bookdownload.ui.fragment.ShuYuZheFragment; 37 | import com.delsart.bookdownload.ui.fragment.XiaoShuWuFragment; 38 | import com.delsart.bookdownload.ui.fragment.ZhiXuanFragment; 39 | import com.delsart.bookdownload.ui.fragment.ZhouDuFragment; 40 | import com.delsart.bookdownload.utils.StatusBarUtils; 41 | 42 | import org.json.JSONObject; 43 | 44 | import java.io.BufferedReader; 45 | import java.io.InputStream; 46 | import java.io.InputStreamReader; 47 | import java.net.HttpURLConnection; 48 | import java.net.URL; 49 | import java.util.ArrayList; 50 | import java.util.List; 51 | 52 | import moe.feng.alipay.zerosdk.AlipayZeroSdk; 53 | 54 | public class MainActivity extends AppCompatActivity { 55 | private SharedPreferences firstime; 56 | private SharedPreferences.Editor editor; 57 | private PagerAdapter mPagerAdapter; 58 | private SearchView searchView; 59 | private SharedPreferences autoupdate; 60 | String lastKeyWords = ""; 61 | 62 | 63 | @Override 64 | protected void onCreate(Bundle savedInstanceState) { 65 | if (PreferenceManager.getDefaultSharedPreferences(this).getBoolean("dark_theme", false)) 66 | setTheme(R.style.DarkTheme); 67 | else 68 | setTheme(R.style.DayTheme); 69 | 70 | super.onCreate(savedInstanceState); 71 | setContentView(R.layout.activity_main); 72 | autoupdate = getSharedPreferences("com.delsart.bookdownload_preferences", MODE_PRIVATE); 73 | StatusBarUtils.MIUISetStatusBarLightMode(this, true); 74 | Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); 75 | setSupportActionBar(toolbar); 76 | initView(); 77 | showInfoDialog(); 78 | 79 | 80 | if (autoupdate.getBoolean("autoUpdate", true)) { 81 | 82 | // try { 83 | // getUpdate(); 84 | // } catch (Exception e) { 85 | // e.printStackTrace(); 86 | // } 87 | } 88 | } 89 | 90 | private void showInfoDialog() { 91 | firstime = getSharedPreferences("data", MODE_PRIVATE); 92 | editor = firstime.edit(); 93 | if (firstime.getInt("first", 0) == 0) { 94 | AlertDialog.Builder builder = new AlertDialog.Builder(this); 95 | builder.setTitle("使用须知"); 96 | builder.setCancelable(false); 97 | builder.setMessage(R.string.firstlaunchshowtext); 98 | builder.setNegativeButton("拒绝", new DialogInterface.OnClickListener() { 99 | @Override 100 | public void onClick(DialogInterface dialog, int which) { 101 | finish(); 102 | } 103 | }); 104 | builder.setPositiveButton("知道了", new DialogInterface.OnClickListener() { 105 | @Override 106 | public void onClick(DialogInterface dialog, int which) { 107 | editor.putInt("first", 1); 108 | editor.apply(); 109 | } 110 | }); 111 | builder.show(); 112 | } 113 | if (firstime.getInt("showrate", 1) > 3 && firstime.getBoolean("ifshowrate", true)) { 114 | editor.putInt("showrate", 1); 115 | editor.apply(); 116 | AlertDialog.Builder builder = new AlertDialog.Builder(this); 117 | builder.setTitle("嗨,还好吗?"); 118 | builder.setMessage(R.string.showrate); 119 | builder.setNegativeButton("评分", new DialogInterface.OnClickListener() { 120 | @Override 121 | public void onClick(DialogInterface dialog, int which) { 122 | Uri uri = Uri.parse("market://details?id=" + getPackageName()); 123 | Intent intent = new Intent(Intent.ACTION_VIEW, uri); 124 | intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 125 | startActivity(intent); 126 | } 127 | }); 128 | builder.setPositiveButton("捐赠", new DialogInterface.OnClickListener() { 129 | @Override 130 | public void onClick(DialogInterface dialog, int which) { 131 | if (AlipayZeroSdk.hasInstalledAlipayClient(MyApplication.getContext())) 132 | AlipayZeroSdk.startAlipayClient(MainActivity.this, "a6x02835mi3wh18ivz0mbdb"); 133 | else 134 | Toast.makeText(getApplicationContext(), "没有安装支付宝", Toast.LENGTH_SHORT).show(); 135 | 136 | } 137 | }); 138 | builder.setNeutralButton("拒绝,并不再提醒", new DialogInterface.OnClickListener() { 139 | @Override 140 | public void onClick(DialogInterface dialog, int which) { 141 | editor.putBoolean("ifshowrate", false); 142 | editor.apply(); 143 | } 144 | }); 145 | builder.show(); 146 | } else { 147 | editor.putInt("showrate", firstime.getInt("showrate", 1) + 1); 148 | editor.apply(); 149 | } 150 | } 151 | 152 | private void getUpdate() throws Exception { 153 | new Thread(new Runnable() { 154 | @Override 155 | public void run() { 156 | try { 157 | URL url = new URL("https://hereacg.org/bookster/update.json"); 158 | HttpURLConnection connection = (HttpURLConnection) url.openConnection(); 159 | connection.setRequestMethod("GET"); 160 | connection.setConnectTimeout(3000); 161 | InputStream in = connection.getInputStream(); 162 | // 下面对获取到的输入流进行读取 163 | BufferedReader reader = new BufferedReader(new InputStreamReader(in)); 164 | StringBuilder response = new StringBuilder(); 165 | String line; 166 | while ((line = reader.readLine()) != null) { 167 | response.append(line); 168 | } 169 | parseJSONWithJSONObject(response.toString()); 170 | } catch (Exception e) { 171 | e.printStackTrace(); 172 | } 173 | } 174 | }).start(); 175 | } 176 | 177 | private void parseJSONWithJSONObject(String jsonDatas) { 178 | final String jsonData = jsonDatas; 179 | new Thread(new Runnable() { 180 | @Override 181 | public void run() { 182 | try { 183 | JSONObject jsonObject = new JSONObject(jsonData); 184 | String version = jsonObject.getString("version"); 185 | String info = jsonObject.getString("info"); 186 | String time = jsonObject.getString("time"); 187 | String size = jsonObject.getString("size"); 188 | final String url = jsonObject.getString("url"); 189 | PackageManager manager = getPackageManager(); 190 | PackageInfo infos = manager.getPackageInfo(getPackageName(), 0); 191 | Log.d("sss", "run: " + version + gettrueversion(version) + "ssssss" + gettrueversion(infos.versionName)); 192 | if (gettrueversion(version) > gettrueversion(infos.versionName)) { 193 | showupdate(version, time, size, info, url); 194 | } 195 | } catch (Exception e) { 196 | e.printStackTrace(); 197 | } 198 | } 199 | }).start(); 200 | } 201 | 202 | public float gettrueversion(String s) { 203 | String s2 = ""; 204 | for (char a : s.toCharArray()) { 205 | 206 | if ("0123456789.".indexOf(a) >= 0) { 207 | s2 = s2 + a; 208 | 209 | } 210 | } 211 | 212 | return Float.parseFloat(s2); 213 | } 214 | 215 | public void showupdate(final String version, final String time, final String size, final String info, final String url) { 216 | runOnUiThread(new Runnable() { 217 | @Override 218 | public void run() { 219 | AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this); 220 | builder.setTitle("有新版本"); 221 | builder.setMessage("版本号:" + version + "\n更新时间:" + time + "\nApk大小:" + size + "MB\n更新日志:" + info); 222 | builder.setNegativeButton("取消", null); 223 | builder.setPositiveButton("下载", new DialogInterface.OnClickListener() { 224 | @Override 225 | public void onClick(DialogInterface dialog, int which) { 226 | Uri uri = Uri.parse(url); 227 | startActivity(new Intent(Intent.ACTION_VIEW, uri)); 228 | } 229 | }); 230 | builder.setNeutralButton("关闭自动检查", new DialogInterface.OnClickListener() { 231 | @Override 232 | public void onClick(DialogInterface dialog, int which) { 233 | SharedPreferences.Editor editor = autoupdate.edit(); 234 | editor.putBoolean("autoUpdate", false); 235 | editor.apply(); 236 | } 237 | }); 238 | builder.show(); 239 | } 240 | }); 241 | } 242 | 243 | List fragments = new ArrayList<>(); 244 | List titles = new ArrayList<>(); 245 | 246 | private void initView() { 247 | getWindow().setBackgroundDrawable(null); 248 | addpage(new AiXiaFragment(), "爱下"); 249 | addpage(new ZhiXuanFragment(), "知轩藏书"); 250 | addpage(new ZhouDuFragment(), "周读"); 251 | addpage(new ShuYuZheFragment(), "书语者"); 252 | addpage(new DongManZhiJiaFragment(), "动漫之家"); 253 | addpage(new M360DFragment(), "360℃"); 254 | addpage(new XiaoShuWuFragment(), "我的小书屋"); 255 | addpage(new QiShuFragment(), "奇书"); 256 | addpage(new BlahFragment(), "blah"); 257 | 258 | ViewPager viewPager = (ViewPager) findViewById(R.id.view_pager); 259 | final TabLayout tabLayout = (TabLayout) findViewById(R.id.tabs); 260 | tabLayout.setupWithViewPager(viewPager); 261 | mPagerAdapter = new PagerAdapter(getSupportFragmentManager(), fragments, titles); 262 | viewPager.setAdapter(mPagerAdapter); 263 | viewPager.setOffscreenPageLimit(fragments.size()); 264 | FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab); 265 | fab.setOnClickListener(new View.OnClickListener() { 266 | @Override 267 | public void onClick(View view) { 268 | searchView.findFocus(); 269 | mPagerAdapter.setTop(tabLayout.getSelectedTabPosition()); 270 | } 271 | }); 272 | 273 | if (PreferenceManager.getDefaultSharedPreferences(this).getBoolean("dark_theme", false)) { 274 | tabLayout.setSelectedTabIndicatorColor(getResources().getColor(R.color.DarkColor)); 275 | tabLayout.setTabTextColors(tabLayout.getTabTextColors().getDefaultColor(), getResources().getColor(R.color.DarkColor)); 276 | } 277 | } 278 | 279 | private void addpage(BaseFragment fragment, String s) { 280 | 281 | if (autoupdate.getBoolean(s, true)) { 282 | fragments.add(fragment); 283 | titles.add(s); 284 | } 285 | } 286 | 287 | @Override 288 | public boolean onOptionsItemSelected(MenuItem item) { 289 | switch (item.getItemId()) { 290 | case R.id.about: 291 | startActivity(new Intent(this, AboutActivity.class)); 292 | break; 293 | case R.id.setting: 294 | startActivity(new Intent(this, SettingsActivity.class)); 295 | break; 296 | case R.id.Theme: 297 | SharedPreferences.Editor meditor = PreferenceManager.getDefaultSharedPreferences(this).edit(); 298 | if (PreferenceManager.getDefaultSharedPreferences(this).getBoolean("dark_theme", false)) 299 | meditor.putBoolean("dark_theme", false); 300 | else 301 | meditor.putBoolean("dark_theme", true); 302 | meditor.apply(); 303 | Intent intent = getIntent(); 304 | 305 | startActivity(intent); 306 | this.overridePendingTransition(R.anim.enter_anim,0); 307 | finish(); 308 | 309 | break; 310 | } 311 | return true; 312 | } 313 | 314 | @Override 315 | public boolean onCreateOptionsMenu(Menu menu) { 316 | getMenuInflater().inflate(R.menu.menu, menu); 317 | 318 | if (PreferenceManager.getDefaultSharedPreferences(this).getBoolean("dark_theme", false)) 319 | menu.findItem(R.id.Theme).setTitle("今夜白"); 320 | final MenuItem searchItem = menu.findItem(R.id.toolbar_search); 321 | searchView = (SearchView) MenuItemCompat.getActionView(searchItem); 322 | MenuItemCompat.getActionView(searchItem); 323 | searchView.setQueryHint("搜索书籍或者作者"); 324 | searchView.setOnSearchClickListener(new View.OnClickListener() { 325 | @Override 326 | public void onClick(View v) { 327 | searchView.setQuery(lastKeyWords, false); 328 | } 329 | }); 330 | 331 | 332 | searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() { 333 | @Override 334 | public boolean onQueryTextSubmit(String query) { 335 | //处理搜索结果 336 | try { 337 | lastKeyWords = query; 338 | Runtime runtime = Runtime.getRuntime(); 339 | runtime.exec("input keyevent " + KeyEvent.KEYCODE_BACK); 340 | runtime.exec("input keyevent " + KeyEvent.KEYCODE_BACK); 341 | setTitle("搜索:" + query); 342 | for (BaseFragment fragment : mPagerAdapter.getFragments()) { 343 | fragment.startSearch(query); 344 | } 345 | } catch (Exception e) { 346 | e.printStackTrace(); 347 | } 348 | return false; 349 | } 350 | 351 | @Override 352 | public boolean onQueryTextChange(String s) { 353 | return false; 354 | } 355 | }); 356 | return super.onCreateOptionsMenu(menu); 357 | } 358 | } 359 | -------------------------------------------------------------------------------- /app/src/main/java/com/delsart/bookdownload/ui/activity/SettingsActivity.java: -------------------------------------------------------------------------------- 1 | package com.delsart.bookdownload.ui.activity; 2 | 3 | 4 | import android.content.Context; 5 | import android.os.Bundle; 6 | import android.preference.PreferenceActivity; 7 | import android.preference.PreferenceManager; 8 | import android.support.annotation.Nullable; 9 | import android.util.AttributeSet; 10 | import android.view.MenuItem; 11 | import android.view.View; 12 | 13 | import com.delsart.bookdownload.R; 14 | 15 | public class SettingsActivity extends PreferenceActivity { 16 | 17 | @Override 18 | public void onCreate(@Nullable Bundle savedInstanceState) { 19 | if (PreferenceManager.getDefaultSharedPreferences(this).getBoolean("dark_theme", false)) 20 | setTheme(R.style.DarkThemeSettingTheme); 21 | else 22 | setTheme(R.style.settingTheme); 23 | super.onCreate(savedInstanceState); 24 | 25 | getActionBar().setDisplayHomeAsUpEnabled(true); 26 | addPreferencesFromResource(R.xml.settinglayout); 27 | } 28 | 29 | 30 | 31 | @Override 32 | public boolean onMenuItemSelected(int featureId, MenuItem item) { 33 | finish(); 34 | return super.onMenuItemSelected(featureId, item); 35 | 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /app/src/main/java/com/delsart/bookdownload/ui/activity/UsedOpenSource.java: -------------------------------------------------------------------------------- 1 | package com.delsart.bookdownload.ui.activity; 2 | 3 | import android.content.Context; 4 | import android.os.Bundle; 5 | import android.preference.PreferenceManager; 6 | import android.support.annotation.NonNull; 7 | import android.support.annotation.Nullable; 8 | import android.support.v4.content.ContextCompat; 9 | import android.view.MenuItem; 10 | 11 | import com.danielstone.materialaboutlibrary.ConvenienceBuilder; 12 | import com.danielstone.materialaboutlibrary.model.MaterialAboutCard; 13 | import com.danielstone.materialaboutlibrary.model.MaterialAboutList; 14 | import com.danielstone.materialaboutlibrary.util.OpenSourceLicense; 15 | import com.delsart.bookdownload.R; 16 | import com.mikepenz.community_material_typeface_library.CommunityMaterial; 17 | import com.mikepenz.iconics.IconicsDrawable; 18 | 19 | /** 20 | * Created by Delsart on 2017/7/24. 21 | */ 22 | 23 | public class UsedOpenSource extends AboutActivity { 24 | @Override 25 | protected void onCreate(@Nullable Bundle savedInstanceState) { 26 | if (PreferenceManager.getDefaultSharedPreferences(this).getBoolean("dark_theme", false)) { 27 | setTheme(R.style.DarkTheme_aboutTheme); 28 | colorIcon = R.color.DarkColor; 29 | } 30 | else 31 | setTheme(R.style.aboutTheme); 32 | super.onCreate(savedInstanceState); 33 | } 34 | @NonNull 35 | @Override 36 | protected MaterialAboutList getMaterialAboutList(@NonNull final Context c) { 37 | MaterialAboutCard materialAboutLIbraryLicenseCard = ConvenienceBuilder.createLicenseCard(c, 38 | new IconicsDrawable(c) 39 | .icon(CommunityMaterial.Icon.cmd_book) 40 | .color(ContextCompat.getColor(c, colorIcon)) 41 | .sizeDp(18), 42 | "material-about-library", "2016", "Daniel Stone", 43 | OpenSourceLicense.APACHE_2); 44 | 45 | MaterialAboutCard androidIconicsLicenseCard = ConvenienceBuilder.createLicenseCard(c, 46 | new IconicsDrawable(c) 47 | .icon(CommunityMaterial.Icon.cmd_book) 48 | .color(ContextCompat.getColor(c, colorIcon)) 49 | .sizeDp(18), 50 | "Android Iconics", "2016", "Mike Penz", 51 | OpenSourceLicense.APACHE_2); 52 | 53 | MaterialAboutCard leakCanaryLicenseCard = ConvenienceBuilder.createLicenseCard(c, 54 | new IconicsDrawable(c) 55 | .icon(CommunityMaterial.Icon.cmd_book) 56 | .color(ContextCompat.getColor(c, colorIcon)) 57 | .sizeDp(18), 58 | "BRVAH", "2016", "陈宇明", 59 | OpenSourceLicense.APACHE_2); 60 | 61 | MaterialAboutCard mitLicenseCard = ConvenienceBuilder.createLicenseCard(c, 62 | new IconicsDrawable(c) 63 | .icon(CommunityMaterial.Icon.cmd_book) 64 | .color(ContextCompat.getColor(c, colorIcon)) 65 | .sizeDp(18), 66 | "Jsoup", "2017", "Jonathan Hedley", 67 | OpenSourceLicense.MIT); 68 | 69 | 70 | 71 | return new MaterialAboutList(materialAboutLIbraryLicenseCard, 72 | androidIconicsLicenseCard, 73 | leakCanaryLicenseCard, 74 | mitLicenseCard); 75 | } 76 | 77 | @Override 78 | protected CharSequence getActivityTitle() { 79 | return "Used-open-sources"; 80 | } 81 | 82 | @Override 83 | public boolean onOptionsItemSelected(MenuItem item) { 84 | switch (item.getItemId()) { 85 | case android.R.id.home: 86 | finish(); 87 | return true; 88 | default: 89 | return false; 90 | } 91 | } 92 | } -------------------------------------------------------------------------------- /app/src/main/java/com/delsart/bookdownload/ui/fragment/AiXiaFragment.java: -------------------------------------------------------------------------------- 1 | package com.delsart.bookdownload.ui.fragment; 2 | 3 | 4 | import android.os.Handler; 5 | 6 | import com.delsart.bookdownload.service.AiXiaService; 7 | import com.delsart.bookdownload.service.BaseService; 8 | 9 | public class AiXiaFragment extends BaseFragment { 10 | 11 | @Override 12 | protected BaseService getService(Handler handler, String keywords) { 13 | return new AiXiaService(handler, keywords); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /app/src/main/java/com/delsart/bookdownload/ui/fragment/BaseFragment.java: -------------------------------------------------------------------------------- 1 | package com.delsart.bookdownload.ui.fragment; 2 | 3 | import android.app.ProgressDialog; 4 | import android.content.DialogInterface; 5 | import android.content.Intent; 6 | import android.net.Uri; 7 | import android.os.Bundle; 8 | import android.os.Handler; 9 | import android.os.Looper; 10 | import android.os.Message; 11 | import android.preference.PreferenceManager; 12 | import android.support.annotation.Nullable; 13 | import android.support.design.widget.Snackbar; 14 | import android.support.v4.app.Fragment; 15 | import android.support.v4.app.NotificationCompatSideChannelService; 16 | import android.support.v4.content.ContextCompat; 17 | import android.support.v7.app.AlertDialog; 18 | import android.support.v7.widget.LinearLayoutManager; 19 | import android.support.v7.widget.RecyclerView; 20 | import android.view.LayoutInflater; 21 | import android.view.View; 22 | import android.view.ViewGroup; 23 | import android.widget.ImageView; 24 | import android.widget.LinearLayout; 25 | import android.widget.TextView; 26 | import android.widget.Toast; 27 | 28 | import com.bumptech.glide.Glide; 29 | import com.chad.library.adapter.base.BaseQuickAdapter; 30 | import com.delsart.bookdownload.MsgType; 31 | import com.delsart.bookdownload.R; 32 | import com.delsart.bookdownload.adapter.MyItemAdapter; 33 | import com.delsart.bookdownload.bean.DownloadBean; 34 | import com.delsart.bookdownload.bean.NovelBean; 35 | import com.delsart.bookdownload.handler.MyHandler; 36 | import com.delsart.bookdownload.handler.OnHandleMessageCallback; 37 | import com.delsart.bookdownload.service.BaseService; 38 | 39 | import java.util.ArrayList; 40 | 41 | public abstract class BaseFragment extends Fragment { 42 | public final MyHandler mHandler = new MyHandler<>(this); 43 | private RecyclerView mRecyclerView; 44 | public MyItemAdapter mAdapter; 45 | public BaseService mService; 46 | public ArrayList mList = new ArrayList<>(); 47 | private ProgressDialog waitingDialog; 48 | public View mNoFoundView; 49 | private View mSearchingView; 50 | 51 | 52 | protected abstract BaseService getService(Handler handler, String keywords); 53 | 54 | @Nullable 55 | @Override 56 | public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 57 | View mNoSearchView = inflater.inflate(R.layout.view_no_search, null, false); 58 | mNoFoundView = inflater.inflate(R.layout.view_no_found, null, false); 59 | mSearchingView = inflater.inflate(R.layout.view_searching, null, false); 60 | View view = LayoutInflater.from(getContext()).inflate(R.layout.recycler_view, container, false); 61 | mRecyclerView = (RecyclerView) view.findViewById(R.id.recycler_view); 62 | 63 | mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL, false)); 64 | if (PreferenceManager.getDefaultSharedPreferences(getContext()) 65 | .getBoolean("dark_theme",false)) 66 | { 67 | mRecyclerView.setBackgroundColor(ContextCompat.getColor(getContext(),R.color.DarkRecyclerViewBackground)); 68 | mAdapter = new MyItemAdapter(ContextCompat.getColor(getContext(),R.color.DarkMainColor)); 69 | }else 70 | mAdapter = new MyItemAdapter(ContextCompat.getColor(getContext(),R.color.DayColor)); 71 | mAdapter.openLoadAnimation(BaseQuickAdapter.SLIDEIN_BOTTOM); 72 | mAdapter.setEmptyView(mNoSearchView); 73 | mRecyclerView.setAdapter(mAdapter); 74 | 75 | 76 | initLoadMore(); 77 | setOnClickEvent(); 78 | initReLoad(); 79 | return view; 80 | } 81 | 82 | 83 | private void initReLoad() { 84 | mNoFoundView.setOnClickListener(new View.OnClickListener() { 85 | @Override 86 | public void onClick(View v) { 87 | mAdapter.setEmptyView(mSearchingView); 88 | mService.reLoad(); 89 | } 90 | }); 91 | } 92 | 93 | public void initLoadMore() { 94 | mAdapter.setOnLoadMoreListener(new BaseQuickAdapter.RequestLoadMoreListener() { 95 | @Override 96 | public void onLoadMoreRequested() { 97 | mService.get(); 98 | } 99 | }, mRecyclerView); 100 | } 101 | 102 | private void setOnClickEvent() { 103 | mAdapter.setOnItemClickListener(new BaseQuickAdapter.OnItemClickListener() { 104 | @Override 105 | public void onItemClick(BaseQuickAdapter adapter, View view, final int position) { 106 | AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); 107 | builder.setTitle("查看"); 108 | View mDialogView = LayoutInflater.from(getContext()).inflate(R.layout.view_dialog, null); 109 | LinearLayout linearLayout = (LinearLayout) mDialogView.findViewById(R.id.droot); 110 | TextView mDialogName = (TextView) linearLayout.getChildAt(0); 111 | ImageView mDialogPic = (ImageView) linearLayout.getChildAt(1); 112 | TextView mDialogInfo = (TextView) linearLayout.getChildAt(2); 113 | mDialogName.setText(mList.get(position).getName()); 114 | mDialogInfo.setText(mList.get(position).getShowText()); 115 | Glide.with(getContext()).load(mList.get(position).getPic()).into(mDialogPic); 116 | mDialogPic.setOnLongClickListener(new View.OnLongClickListener() { 117 | @Override 118 | public boolean onLongClick(View v) { 119 | Toast.makeText(getContext(),"在网页中打开图片",Toast.LENGTH_SHORT).show(); 120 | Uri uri = Uri.parse(mList.get(position).getPic()); 121 | startActivity(new Intent(Intent.ACTION_VIEW, uri)); 122 | return false; 123 | } 124 | }); 125 | builder.setView(mDialogView); 126 | builder.setPositiveButton("下载", new DialogInterface.OnClickListener() { 127 | @Override 128 | public void onClick(DialogInterface dialog, int which) { 129 | waitingDialog = new ProgressDialog(getContext()); 130 | waitingDialog.setTitle("下载"); 131 | waitingDialog.setMessage("获取中..."); 132 | waitingDialog.setIndeterminate(true); 133 | waitingDialog.setCancelable(false); 134 | waitingDialog.show(); 135 | try { 136 | new Thread(new Runnable() { 137 | @Override 138 | public void run() { 139 | try { 140 | doOnClickDownload(mService.getDownloadurls(mList.get(position).getDownloadFromUrl())); 141 | } catch (InterruptedException e) { 142 | e.printStackTrace(); 143 | } 144 | } 145 | }).start(); 146 | } catch (Exception e) { 147 | e.printStackTrace(); 148 | } 149 | } 150 | }); 151 | builder.setNegativeButton("取消", null); 152 | builder.show(); 153 | } 154 | }); 155 | } 156 | 157 | public void doOnClickDownload(final ArrayList urls) { 158 | String[] sList = new String[urls.size()]; 159 | for (int i = 0; i < urls.size(); i++) { 160 | sList[i] = urls.get(i).getType(); 161 | } 162 | AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); 163 | Looper.prepare(); 164 | builder.setTitle("选择下载对象"); 165 | builder.setItems(sList, new DialogInterface.OnClickListener() { 166 | @Override 167 | public void onClick(DialogInterface dialog, int which) { 168 | String url = urls.get(which).getUrl(); 169 | if (!url.equals("")) { 170 | Uri uri = Uri.parse(url); 171 | startActivity(new Intent(Intent.ACTION_VIEW, uri)); 172 | } 173 | } 174 | }); 175 | builder.setPositiveButton("取消", null); 176 | builder.create().show(); 177 | waitingDialog.dismiss(); 178 | Looper.loop(); 179 | } 180 | 181 | 182 | public void startSearch(String keywords) { 183 | mList.clear(); 184 | mAdapter.setNewData(null); 185 | mService = getService(mHandler, keywords); 186 | mAdapter.setEmptyView(mSearchingView); 187 | runService(); 188 | } 189 | 190 | 191 | public void runService() { 192 | mService.get(); 193 | mHandler.setOnHandleMessageCallback(new OnHandleMessageCallback() { 194 | @Override 195 | public void handleMessage(BaseFragment fragment, Message msg) { 196 | switch (msg.what) { 197 | case MsgType.ERROR: 198 | mAdapter.loadMoreFail(); 199 | mAdapter.setEmptyView(mNoFoundView); 200 | break; 201 | case MsgType.SUCCESS: 202 | ArrayList data = (ArrayList) msg.obj; 203 | if (data != null) { 204 | mList.addAll(data); 205 | if (data.size() > 0) { 206 | mAdapter.addData(data); 207 | mAdapter.loadMoreComplete(); 208 | } else { 209 | mAdapter.setEmptyView(mNoFoundView); 210 | mAdapter.loadMoreEnd(); 211 | } 212 | } else { 213 | Snackbar.make(getActivity().findViewById(android.R.id.content), "未知错误", Snackbar.LENGTH_SHORT).show(); 214 | } 215 | break; 216 | } 217 | } 218 | }); 219 | } 220 | 221 | public void toTop() { 222 | mRecyclerView.smoothScrollToPosition(0); 223 | } 224 | } 225 | -------------------------------------------------------------------------------- /app/src/main/java/com/delsart/bookdownload/ui/fragment/BlahFragment.java: -------------------------------------------------------------------------------- 1 | package com.delsart.bookdownload.ui.fragment; 2 | 3 | 4 | import android.os.Handler; 5 | 6 | import com.delsart.bookdownload.service.BaseService; 7 | import com.delsart.bookdownload.service.BlahService; 8 | 9 | public class BlahFragment extends BaseFragment { 10 | 11 | @Override 12 | protected BaseService getService(Handler handler, String keywords) { 13 | return new BlahService(handler, keywords); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /app/src/main/java/com/delsart/bookdownload/ui/fragment/DongManZhiJiaFragment.java: -------------------------------------------------------------------------------- 1 | package com.delsart.bookdownload.ui.fragment; 2 | 3 | 4 | import android.os.Handler; 5 | import android.os.Message; 6 | import android.support.design.widget.Snackbar; 7 | 8 | import com.chad.library.adapter.base.BaseQuickAdapter; 9 | import com.delsart.bookdownload.MsgType; 10 | import com.delsart.bookdownload.bean.NovelBean; 11 | import com.delsart.bookdownload.handler.OnHandleMessageCallback; 12 | import com.delsart.bookdownload.service.BaseService; 13 | import com.delsart.bookdownload.service.DongManZhiJiaService; 14 | import com.delsart.bookdownload.service.ZhouDuService; 15 | 16 | import java.util.ArrayList; 17 | 18 | public class DongManZhiJiaFragment extends BaseFragment { 19 | 20 | @Override 21 | protected BaseService getService(Handler handler, String keywords) { 22 | return new DongManZhiJiaService(handler, keywords); 23 | } 24 | 25 | @Override 26 | public void runService() { 27 | mService.get(); 28 | mHandler.setOnHandleMessageCallback(new OnHandleMessageCallback() { 29 | @Override 30 | public void handleMessage(BaseFragment fragment, Message msg) { 31 | switch (msg.what) { 32 | case MsgType.ERROR: 33 | mAdapter.loadMoreFail(); 34 | mAdapter.setEmptyView(mNoFoundView); 35 | break; 36 | case MsgType.SUCCESS: 37 | ArrayList data = (ArrayList) msg.obj; 38 | if (data != null) { 39 | mList.addAll(data); 40 | if (data.size() > 0) { 41 | mAdapter.addData(data); 42 | mAdapter.loadMoreEnd(); 43 | } else { 44 | mAdapter.setEmptyView(mNoFoundView); 45 | mAdapter.loadMoreEnd(); 46 | } 47 | } else { 48 | Snackbar.make(getActivity().findViewById(android.R.id.content), "未知错误", Snackbar.LENGTH_SHORT).show(); 49 | } 50 | break; 51 | } 52 | } 53 | }); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /app/src/main/java/com/delsart/bookdownload/ui/fragment/M360DFragment.java: -------------------------------------------------------------------------------- 1 | package com.delsart.bookdownload.ui.fragment; 2 | 3 | 4 | import android.os.Handler; 5 | 6 | import com.delsart.bookdownload.service.BaseService; 7 | import com.delsart.bookdownload.service.M360DService; 8 | 9 | public class M360DFragment extends BaseFragment { 10 | 11 | @Override 12 | protected BaseService getService(Handler handler, String keywords) { 13 | return new M360DService(handler, keywords); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /app/src/main/java/com/delsart/bookdownload/ui/fragment/QiShuFragment.java: -------------------------------------------------------------------------------- 1 | package com.delsart.bookdownload.ui.fragment; 2 | 3 | 4 | import android.os.Handler; 5 | 6 | import com.delsart.bookdownload.service.BaseService; 7 | import com.delsart.bookdownload.service.QiShuService; 8 | 9 | public class QiShuFragment extends BaseFragment { 10 | 11 | @Override 12 | protected BaseService getService(Handler handler, String keywords) { 13 | return new QiShuService(handler, keywords); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /app/src/main/java/com/delsart/bookdownload/ui/fragment/ShuYuZheFragment.java: -------------------------------------------------------------------------------- 1 | package com.delsart.bookdownload.ui.fragment; 2 | 3 | 4 | import android.os.Handler; 5 | 6 | import com.delsart.bookdownload.service.BaseService; 7 | import com.delsart.bookdownload.service.ShuYuZheService; 8 | 9 | public class ShuYuZheFragment extends BaseFragment { 10 | 11 | @Override 12 | protected BaseService getService(Handler handler, String keywords) { 13 | return new ShuYuZheService(handler, keywords); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /app/src/main/java/com/delsart/bookdownload/ui/fragment/XiaoShuWuFragment.java: -------------------------------------------------------------------------------- 1 | package com.delsart.bookdownload.ui.fragment; 2 | 3 | 4 | import android.os.Handler; 5 | 6 | import com.delsart.bookdownload.service.BaseService; 7 | import com.delsart.bookdownload.service.XiaoShuWuService; 8 | 9 | public class XiaoShuWuFragment extends BaseFragment { 10 | 11 | @Override 12 | protected BaseService getService(Handler handler, String keywords) { 13 | return new XiaoShuWuService(handler, keywords); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /app/src/main/java/com/delsart/bookdownload/ui/fragment/ZhiXuanFragment.java: -------------------------------------------------------------------------------- 1 | package com.delsart.bookdownload.ui.fragment; 2 | 3 | 4 | import android.os.Handler; 5 | 6 | import com.delsart.bookdownload.service.BaseService; 7 | import com.delsart.bookdownload.service.ZhiXuanService; 8 | 9 | public class ZhiXuanFragment extends BaseFragment { 10 | 11 | @Override 12 | protected BaseService getService(Handler handler, String keywords) { 13 | return new ZhiXuanService(handler, keywords); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /app/src/main/java/com/delsart/bookdownload/ui/fragment/ZhouDuFragment.java: -------------------------------------------------------------------------------- 1 | package com.delsart.bookdownload.ui.fragment; 2 | 3 | 4 | import android.os.Handler; 5 | 6 | import com.delsart.bookdownload.service.BaseService; 7 | import com.delsart.bookdownload.service.ZhouDuService; 8 | 9 | public class ZhouDuFragment extends BaseFragment { 10 | 11 | @Override 12 | protected BaseService getService(Handler handler, String keywords) { 13 | return new ZhouDuService(handler, keywords); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /app/src/main/java/com/delsart/bookdownload/utils/StatusBarUtils.java: -------------------------------------------------------------------------------- 1 | package com.delsart.bookdownload.utils; 2 | 3 | import android.app.Activity; 4 | import android.os.Build; 5 | import android.view.View; 6 | import android.view.Window; 7 | 8 | import java.lang.reflect.Field; 9 | import java.lang.reflect.Method; 10 | 11 | 12 | public class StatusBarUtils { 13 | public static boolean MIUISetStatusBarLightMode(Activity activity, boolean dark) { 14 | boolean result = false; 15 | Window window = activity.getWindow(); 16 | if (window != null) { 17 | Class clazz = window.getClass(); 18 | try { 19 | int darkModeFlag = 0; 20 | Class layoutParams = Class.forName("android.view.MiuiWindowManager$LayoutParams"); 21 | Field field = layoutParams.getField("EXTRA_FLAG_STATUS_BAR_DARK_MODE"); 22 | darkModeFlag = field.getInt(layoutParams); 23 | Method extraFlagField = clazz.getMethod("setExtraFlags", int.class, int.class); 24 | if (dark) { 25 | extraFlagField.invoke(window, darkModeFlag, darkModeFlag);//状态栏透明且黑色字体 26 | } else { 27 | extraFlagField.invoke(window, 0, darkModeFlag);//清除黑色字体 28 | } 29 | result = true; 30 | 31 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 32 | //开发版 7.7.13 及以后版本采用了系统API,旧方法无效但不会报错,所以两个方式都要加上 33 | if (dark) { 34 | activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR); 35 | } else { 36 | activity.getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE); 37 | } 38 | } 39 | } catch (Exception ignored) { 40 | } 41 | } 42 | return result; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /app/src/main/res/anim/enter_anim.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 12 | 13 | 20 | 21 | 30 | 31 | 32 | 37 | 38 | 47 | 48 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_custom.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 21 | 22 | 29 | 30 | 37 | 38 | 39 | 40 | 53 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_list.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 20 | 21 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /app/src/main/res/layout/recycler_view.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/layout/view_dialog.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 14 | 15 | 16 | 21 | 22 | 28 | 29 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /app/src/main/res/layout/view_no_found.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 16 | 17 | -------------------------------------------------------------------------------- /app/src/main/res/layout/view_no_search.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 16 | -------------------------------------------------------------------------------- /app/src/main/res/layout/view_searching.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 13 | 14 | 19 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 11 | 15 | 19 | 23 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Delsart/Bookster/dead2122e3456e910a13dc7c906282cc83f0c594/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Delsart/Bookster/dead2122e3456e910a13dc7c906282cc83f0c594/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_to_top.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Delsart/Bookster/dead2122e3456e910a13dc7c906282cc83f0c594/app/src/main/res/mipmap-xhdpi/ic_to_top.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Delsart/Bookster/dead2122e3456e910a13dc7c906282cc83f0c594/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Delsart/Bookster/dead2122e3456e910a13dc7c906282cc83f0c594/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Delsart/Bookster/dead2122e3456e910a13dc7c906282cc83f0c594/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Delsart/Bookster/dead2122e3456e910a13dc7c906282cc83f0c594/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_no_found.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Delsart/Bookster/dead2122e3456e910a13dc7c906282cc83f0c594/app/src/main/res/mipmap-xxxhdpi/ic_no_found.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_no_search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Delsart/Bookster/dead2122e3456e910a13dc7c906282cc83f0c594/app/src/main/res/mipmap-xxxhdpi/ic_no_search.png -------------------------------------------------------------------------------- /app/src/main/res/values-v23/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 15 | 23 | 24 | 25 | 26 | 34 | 35 | 42 | 43 | 44 | 45 | 53 | 61 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | @color/accent_material_light 6 | #ffffff 7 | #608cb1 8 | #2c2c2c 9 | #202020 10 | #4C708E 11 | #00000000 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 16dp 3 | 16dp 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | Bookster 3 | 请进行搜索 4 | 本软件只提供搜索服务,不储存任何网络资源。所得任何结果不代表本应用立场。\n\n本软件完全免费,所有数据均来源网络,请勿用作非法用途,如果侵害了你的权益,请联系我尽快删除。\n\n如果可以,请点击来源网页中的广告来支持来源网站做下去 5 | 设置 6 | 到目前为止,用的还算称心吗?\n\n在这里恳请您为这个应用评个5星。\n\n此外开发者在这个应用上花费了大量的心血和时间,希望您能够小小的支持一下。 7 | 没有找到搜索条目\n点击重试,或尝试其他来源 8 | 正在搜索… 9 | Search 10 | 设置 11 | 关于 12 | 深空黑 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 12 | 18 | 19 | 20 | 21 | 22 | 28 | 29 | 35 | 36 | 37 | 38 | 39 | 40 | 46 | 51 | 52 | 53 | 54 | 60 | 61 | 65 | 69 | 70 | -------------------------------------------------------------------------------- /app/src/main/res/xml/settinglayout.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 12 | 16 | 20 | 24 | 28 | 32 | 36 | 40 | 44 | 48 | 49 | -------------------------------------------------------------------------------- /app/src/test/java/com/delsart/bookdownload/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.delsart.bookdownload; 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 | maven { url 'http://maven.aliyun.com/nexus/content/groups/public/' } 6 | jcenter() 7 | mavenCentral() 8 | maven { url "https://jitpack.io" } 9 | maven { url = 'https://dl.bintray.com/yuancloud/maven/' } 10 | } 11 | dependencies { 12 | classpath 'com.android.tools.build:gradle:2.3.3' 13 | 14 | // NOTE: Do not place your application dependencies here; they belong 15 | // in the individual module build.gradle files 16 | } 17 | } 18 | 19 | allprojects { 20 | repositories { 21 | maven { url 'http://maven.aliyun.com/nexus/content/groups/public/' } 22 | jcenter() 23 | mavenCentral() 24 | maven { url "https://jitpack.io" } 25 | maven { url = 'https://dl.bintray.com/yuancloud/maven/' } 26 | } 27 | } 28 | 29 | task clean(type: Delete) { 30 | delete rootProject.buildDir 31 | } 32 | -------------------------------------------------------------------------------- /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 18 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Delsart/Bookster/dead2122e3456e910a13dc7c906282cc83f0c594/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri Jul 21 23:53:24 CST 2017 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-3.3-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' 2 | -------------------------------------------------------------------------------- /更新日志.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Delsart/Bookster/dead2122e3456e910a13dc7c906282cc83f0c594/更新日志.txt --------------------------------------------------------------------------------