├── .idea ├── copyright │ └── profiles_settings.xml └── dictionaries │ └── Administrator.xml ├── README.md ├── app ├── .gitignore ├── app.iml ├── bugly │ ├── BuglySymtabLog.txt │ └── BuglyUploadLog.txt ├── build.gradle ├── proguard-rules.pro ├── release │ ├── output.json │ └── 修改单词导出.apk └── src │ ├── androidTest │ └── java │ │ └── cn │ │ └── jk │ │ └── kaoyandanci │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── assets │ │ ├── databases │ │ │ ├── word.db │ │ │ ├── word.db_upgrade_2-3.sql │ │ │ └── word.db_upgrade_3-4.sql │ │ └── question.json │ ├── java │ │ └── cn │ │ │ └── jk │ │ │ └── kaoyandanci │ │ │ ├── InitApplication.java │ │ │ ├── model │ │ │ ├── AutoReviewWordList.java │ │ │ ├── CommonQuestion.java │ │ │ ├── DayReviewWordList.java │ │ │ ├── DefaultWordList.java │ │ │ ├── LearnWordList.java │ │ │ ├── Queries.java │ │ │ ├── QueryCondition.java │ │ │ ├── Word.java │ │ │ ├── WordList.java │ │ │ └── WordState.java │ │ │ ├── ui │ │ │ ├── activity │ │ │ │ ├── AboutActivity.java │ │ │ │ ├── AdvanceSettingActivity.java │ │ │ │ ├── BaseActivity.java │ │ │ │ ├── BaseWordListActivity.java │ │ │ │ ├── CommonQuestionActivity.java │ │ │ │ ├── DisplaySettingActivity.java │ │ │ │ ├── DonateActivity.java │ │ │ │ ├── EmptyActivity.java │ │ │ │ ├── FeedbackActivity.java │ │ │ │ ├── IntroActivity.java │ │ │ │ ├── LearnWordActivity.java │ │ │ │ ├── MainActivity.java │ │ │ │ ├── MyWordListActivity.java │ │ │ │ ├── SearchWordActivity.java │ │ │ │ ├── SolutionActivity.java │ │ │ │ ├── WordDetailActivity.java │ │ │ │ ├── WordListActivity.java │ │ │ │ └── YoudaoWordActivity.java │ │ │ ├── adapter │ │ │ │ ├── QuestionAdapter.java │ │ │ │ └── WordListAdapter.java │ │ │ ├── dialog │ │ │ │ ├── AddWordDialog.java │ │ │ │ ├── ChoosePlanDialog.java │ │ │ │ ├── DownloadDialog.java │ │ │ │ ├── NeverShowWordDialog.java │ │ │ │ ├── PleaseDonateDialog.java │ │ │ │ └── WebSearchTipDialog.java │ │ │ ├── fragment │ │ │ │ ├── AdvanceSettingFragment.java │ │ │ │ ├── HomeFragment.java │ │ │ │ ├── Intro1Fragment.java │ │ │ │ ├── Intro2Fragment.java │ │ │ │ ├── Intro3Fragment.java │ │ │ │ ├── ReviewFragment.java │ │ │ │ └── SettingFragment.java │ │ │ └── preference │ │ │ │ ├── ColorPickerPreference.java │ │ │ │ └── DatePreference.java │ │ │ └── util │ │ │ ├── AssetsUtil.java │ │ │ ├── ChineseCheck.java │ │ │ ├── ColorUtil.java │ │ │ ├── Config.java │ │ │ ├── Constant.java │ │ │ ├── DateLongGson.java │ │ │ ├── DayUtil.java │ │ │ ├── EmptyNetListener.java │ │ │ ├── FileUtil.java │ │ │ ├── JsonReader.java │ │ │ ├── MD5.java │ │ │ ├── MediaFileNameGenerator.java │ │ │ ├── MediaUtil.java │ │ │ ├── NetWorkSingleton.java │ │ │ ├── NetWorkUtil.java │ │ │ ├── OnSwipeTouchListener.java │ │ │ ├── SPUtil.java │ │ │ ├── ShadowImageView.java │ │ │ ├── TencentCloudService.java │ │ │ ├── ToastUtil.java │ │ │ └── WordDatabase.java │ └── res │ │ ├── drawable-night-xxhdpi │ │ └── ic_volume.png │ │ ├── drawable-xxhdpi │ │ ├── app_icon.png │ │ ├── blue_star.xml │ │ ├── donate_alipay.png │ │ ├── donate_weixin.png │ │ ├── ic_delete_blue_24dp.xml │ │ ├── ic_home_black_24dp.xml │ │ ├── ic_keyboard_arrow_right_black_24dp.png │ │ ├── ic_rate_review_black_24dp.png │ │ ├── ic_settings_black_24dp.png │ │ ├── ic_volume.png │ │ ├── intro_back1.png │ │ ├── intro_back2.png │ │ └── intro_back3.jpg │ │ ├── drawable │ │ ├── empty.png │ │ ├── ic_add.xml │ │ ├── ic_delete_black_24dp.xml │ │ ├── ic_restore_black_24dp.xml │ │ ├── ic_search_black_24dp.xml │ │ ├── ic_star_border_blue_24dp.xml │ │ └── star.xml │ │ ├── into_back2.jpg │ │ ├── layout │ │ ├── activity_about.xml │ │ ├── activity_advance_setting.xml │ │ ├── activity_common_question.xml │ │ ├── activity_display_setting.xml │ │ ├── activity_donate.xml │ │ ├── activity_feedback.xml │ │ ├── activity_learn_word.xml │ │ ├── activity_main.xml │ │ ├── activity_my_word_list.xml │ │ ├── activity_search_word.xml │ │ ├── activity_solution.xml │ │ ├── activity_word_detail.xml │ │ ├── activity_word_list.xml │ │ ├── activity_youdao_word.xml │ │ ├── ate_preference_custom.xml │ │ ├── ate_preference_widget.xml │ │ ├── content_my_word_list.xml │ │ ├── dialog_add_word.xml │ │ ├── dialog_plan_learn.xml │ │ ├── fragment_advance_setting.xml │ │ ├── fragment_home.xml │ │ ├── fragment_intro1.xml │ │ ├── fragment_intro2.xml │ │ ├── fragment_intro3.xml │ │ ├── fragment_review.xml │ │ ├── layout_question.xml │ │ └── layout_word_brief.xml │ │ ├── menu │ │ ├── main_navigation.xml │ │ ├── menu_learn_word.xml │ │ ├── menu_main.xml │ │ ├── menu_my_word_list.xml │ │ ├── menu_word_list.xml │ │ ├── menu_word_web_page.xml │ │ └── search_word_menu.xml │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── values │ │ ├── arrays.xml │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ │ └── xml │ │ ├── advance_setting.xml │ │ ├── display_setting.xml │ │ ├── network_security_config.xml │ │ └── setting.xml │ └── test │ └── java │ └── cn │ └── jk │ └── kaoyandanci │ └── ExampleUnitTest.java ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/dictionaries/Administrator.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | alipay 5 | guid 6 | kaoyandanci 7 | kydc 8 | weixin 9 | 10 | 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 老旧的火把 - 考研单词 2 | =========================================== 3 | Copyright (C) 2019 火把工作室. 4 | 5 | ## 介绍 6 | 考研单词是一个用来记忆考研大纲单词的app,做这个app的初衷是为了背诵考研大纲中单词,但当时比较了应用市场中的单词app.并没有一个界面简介,无付费项,无广告,且词库准确的app.于是就做了一个这样的app.并把它传到了各个应用市场. 7 | 没想到竟然还有人用.并提出了很多建设性的建议.于是就这样一版一般的完善了起来. 8 | ## 特色 9 | 1. 符合md设计. 10 | 2. apk仅4mb(包括一个大约0.7mb的db). 11 | 3. 界面简介.无广告.不推送. 12 | 4. 多种学习模式供用户选择. 13 | ## 下载地址 14 | 下载地址:[点击这里](https://www.coolapk.com/apk/cn.jk.kaoyandanci) 15 | ## todo 16 | - [X] 加入去除简单词功能. 17 | - [X] 根据 *认识* *不认识* 进行复习. 18 | - [X] 修复已经发现的bug.学习计划中的单词总数不根据学习模式变化,有个字符串数组越界的bug. 19 | - [X] 加入生词本. 20 | ## 第三方库 21 | Project | Introduction 22 | -------- | ------ 23 | [butterknife](https://github.com/JakeWharton/butterknife) | 提供view绑定 24 | [aesthetic](https://github.com/afollestad/aesthetic) | 一个强大的主题切换库 25 | [MPAndroidChart](https://github.com/PhilJay/MPAndroidChart) | 图表绘制 26 | [green dao ](https://github.com/greenrobot/greenDAO) | orm 库 27 | [sqliteassethelper](https://github.com/jgilfelt/android-sqlite-asset-helper) | 便捷的升级和管理数据库 28 | [appintro](https://github.com/apl-devs/AppIntro) | 快速制作app引导页 29 | [AndroidVideoCache](https://github.com/danikula/AndroidVideoCache) | 提供发音缓存 30 | [bugly](https://bugly.qq.com/v2/index) |提供崩溃统计. 31 | ## 感谢 32 | 感谢每一个捐赠或鼓励我的人 /比心. 33 | 截至目前已经是一个相对完善的工具类应用了. 34 | 估计代码不会再更新了,由于是很久之前写的代码,整体的逻辑并没有那么好. 35 | 不过功能还是很好用的. 36 | 比心 ♥ 37 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/bugly/BuglySymtabLog.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HIjack2015/KaoYanDanci/4fe402844f173d92e4e49365a458b983b5b97490/app/bugly/BuglySymtabLog.txt -------------------------------------------------------------------------------- /app/bugly/BuglyUploadLog.txt: -------------------------------------------------------------------------------- 1 | file=D:\project\demo\KaoYanDanci\app\build\outputs\mapping\release\mapping.txt 2 | sha1=d981cf139a0367b7311dcc830a1ef71aa964c187 3 | appId=11cc1a2754 4 | 5 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | jcenter() 4 | mavenCentral() 5 | google() 6 | 7 | } 8 | 9 | dependencies { 10 | classpath 'com.android.tools.build:gradle:3.0.1' 11 | classpath 'org.greenrobot:greendao-gradle-plugin:3.2.2' 12 | } 13 | } 14 | 15 | // In your app projects build.gradle file: 16 | 17 | apply plugin: 'com.android.application' 18 | apply plugin: 'org.greenrobot.greendao' // apply plugin 19 | apply plugin: 'bugly' 20 | 21 | bugly { 22 | appId = '11cc1a2754' // 注册时分配的App ID 23 | appKey = 'e25c40c6-1024-40c2-9ba5-cc56a1869bcf' // 注册时分配的App Key 24 | } 25 | android { 26 | compileSdkVersion target_sdk_version 27 | defaultConfig { 28 | applicationId "cn.jk.kaoyandanci" 29 | minSdkVersion min_sdk_version 30 | targetSdkVersion target_sdk_version 31 | versionCode version_code 32 | versionName version_name 33 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 34 | } 35 | sourceSets { 36 | main { 37 | java.srcDirs = ['src/main/java', 'src/main/java-gen'] 38 | } 39 | } 40 | 41 | buildTypes { 42 | //开发调试的时候有效 43 | debug { 44 | // 显示Log 45 | buildConfigField "boolean", "LOG_DEBUG", "true" 46 | minifyEnabled false 47 | zipAlignEnabled false 48 | shrinkResources false 49 | debuggable true 50 | } 51 | //打包的时候使用 52 | release { 53 | // 不显示Log 54 | buildConfigField "boolean", "LOG_DEBUG", "false" 55 | //混淆 56 | minifyEnabled true 57 | //Zipalign优化 58 | zipAlignEnabled true 59 | // 移除无用的resource文件 60 | shrinkResources true 61 | //加载混淆配置文件 62 | //proguard-android.txt为默认的混淆文件 63 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 64 | debuggable true 65 | 66 | } 67 | } 68 | productFlavors { 69 | } 70 | } 71 | greendao { 72 | schemaVersion 4 73 | } 74 | configurations.all { 75 | resolutionStrategy { 76 | force "com.android.support:support-v4:$support_version" 77 | force "com.android.support:support-v13:$support_version" 78 | } 79 | } 80 | dependencies { 81 | compile fileTree(include: ['*.jar'], dir: 'libs') 82 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { 83 | exclude group: 'com.android.support', module: 'support-annotations' 84 | }) 85 | repositories { 86 | maven { 87 | url 'https://maven.google.com' 88 | } 89 | } 90 | //数据库 91 | //view兼容 92 | //json解析 93 | //view注入 94 | //图表支持 95 | //音频缓存//当前没用 96 | //功能介绍页面 97 | implementation "com.android.support:multidex:1.0.3" 98 | implementation "com.tencent.bugly:crashreport:2.6.5" 99 | implementation "com.google.code.gson:gson:2.8.0" 100 | implementation "org.greenrobot:greendao:3.2.2" 101 | implementation "com.readystatesoftware.sqliteasset:sqliteassethelper:2.0.1" 102 | implementation "com.android.support:cardview-v7:$support_version" 103 | implementation "com.android.support:appcompat-v7:$support_version" 104 | implementation "com.android.support:design:$support_version" 105 | implementation "com.android.support.constraint:constraint-layout:1.0.2" 106 | implementation "com.android.support:support-v4:$support_version" 107 | implementation "com.jakewharton:butterknife:8.5.1" 108 | implementation "com.github.PhilJay:MPAndroidChart:v3.0.2" 109 | implementation "com.github.apl-devs:appintro:v4.2.0" 110 | implementation 'com.afollestad.material-dialogs:core:0.9.6.0' 111 | implementation 'com.afollestad.material-dialogs:commons:0.9.6.0' 112 | compile "com.afollestad:aesthetic:0.4.7" 113 | compile "com.danikula:videocache:2.7.0" 114 | compile "com.android.volley:volley:1.1.0" 115 | compile 'com.tencent.qcloud:cosxml:5.4.4' 116 | compile "com.github.prolificinteractive:material-calendarview:1.6.0" 117 | implementation "com.github.hotchemi:permissionsdispatcher:3.3.1" 118 | annotationProcessor "com.github.hotchemi:permissionsdispatcher-processor:3.3.1" 119 | testCompile "junit:junit:4.12" 120 | testCompile "org.json:json:20140107" 121 | testCompile "com.google.code.gson:gson:2.8.0" 122 | annotationProcessor "com.jakewharton:butterknife-compiler:8.5.1" 123 | } 124 | uploadArchives.enabled = false -------------------------------------------------------------------------------- /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 E:\SDK\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 | -dontskipnonpubliclibraryclasses # 不忽略非公共的库类 19 | -optimizationpasses 5 # 指定代码的压缩级别 20 | -dontusemixedcaseclassnames # 是否使用大小写混合 21 | -dontpreverify # 混淆时是否做预校验 22 | -verbose # 混淆时是否记录日志 23 | -keepattributes *Annotation* # 保持注解 24 | -dontoptimize # 优化不优化输入的类文件 25 | -dontwarn 26 | -optimizations !code/simplification/arithmetic,!field/*,!class/merging/* # 混淆时所采用的算法 27 | -dontwarn okio.** 28 | #保持哪些类不被混淆 29 | -keep public class * extends android.app.Activity 30 | -keep public class * extends android.app.Application 31 | -keep public class * extends android.app.Service 32 | -keep public class * extends android.content.BroadcastReceiver 33 | -keep public class * extends android.content.ContentProvider 34 | -keep public class * extends android.app.backup.BackupAgentHelper 35 | -keep public class * extends android.preference.Preference 36 | -keep public class com.android.vending.licensing.ILicensingService 37 | -keep public class * extends android.app.Fragment 38 | 39 | -keep class android.support.v4.app.** { *; } 40 | -keep interface android.support.v4.app.** { *; } 41 | -keep class android.support.v7.widget.SearchView { *; } 42 | -keepattributes *Annotation* 43 | -keep class com.squareup.** { *; } 44 | -keep class permissions.dispatcher.** { *; } 45 | #如果有引用v4包可以添加下面这行 46 | -keep public class * extends android.support.v4.app.Fragment 47 | 48 | #生成日志数据,gradle build时在本项目根目录输出 49 | -dump class_files.txt #apk包内所有class的内部结构 50 | -printseeds seeds.txt #未混淆的类和成员 51 | -printusage unused.txt #打印未被使用的代码 52 | -printmapping mapping.txt #混淆前后的映射 53 | 54 | 55 | #加上之后才可以进行调试 56 | #-renamesourcefileattribute SourceFile 57 | #-keepattributes SourceFile,LineNumberTable 58 | 59 | -keep public class * extends android.support.** #如果有引用v4或者v7包,需添加 60 | -keep class com.xxx.**{*;} #不混淆某个包内的所有文件 61 | -keepclassmembers class * extends org.greenrobot.greendao.AbstractDao { 62 | public static java.lang.String TABLENAME; 63 | } 64 | -keep class **$Properties 65 | 66 | -keep class cn.jk.kaoyandanci.model.*{ *; } 67 | ### greenDAO 3 68 | -keepclassmembers class * extends org.greenrobot.greendao.AbstractDao { 69 | public static java.lang.String TABLENAME; 70 | } 71 | -keep class **$Properties 72 | 73 | # If you do not use SQLCipher: 74 | -dontwarn org.greenrobot.greendao.database.** 75 | # If you do not use RxJava: 76 | -dontwarn rx.** 77 | -dontwarn com.** 78 | -dontwarn permissions.** 79 | -dontwarn kotlin.** 80 | ### greenDAO 2 81 | -keepclassmembers class * extends de.greenrobot.dao.AbstractDao { 82 | public static java.lang.String TABLENAME; 83 | } 84 | -keep class **$Properties 85 | 86 | -dontwarn com.xxx** #忽略某个包的警告 87 | -keepattributes Signature #不混淆泛型 88 | -keepnames class * implements java.io.Serializable #不混淆Serializable 89 | 90 | -keepclassmembers class **.R$* { #不混淆资源类 91 | public static ; 92 | } 93 | -keepclasseswithmembernames class * { # 保持 native 方法不被混淆 94 | native ; 95 | } 96 | -keepclasseswithmembers class * { # 保持自定义控件类不被混淆 97 | public (android.content.Context, android.util.AttributeSet); 98 | } 99 | -keepclasseswithmembers class * { # 保持自定义控件类不被混淆 100 | public (android.content.Context, android.util.AttributeSet, int); 101 | } 102 | -keepclassmembers class * extends android.app.Activity { # 保持自定义控件类不被混淆 103 | public void *(android.view.View); 104 | } 105 | -keepclassmembers enum * { # 保持枚举 enum 类不被混淆 106 | public static **[] values(); 107 | public static ** valueOf(java.lang.String); 108 | } 109 | -keep class * implements android.os.Parcelable { # 保持 Parcelable 不被混淆 110 | public static final android.os.Parcelable$Creator *; 111 | } 112 | -dontwarn com.tencent.bugly.** #不混淆bugly 113 | -keep public class com.tencent.bugly.**{*;} 114 | -dontwarn rx.** 115 | -renamesourcefileattribute SourceFile # 保持行号 116 | -keepattributes SourceFile,LineNumberTable 117 | -dontwarn * -------------------------------------------------------------------------------- /app/release/output.json: -------------------------------------------------------------------------------- 1 | [{"outputType":{"type":"APK"},"apkInfo":{"type":"MAIN","splits":[],"versionCode":9},"path":"app-release.apk","properties":{"packageId":"cn.jk.kaoyandanci","split":"","minSdkVersion":"16"}}] -------------------------------------------------------------------------------- /app/release/修改单词导出.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HIjack2015/KaoYanDanci/4fe402844f173d92e4e49365a458b983b5b97490/app/release/修改单词导出.apk -------------------------------------------------------------------------------- /app/src/androidTest/java/cn/jk/kaoyandanci/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package cn.jk.kaoyandanci; 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.assertEquals; 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("cn.jk.kaoyandanci", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /app/src/main/assets/databases/word.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HIjack2015/KaoYanDanci/4fe402844f173d92e4e49365a458b983b5b97490/app/src/main/assets/databases/word.db -------------------------------------------------------------------------------- /app/src/main/assets/question.json: -------------------------------------------------------------------------------- 1 | [ 2 | 3 | { 4 | "question": "我想背其他单词怎么办\n比如说托福,雅思,四六级之类的?", 5 | "solution": "打开如下网址https://www.coolapk.com/apk/240082,安装背单词,里边有各种各样的词库哦~" 6 | }, 7 | { 8 | "question": "倒计时对不对?", 9 | "solution": "我的计算方法为寻找当年的12月29日之前的最后一个周六,那天就是开考时间,如果和官方公布的不一致.可以在高级设置中手动调节." 10 | }, 11 | { 12 | "question": "简单词来源?", 13 | "solution": "在用户学习时偷偷收集用户第一遍学习就设为掌握的单词.当有几个用户同时认为这个单词简单时就将这个单词认定为简单词.此外.季节,月份,星期,数字...都是简单词(找这些词真的很累...)" 14 | }, 15 | { 16 | "question": "核心单词来源?", 17 | "solution": "新东方bbs论坛一份http://bbs.koolearn.com/t-5130720-1-1.html,扇贝单词一份https://www.shanbay.com/wordbook/115978.两份混在一起,去掉不在考研大纲内的单词." 18 | }, 19 | { 20 | "question": "代码开源吗?", 21 | "solution": "在 github 搜 kaoyandanci即可, 求star /星星眼." 22 | }, 23 | { 24 | "question": "为什么首页的饼图比例不太对?", 25 | "solution": "由于词汇量开始时过低,饼图难以绘制,等单词量过了500就好啦!" 26 | }, 27 | { 28 | "question": "单词总数不足5500?", 29 | "solution": "您是不是在高级设置中去除了简单词或者开启了核心模式?" 30 | }, 31 | { 32 | "question": "如何自动发音?", 33 | "solution": "你看见学习单词右上角那三个竖着的小点没...?" 34 | }, 35 | { 36 | "question": "单词来源是哪里?", 37 | "solution": "来源于2019年考研大纲.这几年考研大纲的单词都没变过,您要是放心不过也可以手动搜几十个考研大纲里边的单词,我想应该是没变化的." 38 | }, 39 | { 40 | "question": "如何进行反馈?", 41 | "solution": "1.应用商店下反馈. 2.设置-关于-意见反馈" 42 | }, 43 | { 44 | "question": "何为智能复习?如何进入?", 45 | "solution": "长按复习界面的开始复习按钮可进入智能复习.\n根据艾宾浩斯遗忘曲线,选出以下时间段内学过的单词,即当前时间往前:3-8分钟,20-40分钟,10-14小时,22-26小时,24*2-24*3小时,(24*6)-(24*7)小时,(24*14)-(24*15)小时.\nps:智能复习请尽可能一次完成,中途退出不保存进度,因为每个时间点产生的单词列表是不同的.没法保存进度.\nps:另一种记忆方法super memo 算法我写了很久,没能写出来,对不起我太菜了. " 46 | }, 47 | 48 | { 49 | "question": "学习或者复习时误触了掌握按钮怎么办?", 50 | "solution": "在单词卡片上左划可以看到上一个单词.点击单词卡片右下角的取消掌握就好了." 51 | }, 52 | { 53 | "question": "提示已经下载语音包,但仍不能离线发音", 54 | "solution": "删除内存卡中/Android/data/cn.jk.kaoyandanci文件夹重新下载,耐心等待解压完成即可." 55 | }, 56 | { 57 | "question": "开发者最近过得怎么样?", 58 | "solution": "走不到的远方,看不见的未来 :<" 59 | } 60 | ] 61 | -------------------------------------------------------------------------------- /app/src/main/java/cn/jk/kaoyandanci/InitApplication.java: -------------------------------------------------------------------------------- 1 | package cn.jk.kaoyandanci; 2 | 3 | import android.Manifest; 4 | import android.app.Application; 5 | import android.content.Context; 6 | import android.database.sqlite.SQLiteDatabase; 7 | import android.support.multidex.MultiDexApplication; 8 | 9 | import com.danikula.videocache.HttpProxyCacheServer; 10 | import com.tencent.bugly.crashreport.CrashReport; 11 | 12 | import cn.jk.kaoyandanci.model.DaoMaster; 13 | import cn.jk.kaoyandanci.model.DaoSession; 14 | import cn.jk.kaoyandanci.util.Config; 15 | import cn.jk.kaoyandanci.util.Constant; 16 | import cn.jk.kaoyandanci.util.MediaFileNameGenerator; 17 | import cn.jk.kaoyandanci.util.SPUtil; 18 | import cn.jk.kaoyandanci.util.WordDatabase; 19 | 20 | import static android.os.Build.ID; 21 | 22 | 23 | /** 24 | * Created by then24 on 2015/9/5. 25 | */ 26 | public class InitApplication extends MultiDexApplication { 27 | 28 | DaoMaster.DevOpenHelper helper; 29 | SQLiteDatabase db; 30 | DaoMaster daoMaster; 31 | 32 | Context context; 33 | private DaoSession daoSession; 34 | private HttpProxyCacheServer proxy; 35 | 36 | public static HttpProxyCacheServer getProxy(Context context) { 37 | InitApplication app = (InitApplication) context.getApplicationContext(); 38 | return app.proxy == null ? (app.proxy = app.newProxy()) : app.proxy; 39 | } 40 | 41 | @Override 42 | public void onCreate() { 43 | super.onCreate(); 44 | context = getApplicationContext(); 45 | 46 | Config.setContext(context); 47 | 48 | boolean isFirstOpen = !SPUtil.contains(context, Constant.FIRST_OPEN); 49 | // isFirstOpen=false; //for init db , delete this later 50 | if (isFirstOpen) { 51 | context.deleteDatabase(Constant.DATABASE_NAME); 52 | new WordDatabase(context).getWritableDatabase(); 53 | helper = new DaoMaster.DevOpenHelper(this, Constant.DATABASE_NAME, null); 54 | db = helper.getWritableDatabase(); 55 | daoMaster = new DaoMaster(db); 56 | daoSession = daoMaster.newSession(); 57 | 58 | SPUtil.putAndApply(context, Constant.FIRST_OPEN, "no"); 59 | 60 | } else { 61 | 62 | db = new WordDatabase(context).getWritableDatabase(); 63 | daoMaster = new DaoMaster(db); 64 | daoSession = daoMaster.newSession(); 65 | } 66 | 67 | CrashReport.initCrashReport(getApplicationContext(), "11cc1a2754", false); 68 | 69 | } 70 | 71 | public DaoSession getDaoSession() { 72 | return daoSession; 73 | } 74 | 75 | private HttpProxyCacheServer newProxy() { 76 | HttpProxyCacheServer proxy = (new HttpProxyCacheServer.Builder(context)) 77 | .fileNameGenerator(new MediaFileNameGenerator()) 78 | .build(); 79 | return proxy; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /app/src/main/java/cn/jk/kaoyandanci/model/AutoReviewWordList.java: -------------------------------------------------------------------------------- 1 | package cn.jk.kaoyandanci.model; 2 | 3 | import android.content.Context; 4 | 5 | import java.util.Date; 6 | 7 | 8 | /** 9 | * Created by Administrator on 2017/6/13. 10 | */ 11 | 12 | public class AutoReviewWordList extends WordList { 13 | 14 | Date reviewDate; 15 | 16 | 17 | /** 18 | * @param context activity 中的context 19 | */ 20 | public AutoReviewWordList(Context context) { 21 | super(context); 22 | long now = new Date().getTime(); 23 | long[][] duringSecond = new long[][]{ 24 | {3, 8}, 25 | {20, 40}, 26 | {10 * 60, 14 * 60}, 27 | {22 * 60, 26 * 60}, 28 | {(24 * 2) * 60, (24 * 3) * 60}, 29 | {(24 * 6) * 60, (24 * 7) * 60}, 30 | {(24 * 14) * 60, (24 * 15) * 60} 31 | }; 32 | for (int i = 0; i < duringSecond.length; i++) { 33 | for (int j = 0; j < duringSecond[0].length; j++) { 34 | duringSecond[i][j] = now - duringSecond[i][j] * 60 * 1000; 35 | } 36 | } 37 | boolean showAnd = false; 38 | StringBuffer stringBuffer = new StringBuffer(); 39 | for (int i = 0; i < duringSecond.length; i++) { 40 | 41 | if (showAnd) { 42 | stringBuffer.append(" or "); 43 | } else { 44 | stringBuffer.append(" where ( "); 45 | showAnd = true; 46 | 47 | } 48 | long before = duringSecond[i][0]; 49 | long after = duringSecond[i][1]; 50 | String condition = " (last_learn_time>" + after + " and last_learn_time<" + before + ") "; 51 | stringBuffer.append(condition); 52 | 53 | } 54 | stringBuffer.append(")and never_show is null order by last_learn_time"); 55 | words = wordDao.queryRaw(stringBuffer.toString()); 56 | currentPosition = 0; 57 | } 58 | 59 | 60 | /** 61 | * 62 | * @return 63 | */ 64 | @Override 65 | public Word next() { 66 | currentPosition++; 67 | if (overLast()) { 68 | return null; 69 | } else { 70 | return words.get(currentPosition); 71 | } 72 | } 73 | 74 | @Override 75 | public String getListName() { 76 | return "智能复习"; 77 | } 78 | 79 | @Override 80 | public String getFinishMessage() { 81 | return "已经完成智能复习"; 82 | } 83 | 84 | @Override 85 | public String getEmptyMessage() { 86 | return "没有需要智能复习的单词"; 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /app/src/main/java/cn/jk/kaoyandanci/model/CommonQuestion.java: -------------------------------------------------------------------------------- 1 | package cn.jk.kaoyandanci.model; 2 | 3 | import java.io.Serializable; 4 | 5 | /** 6 | * Created by Administrator on 2017/6/30. 7 | */ 8 | 9 | public class CommonQuestion implements Serializable { 10 | private String question; 11 | private String solution; 12 | 13 | public String getQuestion() { 14 | return question; 15 | } 16 | 17 | public void setQuestion(String question) { 18 | this.question = question; 19 | } 20 | 21 | public String getSolution() { 22 | return solution; 23 | } 24 | 25 | public void setSolution(String solution) { 26 | this.solution = solution; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /app/src/main/java/cn/jk/kaoyandanci/model/DayReviewWordList.java: -------------------------------------------------------------------------------- 1 | package cn.jk.kaoyandanci.model; 2 | 3 | import android.content.Context; 4 | 5 | import org.greenrobot.greendao.query.WhereCondition; 6 | 7 | import java.text.SimpleDateFormat; 8 | import java.util.Date; 9 | 10 | import cn.jk.kaoyandanci.util.DayUtil; 11 | import cn.jk.kaoyandanci.util.SPUtil; 12 | 13 | 14 | /** 15 | * Created by Administrator on 2017/6/13. 16 | */ 17 | 18 | public class DayReviewWordList extends WordList { 19 | 20 | Date reviewDate; 21 | 22 | 23 | /** 24 | * @param context activity 中的context 25 | * @param reviewDate 26 | */ 27 | public DayReviewWordList(Context context, Date reviewDate) { 28 | super(context); 29 | this.reviewDate = reviewDate; 30 | 31 | if (reviewDate == null) { 32 | reviewDate = new Date(); 33 | } 34 | WhereCondition afterStart = WordDao.Properties.LastLearnTime.ge(DayUtil.getStartOfDay(reviewDate)); 35 | WhereCondition beforeEnd = WordDao.Properties.LastLearnTime.le(DayUtil.getEndOfDay(reviewDate)); 36 | WhereCondition shouldShow = WordDao.Properties.NeverShow.isNull(); 37 | words = wordDao.queryBuilder().where(afterStart, beforeEnd, shouldShow).orderAsc(WordDao.Properties.LastLearnTime).list(); 38 | SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMdd"); 39 | spName = simpleDateFormat.format(reviewDate) + "review"; 40 | 41 | int index = (int) SPUtil.get(context, spName, 0); 42 | if (index != 0) { 43 | currentPosition = index; 44 | } 45 | } 46 | 47 | 48 | /** 49 | * 将当前单词 置入这一天的sp中 50 | * 51 | * @return 52 | */ 53 | @Override 54 | public Word next() { 55 | currentPosition++; 56 | if (overLast()) { 57 | SPUtil.putAndApply(context, spName, 0); 58 | return null; 59 | } else { 60 | 61 | SPUtil.putAndApply(context, spName, currentPosition); 62 | return words.get(currentPosition); 63 | } 64 | } 65 | 66 | /** 67 | * 复习完成后重置复习进度 68 | */ 69 | public void init() { 70 | 71 | } 72 | 73 | @Override 74 | public String getListName() { 75 | 76 | return "按天复习"; 77 | } 78 | 79 | @Override 80 | public String getFinishMessage() { 81 | SimpleDateFormat simpleDateFormat = new SimpleDateFormat("MM月dd日"); 82 | String monthDay = simpleDateFormat.format(reviewDate); 83 | return String.format("已经完成%s的复习计划", monthDay); 84 | } 85 | 86 | @Override 87 | public String getEmptyMessage() { 88 | return "没有需要复习的单词"; 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /app/src/main/java/cn/jk/kaoyandanci/model/DefaultWordList.java: -------------------------------------------------------------------------------- 1 | package cn.jk.kaoyandanci.model; 2 | 3 | import android.content.Context; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * Created by jack on 2017/9/11. 9 | * wordList 的默认实现. 10 | */ 11 | 12 | public class DefaultWordList extends WordList { 13 | /** 14 | * @param context 15 | * @param querySql dao.queryRaw()的参数. 16 | * @param title 显示在actionbar上的标题. 17 | */ 18 | public DefaultWordList(Context context, String querySql, String title) { 19 | super(context); 20 | words = wordDao.queryRaw(querySql); 21 | this.title = title; 22 | } 23 | 24 | /** 25 | * @param context 26 | * @param words 27 | * @param title 显示在actionbar上的标题. 28 | */ 29 | public DefaultWordList(Context context, List words, String title) { 30 | super(context); 31 | this.words = words; 32 | this.title = title; 33 | } 34 | 35 | /** 36 | * @return 下一个单词. 37 | */ 38 | @Override 39 | public Word next() { 40 | currentPosition++; 41 | if (overLast()) { 42 | return null; 43 | } else { 44 | return words.get(currentPosition); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /app/src/main/java/cn/jk/kaoyandanci/model/LearnWordList.java: -------------------------------------------------------------------------------- 1 | package cn.jk.kaoyandanci.model; 2 | 3 | import android.content.Context; 4 | 5 | import java.text.SimpleDateFormat; 6 | import java.util.Date; 7 | 8 | import cn.jk.kaoyandanci.util.Config; 9 | import cn.jk.kaoyandanci.util.SPUtil; 10 | import cn.jk.kaoyandanci.util.ToastUtil; 11 | 12 | /** 13 | * Created by Administrator on 2017/6/13. 14 | */ 15 | 16 | public class LearnWordList extends WordList { 17 | 18 | String haveLearnSp; 19 | int shouldLearn; 20 | boolean finish_today; 21 | 22 | public LearnWordList(Context context) { 23 | super(context); 24 | 25 | SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMdd"); 26 | haveLearnSp = simpleDateFormat.format(new Date()) + "learn"; 27 | int haveLearn = (int) SPUtil.get(context, haveLearnSp, 0); 28 | int planLearn = Config.getPlanShouldLearn(); 29 | shouldLearn = planLearn - haveLearn; 30 | String querySql = ""; 31 | String coreSql = ""; 32 | String easySql = ""; 33 | if (Config.coreModeIsOn()) { 34 | coreSql = " and hot=1 "; 35 | } 36 | if (Config.easyModeIsOn()) { 37 | easySql = " and easy =0 "; 38 | } 39 | if (shouldLearn <= 0) { 40 | ToastUtil.showShort(context, "已经完成今日计划,请随意发挥"); 41 | querySql = " where never_show is null " + coreSql + easySql + " ORDER BY RANDOM() LIMIT 1000"; 42 | } else { 43 | querySql = " where never_show is null " + coreSql + easySql + " ORDER BY RANDOM() LIMIT " + shouldLearn; 44 | } 45 | words = wordDao.queryRaw(querySql); 46 | } 47 | 48 | public int getAll() { 49 | int planLearn = Config.getPlanShouldLearn(); 50 | return planLearn; 51 | } 52 | 53 | @Override 54 | public Word next() { 55 | Word currentWord = getCurrent(); 56 | //如果当前单词为空 57 | if (currentWord != null) { 58 | currentWord.setKnowed(); 59 | if (currentWord.getFirstLearnTime() == null) { 60 | currentWord.setFirstLearnTime(new Date()); 61 | } 62 | currentWord.setLastLearnTime(new Date()); 63 | wordDao.update(currentWord); 64 | } 65 | 66 | shouldLearn--; 67 | currentPosition++; 68 | SPUtil.putAndApply(context, haveLearnSp, getAll() - shouldLearn); 69 | //如果当前位置超过应学单词数目 70 | if (overLast()) { 71 | return null; 72 | } 73 | return words.get(currentPosition); 74 | } 75 | 76 | 77 | @Override 78 | public int getNeedLearn() { 79 | return shouldLearn; 80 | } 81 | 82 | public int getPercent() { 83 | if (finish_today) { 84 | return 100; 85 | } else { 86 | return super.getPercent(); 87 | } 88 | } 89 | 90 | @Override 91 | public String getListName() { 92 | return "学习单词"; 93 | } 94 | 95 | @Override 96 | public String getFinishMessage() { 97 | return "已经完成今日学习计划"; 98 | } 99 | 100 | 101 | @Override 102 | public String getEmptyMessage() { 103 | return "我的天,你背完了所有的单词!"; 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /app/src/main/java/cn/jk/kaoyandanci/model/Queries.java: -------------------------------------------------------------------------------- 1 | package cn.jk.kaoyandanci.model; 2 | 3 | import org.greenrobot.greendao.query.QueryBuilder; 4 | 5 | import java.util.List; 6 | 7 | import cn.jk.kaoyandanci.util.Constant; 8 | 9 | /** 10 | * Created by Administrator on 2017/8/3. 11 | */ 12 | 13 | public class Queries { 14 | WordDao wordDao; 15 | 16 | private static Queries ourInstance = null; 17 | 18 | public static Queries getInstance(DaoSession daoSession) { 19 | if (ourInstance == null) { 20 | ourInstance = new Queries(daoSession); 21 | } 22 | return ourInstance; 23 | } 24 | 25 | private Queries(DaoSession daoSession) { 26 | wordDao = daoSession.getWordDao(); 27 | 28 | } 29 | 30 | public List getList(String state, boolean coreMode, boolean easyMode) { 31 | QueryBuilder queryBuilder = wordDao.queryBuilder(); 32 | switch (state) { 33 | case Constant.NEVER_SHOW: 34 | queryBuilder.where(WordDao.Properties.NeverShow.eq("1")); 35 | break; 36 | case Constant.UNKNOWN: 37 | queryBuilder.where(WordDao.Properties.KnowTime.isNull()). 38 | where(WordDao.Properties.UnknownTime.gt(0)).where(WordDao.Properties.NeverShow.isNull()).orderDesc(WordDao.Properties.UnknownTime); 39 | break; 40 | case Constant.NOT_LEARNED: 41 | queryBuilder.where(WordDao.Properties.KnowTime.isNull()). 42 | where(WordDao.Properties.UnknownTime.isNull()).where(WordDao.Properties.NeverShow.isNull()); 43 | break; 44 | case Constant.KNOWED: 45 | queryBuilder.where(WordDao.Properties.KnowTime.gt("0")).where(WordDao.Properties.NeverShow.isNull()).orderDesc(WordDao.Properties.KnowTime); 46 | break; 47 | case Constant.NEED_LEARN: 48 | queryBuilder.where(WordDao.Properties.NeverShow.isNull()); 49 | break; 50 | case Constant.EASY: 51 | return queryBuilder.where(WordDao.Properties.Easy.eq(true)).list(); 52 | 53 | 54 | } 55 | if (coreMode) { 56 | queryBuilder.where(WordDao.Properties.Hot.eq(1)); 57 | } 58 | if (easyMode) { 59 | queryBuilder.where(WordDao.Properties.Easy.notEq(true)); 60 | } 61 | return queryBuilder.list(); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /app/src/main/java/cn/jk/kaoyandanci/model/QueryCondition.java: -------------------------------------------------------------------------------- 1 | package cn.jk.kaoyandanci.model; 2 | 3 | import org.greenrobot.greendao.query.WhereCondition; 4 | 5 | /** 6 | * Created by Administrator on 2017/7/11. 7 | */ 8 | 9 | public class QueryCondition { 10 | static WhereCondition neverShow = WordDao.Properties.NeverShow.in(null, 0); 11 | 12 | } 13 | -------------------------------------------------------------------------------- /app/src/main/java/cn/jk/kaoyandanci/model/WordList.java: -------------------------------------------------------------------------------- 1 | package cn.jk.kaoyandanci.model; 2 | 3 | import android.content.Context; 4 | 5 | import java.util.List; 6 | 7 | import cn.jk.kaoyandanci.InitApplication; 8 | import cn.jk.kaoyandanci.ui.activity.MainActivity; 9 | import cn.jk.kaoyandanci.util.ToastUtil; 10 | 11 | /** 12 | * Created by Administrator on 2017/6/13. 13 | */ 14 | 15 | public abstract class WordList { 16 | 17 | 18 | List words; 19 | Context context; 20 | DaoSession daoSession; 21 | WordDao wordDao; 22 | int currentPosition = 0; 23 | String spName; 24 | String title = "学习单词"; 25 | 26 | public WordList(Context context) { 27 | this.context = context; 28 | DaoSession daoSession = ((InitApplication) context.getApplicationContext()).getDaoSession(); 29 | wordDao = daoSession.getWordDao(); 30 | } 31 | 32 | /** 33 | * @return 共包含多少个单词 34 | */ 35 | public int getAll() { 36 | return words.size(); 37 | } 38 | 39 | 40 | public int getPercent() { 41 | int all = getAll(); 42 | if (all == 0) { 43 | return 100; 44 | } 45 | int learned = all - getNeedLearn(); 46 | return (learned * 100 / all); 47 | } 48 | 49 | /** 50 | * @return 当前需要学习多少个 51 | */ 52 | public int getNeedLearn() { 53 | return words.size() - currentPosition - 1; 54 | } 55 | 56 | /** 57 | * @return 获取下一个单词 58 | */ 59 | public abstract Word next(); 60 | 61 | /** 62 | * @return 当前在学单词 63 | */ 64 | public Word getCurrent() { 65 | if (words.size() <= currentPosition) { 66 | return null; 67 | } else { 68 | return words.get(currentPosition); 69 | } 70 | } 71 | 72 | public void currentKnown() { 73 | if (currentPosition >= words.size()) { 74 | ToastUtil.showShort(context,"你背的单词太快太多了,APP出了些问题.你需要重新进一下应用."); 75 | return; 76 | } 77 | Word currentWord = words.get(currentPosition); 78 | 79 | if (currentWord.getKnowTime() == null) { 80 | currentWord.setKnowTime(1); 81 | } else { 82 | currentWord.setKnowTime(currentWord.getKnowTime() + 1); 83 | } 84 | wordDao.update(currentWord); 85 | MainActivity.DATA_CHANGED = true; 86 | 87 | } 88 | 89 | public void currentUnknown() { 90 | Word currentWord = words.get(currentPosition); 91 | if (currentWord.getUnknownTime() == null) { 92 | currentWord.setUnknownTime(1); 93 | } else { 94 | currentWord.setUnknownTime(currentWord.getUnknownTime() + 1); 95 | } 96 | wordDao.update(currentWord); 97 | MainActivity.DATA_CHANGED = true; 98 | } 99 | 100 | public void currentNeverShow() { 101 | Word currentWord = words.get(currentPosition); 102 | if (currentWord.getKnowTime() == null || currentWord.getKnowTime() == 0) { 103 | currentWord.setKnowTime(1); 104 | } 105 | currentWord.setNeverShow(1); 106 | wordDao.update(currentWord); 107 | MainActivity.DATA_CHANGED = true; 108 | } 109 | 110 | /** 111 | * 当前是否为最后一个元素 112 | * 113 | * @return 114 | */ 115 | public boolean inLast() { 116 | return currentPosition + 1 == words.size(); 117 | } 118 | 119 | /** 120 | * 当前下标超过list长度 121 | */ 122 | public boolean overLast() { 123 | return currentPosition >= words.size(); 124 | } 125 | 126 | 127 | public boolean isEmpty() { 128 | return words.isEmpty(); 129 | } 130 | 131 | public Word previous() { 132 | if (currentPosition == 0) { 133 | return null; 134 | } else { 135 | currentPosition--; 136 | } 137 | return getCurrent(); 138 | } 139 | 140 | public String getListName() { 141 | return title; 142 | } 143 | 144 | public String getFinishMessage() { 145 | return "完成学习单词列表"; 146 | } 147 | 148 | public String getEmptyMessage() { 149 | return "单词列表为空"; 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /app/src/main/java/cn/jk/kaoyandanci/model/WordState.java: -------------------------------------------------------------------------------- 1 | package cn.jk.kaoyandanci.model; 2 | 3 | /** 4 | *
 5 |  *     author : jiakang
 6 |  *     e-mail : 1079153785@qq.com
 7 |  *     time   : 2018/07/25
 8 |  *     desc   :
 9 |  *     version: 1.0
10 |  * 
11 | */ 12 | public class WordState { 13 | public static final int isNeverShow = 1; 14 | 15 | 16 | public static boolean isNeverShow(Word word) { 17 | return word.getNeverShow() != null && word.getNeverShow() == isNeverShow; 18 | } 19 | 20 | public static boolean isCollect(Word word) { 21 | return word.getCollect() != null && word.getCollect() == 1; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /app/src/main/java/cn/jk/kaoyandanci/ui/activity/AboutActivity.java: -------------------------------------------------------------------------------- 1 | package cn.jk.kaoyandanci.ui.activity; 2 | 3 | import android.content.Intent; 4 | import android.net.Uri; 5 | import android.os.Bundle; 6 | import android.preference.Preference; 7 | import android.support.annotation.NonNull; 8 | import android.widget.TextView; 9 | 10 | import com.afollestad.materialdialogs.DialogAction; 11 | import com.afollestad.materialdialogs.MaterialDialog; 12 | 13 | import butterknife.BindView; 14 | import butterknife.ButterKnife; 15 | import butterknife.OnClick; 16 | import cn.jk.kaoyandanci.R; 17 | import cn.jk.kaoyandanci.util.ToastUtil; 18 | 19 | public class AboutActivity extends BaseActivity { 20 | 21 | @BindView(R.id.versionLbl) 22 | TextView versionLbl; 23 | @BindView(R.id.commonQuestionLbl) 24 | TextView commonQuestionLbl; 25 | @BindView(R.id.rateLbl) 26 | TextView rateLbl; 27 | @BindView(R.id.shareLbl) 28 | TextView shareLbl; 29 | @BindView(R.id.donateLbl) 30 | TextView donateLbl; 31 | @BindView(R.id.feedbackLbl) 32 | TextView feedbackLbl; 33 | @BindView(R.id.suggestAppLbl) 34 | TextView suggestAppLbl; 35 | 36 | @Override 37 | protected void onCreate(Bundle savedInstanceState) { 38 | super.onCreate(savedInstanceState); 39 | 40 | setContentView(R.layout.activity_about); 41 | ButterKnife.bind(this); 42 | getSupportActionBar().setTitle("关于软件"); 43 | String versionName = ""; 44 | try { 45 | versionName = getPackageManager().getPackageInfo(getPackageName(), 0).versionName; 46 | } catch (Exception e) { 47 | ToastUtil.showShort(context, e.toString()); 48 | } 49 | versionLbl.setText(versionName); 50 | } 51 | 52 | @OnClick(R.id.commonQuestionLbl) 53 | public void onCommonQuestionLblClicked() { 54 | startActivity(new Intent(context, CommonQuestionActivity.class)); 55 | } 56 | @OnClick(R.id.suggestAppLbl) 57 | public void onsuggestAppLblclicked() { 58 | new MaterialDialog.Builder(this).content("背单词是考研单词的升级版,(可能)会长期维护,并且释义更全,单词书更多,欢迎下载(๑•́ ₃ •̀๑)").positiveText(R.string.open_broswer) 59 | .onPositive(new MaterialDialog.SingleButtonCallback() { 60 | @Override 61 | public void onClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which) { 62 | Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://www.coolapk.com/apk/240082")); 63 | startActivity(browserIntent); 64 | } 65 | }).show(); 66 | } 67 | 68 | @OnClick(R.id.rateLbl) 69 | public void onRateLblClicked() { 70 | try { 71 | 72 | Uri uri = Uri.parse("market://details?id=" + getPackageName()); 73 | Intent intent = new Intent(Intent.ACTION_VIEW, uri); 74 | intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 75 | startActivity(intent); 76 | } catch (Exception e) { 77 | ToastUtil.showShort(context, "没有找到应用市场.sorry"); 78 | } 79 | } 80 | 81 | @OnClick(R.id.shareLbl) 82 | public void onShareLblClicked() { 83 | Intent sendIntent = new Intent(); 84 | sendIntent.setAction(Intent.ACTION_SEND); 85 | sendIntent.setType("text/*"); 86 | sendIntent.putExtra(Intent.EXTRA_TEXT, getResources().getString(R.string.share_content)); 87 | startActivity(sendIntent); 88 | } 89 | 90 | @OnClick(R.id.donateLbl) 91 | public void onDonateLblClicked() { 92 | startActivity(new Intent(context, DonateActivity.class)); 93 | } 94 | 95 | @OnClick(R.id.feedbackLbl) 96 | public void onFeedbackLblClicked() { 97 | startActivity(new Intent(context, FeedbackActivity.class)); 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /app/src/main/java/cn/jk/kaoyandanci/ui/activity/AdvanceSettingActivity.java: -------------------------------------------------------------------------------- 1 | package cn.jk.kaoyandanci.ui.activity; 2 | 3 | import android.os.Bundle; 4 | 5 | import cn.jk.kaoyandanci.R; 6 | import cn.jk.kaoyandanci.ui.fragment.AdvanceSettingFragment; 7 | 8 | public class AdvanceSettingActivity extends BaseActivity { 9 | 10 | private AdvanceSettingFragment fragment; 11 | public boolean visible; 12 | 13 | @Override 14 | protected void onCreate(Bundle savedInstanceState) { 15 | super.onCreate(savedInstanceState); 16 | setContentView(R.layout.activity_display_setting); 17 | if (savedInstanceState == null) { 18 | fragment = new AdvanceSettingFragment(); 19 | getFragmentManager().beginTransaction().replace(R.id.content_frames, fragment).commit(); 20 | } else { 21 | fragment = (AdvanceSettingFragment) (getFragmentManager().findFragmentById(R.id.content_frames)); 22 | 23 | } 24 | getSupportActionBar().setTitle("高级设置"); 25 | } 26 | 27 | @Override 28 | public void onResume() { 29 | super.onResume(); 30 | visible = true; 31 | } 32 | 33 | @Override 34 | protected void onPause() { 35 | super.onPause(); 36 | visible = false; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /app/src/main/java/cn/jk/kaoyandanci/ui/activity/BaseActivity.java: -------------------------------------------------------------------------------- 1 | package cn.jk.kaoyandanci.ui.activity; 2 | 3 | import android.content.Context; 4 | import android.content.pm.ActivityInfo; 5 | import android.os.Bundle; 6 | 7 | import com.afollestad.aesthetic.AestheticActivity; 8 | 9 | import cn.jk.kaoyandanci.InitApplication; 10 | import cn.jk.kaoyandanci.model.DaoSession; 11 | import cn.jk.kaoyandanci.model.WordDao; 12 | 13 | /** 14 | * Created by Administrator on 2017/6/8. 15 | */ 16 | 17 | public class BaseActivity extends AestheticActivity { 18 | 19 | DaoSession daoSession; 20 | WordDao wordDao; 21 | Context context; 22 | 23 | @Override 24 | protected void onCreate(Bundle savedInstanceState) { 25 | super.onCreate(savedInstanceState); 26 | setRequestedOrientation (ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); 27 | daoSession = ((InitApplication) getApplication()).getDaoSession(); 28 | wordDao = daoSession.getWordDao(); 29 | context = getApplicationContext(); 30 | } 31 | 32 | @Override 33 | public void onResume() { 34 | super.onResume(); 35 | 36 | } 37 | 38 | public WordDao getWordDao() { 39 | return wordDao; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /app/src/main/java/cn/jk/kaoyandanci/ui/activity/BaseWordListActivity.java: -------------------------------------------------------------------------------- 1 | package cn.jk.kaoyandanci.ui.activity; 2 | 3 | import android.os.Bundle; 4 | import android.support.v7.widget.LinearLayoutManager; 5 | import android.support.v7.widget.RecyclerView; 6 | import android.view.Menu; 7 | import android.view.MenuItem; 8 | import android.view.View; 9 | 10 | import java.util.Date; 11 | import java.util.List; 12 | 13 | import butterknife.BindView; 14 | import butterknife.ButterKnife; 15 | import cn.jk.kaoyandanci.R; 16 | import cn.jk.kaoyandanci.model.Word; 17 | import cn.jk.kaoyandanci.model.WordState; 18 | import cn.jk.kaoyandanci.ui.adapter.WordListAdapter; 19 | import cn.jk.kaoyandanci.util.Config; 20 | 21 | /** 22 | *
 23 |  *     author : jiakang
 24 |  *     e-mail : 1079153785@qq.com
 25 |  *     time   : 2018/07/26
 26 |  *     desc   :
 27 |  *     version: 1.0
 28 |  * 
29 | */ 30 | 31 | public abstract class BaseWordListActivity extends BaseActivity { 32 | @BindView(R.id.wordRcy) 33 | RecyclerView wordRcy; 34 | 35 | @BindView(R.id.empty_view) 36 | View emptyView; 37 | 38 | 39 | boolean showChinese = Config.getShowChinese(); 40 | boolean showEdt = false; 41 | 42 | List words; 43 | int currentPosition = 0; 44 | 45 | WordListAdapter wordListAdapter; 46 | LinearLayoutManager layoutManager; 47 | 48 | String wordType = "单词列表"; 49 | int wordCount = -1; 50 | 51 | 52 | @Override 53 | protected void onCreate(Bundle savedInstanceState) { 54 | super.onCreate(savedInstanceState); 55 | setContentView(getContentViewId()); 56 | ButterKnife.bind(this); 57 | } 58 | 59 | @Override 60 | public void onPause() { 61 | wordRcy.stopScroll(); //这里有一个bug...就是在scroll的时候pause aesthetic就会崩溃. 62 | super.onPause(); 63 | } 64 | 65 | public void reverseNeverShow(Word word) { 66 | if (WordState.isNeverShow(word)) { 67 | word.setNeverShow(null); 68 | wordDao.update(word); 69 | } else { 70 | if (word.getKnowTime() == null || word.getKnowTime() == 0) { 71 | word.setKnowTime(1); 72 | word.setLastLearnTime(new Date()); 73 | } 74 | word.setNeverShow(1); 75 | wordDao.update(word); 76 | } 77 | wordCount--; 78 | getSupportActionBar().setTitle(wordType + wordCount); 79 | } 80 | 81 | public void reverseCollect(Word word) { 82 | if (WordState.isCollect(word)) { 83 | word.setCollect(0); 84 | } else { 85 | word.setCollect(1); 86 | } 87 | wordDao.update(word); 88 | } 89 | 90 | @Override 91 | public boolean onOptionsItemSelected(MenuItem item) { 92 | switch (item.getItemId()) { 93 | 94 | case R.id.showChineseChk: 95 | 96 | currentPosition = layoutManager.findFirstVisibleItemPosition(); 97 | 98 | item.setChecked(!item.isChecked()); 99 | showChinese = item.isChecked(); 100 | Config.setShowChinese(showChinese); 101 | showWord(); 102 | 103 | return true; 104 | case R.id.showEditChk: 105 | item.setChecked(!item.isChecked()); 106 | showEdt = item.isChecked(); 107 | showWord(); 108 | return true; 109 | default: 110 | return super.onOptionsItemSelected(item); 111 | } 112 | } 113 | 114 | @Override 115 | public boolean onCreateOptionsMenu(Menu menu) { 116 | 117 | getMenuInflater().inflate(R.menu.menu_word_list, menu); 118 | MenuItem showChineseChk = menu.findItem(R.id.showChineseChk); 119 | showChineseChk.setChecked(Config.getShowChinese()); 120 | return true; 121 | } 122 | 123 | public void showWord() { 124 | if (wordListAdapter == null) { 125 | wordListAdapter = new WordListAdapter(words, this); 126 | wordRcy.setHasFixedSize(true); 127 | layoutManager = new LinearLayoutManager(context); 128 | wordRcy.setLayoutManager(layoutManager); 129 | wordRcy.setAdapter(wordListAdapter); 130 | } 131 | 132 | if (words.size() != 0) { 133 | wordCount = words.size(); 134 | getSupportActionBar().setTitle(wordType + wordCount); 135 | } 136 | if (words.size() == 0) { 137 | emptyView.setVisibility(View.VISIBLE); 138 | } else { 139 | emptyView.setVisibility(View.GONE); 140 | } 141 | 142 | wordListAdapter.setShowEdt(showEdt); 143 | wordListAdapter.setShowChinese(showChinese); 144 | wordListAdapter.notifyDataSetChanged(); 145 | layoutManager.scrollToPosition(currentPosition); 146 | } 147 | 148 | abstract int getContentViewId(); 149 | } 150 | -------------------------------------------------------------------------------- /app/src/main/java/cn/jk/kaoyandanci/ui/activity/CommonQuestionActivity.java: -------------------------------------------------------------------------------- 1 | package cn.jk.kaoyandanci.ui.activity; 2 | 3 | import android.os.Bundle; 4 | import android.support.v7.widget.LinearLayoutManager; 5 | import android.support.v7.widget.RecyclerView; 6 | 7 | import java.util.List; 8 | 9 | import butterknife.BindView; 10 | import butterknife.ButterKnife; 11 | import cn.jk.kaoyandanci.R; 12 | import cn.jk.kaoyandanci.model.CommonQuestion; 13 | import cn.jk.kaoyandanci.ui.adapter.QuestionAdapter; 14 | import cn.jk.kaoyandanci.util.AssetsUtil; 15 | 16 | public class CommonQuestionActivity extends BaseActivity { 17 | 18 | @BindView(R.id.questionRcl) 19 | RecyclerView questionRcl; 20 | 21 | @Override 22 | protected void onCreate(Bundle savedInstanceState) { 23 | super.onCreate(savedInstanceState); 24 | setContentView(R.layout.activity_common_question); 25 | 26 | List commonQuestions = AssetsUtil.loadCardFromFile(this, "question.json"); 27 | ButterKnife.bind(this); 28 | questionRcl.setHasFixedSize(true); 29 | 30 | questionRcl.setLayoutManager(new LinearLayoutManager(this)); 31 | questionRcl.setAdapter(new QuestionAdapter(commonQuestions, this)); 32 | getSupportActionBar().setTitle("常见问题"); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /app/src/main/java/cn/jk/kaoyandanci/ui/activity/DonateActivity.java: -------------------------------------------------------------------------------- 1 | package cn.jk.kaoyandanci.ui.activity; 2 | 3 | import android.Manifest; 4 | import android.content.Intent; 5 | import android.content.pm.PackageManager; 6 | import android.graphics.Bitmap; 7 | import android.graphics.BitmapFactory; 8 | import android.net.Uri; 9 | import android.os.Bundle; 10 | import android.support.v4.app.ActivityCompat; 11 | import android.support.v4.content.ContextCompat; 12 | import android.view.View; 13 | import android.widget.Button; 14 | import android.widget.ImageView; 15 | 16 | import butterknife.BindView; 17 | import butterknife.ButterKnife; 18 | import butterknife.OnClick; 19 | import cn.jk.kaoyandanci.R; 20 | import cn.jk.kaoyandanci.util.FileUtil; 21 | import cn.jk.kaoyandanci.util.ToastUtil; 22 | 23 | public class DonateActivity extends BaseActivity { 24 | 25 | public static final String weixin = "微信"; 26 | public static final String alipay = "支付宝"; 27 | @BindView(R.id.alipayBtn) 28 | Button alipayBtn; 29 | @BindView(R.id.weixinBtn) 30 | Button weixinBtn; 31 | @BindView(R.id.openAlipayBtn) 32 | Button openAlipayBtn; 33 | @BindView(R.id.donateImg) 34 | ImageView donateImg; 35 | @BindView(R.id.saveDonateImgBtn) 36 | Button saveDonateImgBtn; 37 | String currentImgType = weixin; 38 | 39 | final int requestPermissionCode = 10; 40 | 41 | @Override 42 | protected void onCreate(Bundle savedInstanceState) { 43 | super.onCreate(savedInstanceState); 44 | setContentView(R.layout.activity_donate); 45 | ButterKnife.bind(this); 46 | getSupportActionBar().setTitle("打赏开发者"); 47 | } 48 | 49 | @OnClick(R.id.alipayBtn) 50 | public void onAlipayBtnClicked() { 51 | openAlipayBtn.setVisibility(View.VISIBLE); 52 | donateImg.setImageResource(R.drawable.donate_alipay); 53 | currentImgType = alipay; 54 | } 55 | 56 | @OnClick(R.id.weixinBtn) 57 | public void onWeixinBtnClicked() { 58 | openAlipayBtn.setVisibility(View.INVISIBLE); 59 | donateImg.setImageResource(R.drawable.donate_weixin); 60 | currentImgType = weixin; 61 | } 62 | 63 | @OnClick(R.id.openAlipayBtn) 64 | public void onOpenAlipayBtnClicked() { 65 | String alipayUrl = getString(R.string.alipayUrl); 66 | Intent i = new Intent(Intent.ACTION_VIEW); 67 | i.setData(Uri.parse(alipayUrl)); 68 | startActivity(i); 69 | } 70 | 71 | @Override 72 | public void onRequestPermissionsResult(int requestCode, 73 | String permissions[], int[] grantResults) { 74 | switch (requestCode) { 75 | case requestPermissionCode: { 76 | // If request is cancelled, the result arrays are empty. 77 | if (grantResults.length > 0 78 | && grantResults[0] == PackageManager.PERMISSION_GRANTED) { 79 | saveQrImg(); 80 | } else { 81 | ToastUtil.showShort(context, "请给我存储权限QAQ"); 82 | } 83 | return; 84 | } 85 | 86 | // other 'case' lines to check for other 87 | // permissions this app might request 88 | } 89 | } 90 | 91 | private void saveQrImg() { 92 | if (ContextCompat.checkSelfPermission(context, 93 | Manifest.permission.WRITE_EXTERNAL_STORAGE) 94 | != PackageManager.PERMISSION_GRANTED) { 95 | ActivityCompat.requestPermissions(this, 96 | new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE}, requestPermissionCode 97 | ); 98 | return; 99 | } 100 | 101 | int resId = currentImgType.equals(weixin) ? R.drawable.donate_weixin : R.drawable.donate_alipay; 102 | Bitmap donateBm = BitmapFactory.decodeResource(getResources(), resId); 103 | 104 | String fileName = currentImgType.equals(weixin) ? "IMG_donateByWeiXin.png" : "IMG_donateByAlipay.png"; 105 | 106 | FileUtil.saveImg(context, fileName, donateBm); 107 | 108 | ToastUtil.showShort(context, String.format("已将二维码保存至本地,请打开%s扫一扫", currentImgType)); 109 | } 110 | 111 | @OnClick(R.id.saveDonateImgBtn) 112 | public void onViewClicked() { 113 | saveQrImg(); 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /app/src/main/java/cn/jk/kaoyandanci/ui/activity/EmptyActivity.java: -------------------------------------------------------------------------------- 1 | package cn.jk.kaoyandanci.ui.activity; 2 | 3 | import android.app.Activity; 4 | import android.os.Bundle; 5 | 6 | /** 7 | * 启动一个空的activity然后关闭,为了给底部的view着色,后期再想办法, 8 | */ 9 | public class EmptyActivity extends Activity { 10 | 11 | @Override 12 | protected void onCreate(Bundle savedInstanceState) { 13 | super.onCreate(savedInstanceState); 14 | finish(); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /app/src/main/java/cn/jk/kaoyandanci/ui/activity/FeedbackActivity.java: -------------------------------------------------------------------------------- 1 | package cn.jk.kaoyandanci.ui.activity; 2 | 3 | import android.os.Bundle; 4 | import android.widget.Button; 5 | import android.widget.EditText; 6 | 7 | import com.android.volley.Request; 8 | import com.android.volley.RequestQueue; 9 | import com.android.volley.Response; 10 | import com.android.volley.VolleyError; 11 | import com.android.volley.toolbox.StringRequest; 12 | 13 | import java.util.Date; 14 | import java.util.HashMap; 15 | import java.util.Map; 16 | 17 | import butterknife.BindView; 18 | import butterknife.ButterKnife; 19 | import butterknife.OnClick; 20 | import cn.jk.kaoyandanci.R; 21 | import cn.jk.kaoyandanci.util.Config; 22 | import cn.jk.kaoyandanci.util.Constant; 23 | import cn.jk.kaoyandanci.util.NetWorkSingleton; 24 | import cn.jk.kaoyandanci.util.ToastUtil; 25 | 26 | public class FeedbackActivity extends BaseActivity { 27 | 28 | @BindView(R.id.contentEdt) 29 | EditText contentEdt; 30 | @BindView(R.id.contactInfoEdt) 31 | EditText contactInfoEdt; 32 | @BindView(R.id.submitBtn) 33 | Button submitBtn; 34 | 35 | @Override 36 | protected void onCreate(Bundle savedInstanceState) { 37 | super.onCreate(savedInstanceState); 38 | setContentView(R.layout.activity_feedback); 39 | ButterKnife.bind(this); 40 | getSupportActionBar().setTitle("意见反馈"); 41 | } 42 | 43 | @OnClick(R.id.submitBtn) 44 | public void onViewClicked() { 45 | final String contactInfo = contactInfoEdt.getText().toString(); 46 | 47 | final String content = contentEdt.getText().toString(); 48 | if (content == null || content.isEmpty()) { 49 | ToastUtil.showShort(context, "反馈内容还没填写"); 50 | return; 51 | } 52 | final String guid = Config.getGUID(); 53 | 54 | final String project = Constant.PROJECT_ID; 55 | 56 | 57 | RequestQueue requestQueue = NetWorkSingleton.getInstance(context).getRequestQueue(); 58 | StringRequest feedbackRequest = new StringRequest(Request.Method.POST, Constant.FEEDBACK_URL, 59 | new Response.Listener() { 60 | @Override 61 | public void onResponse(String response) { 62 | ToastUtil.showShort(context, response); 63 | submitBtn.setClickable(true); 64 | } 65 | }, new Response.ErrorListener() { 66 | @Override 67 | public void onErrorResponse(VolleyError error) { 68 | ToastUtil.showShort(context, error.toString()); 69 | submitBtn.setClickable(true); 70 | } 71 | }) { 72 | protected Map getParams() throws com.android.volley.AuthFailureError { 73 | Map params = new HashMap(); 74 | if (contactInfo != null && !contactInfo.isEmpty()) { 75 | params.put("contactInfo", contactInfo); 76 | } 77 | params.put("guid", guid); 78 | params.put("project", project); 79 | params.put("content", content + new Date().toString()); 80 | 81 | return params; 82 | } 83 | 84 | ; 85 | }; 86 | requestQueue.add(feedbackRequest); 87 | submitBtn.setClickable(false); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /app/src/main/java/cn/jk/kaoyandanci/ui/activity/IntroActivity.java: -------------------------------------------------------------------------------- 1 | package cn.jk.kaoyandanci.ui.activity; 2 | 3 | import android.os.Bundle; 4 | import android.support.annotation.Nullable; 5 | import android.support.v4.app.Fragment; 6 | import android.support.v7.app.ActionBar; 7 | 8 | import com.github.paolorotolo.appintro.AppIntro; 9 | 10 | import cn.jk.kaoyandanci.ui.fragment.Intro1Fragment; 11 | import cn.jk.kaoyandanci.ui.fragment.Intro2Fragment; 12 | import cn.jk.kaoyandanci.ui.fragment.Intro3Fragment; 13 | import cn.jk.kaoyandanci.util.Config; 14 | import cn.jk.kaoyandanci.util.Constant; 15 | 16 | /** 17 | * Created by Administrator on 2017/6/30. 18 | */ 19 | 20 | public class IntroActivity extends AppIntro { 21 | @Override 22 | protected void onCreate(@Nullable Bundle savedInstanceState) { 23 | super.onCreate(savedInstanceState); 24 | setFadeAnimation(); 25 | ActionBar actionBar = getSupportActionBar(); 26 | if (actionBar != null) { 27 | actionBar.hide(); 28 | } 29 | // Note here that we DO NOT use setContentView(); 30 | Fragment intro1 = new Intro1Fragment(); 31 | Fragment intro2 = new Intro2Fragment(); 32 | Fragment intro3 = new Intro3Fragment(); 33 | 34 | addSlide(intro1); 35 | addSlide(intro2); 36 | addSlide(intro3); 37 | 38 | 39 | // Hide Skip/Done button. 40 | showSkipButton(true); 41 | setProgressButtonEnabled(true); 42 | setSkipText("跳过"); 43 | setDoneText("开始"); 44 | 45 | if (Config.getGUID().equals(Constant.DEFAULT_GUID)) { 46 | Config.setGuid(java.util.UUID.randomUUID().toString()); 47 | } 48 | 49 | } 50 | 51 | @Override 52 | public void onSkipPressed(Fragment currentFragment) { 53 | super.onSkipPressed(currentFragment); 54 | finish(); 55 | } 56 | 57 | @Override 58 | public void onDonePressed(Fragment currentFragment) { 59 | super.onDonePressed(currentFragment); 60 | finish(); 61 | } 62 | 63 | @Override 64 | public void onSlideChanged(@Nullable Fragment oldFragment, @Nullable Fragment newFragment) { 65 | super.onSlideChanged(oldFragment, newFragment); 66 | // Do something when the slide changes. 67 | } 68 | } -------------------------------------------------------------------------------- /app/src/main/java/cn/jk/kaoyandanci/ui/activity/MyWordListActivity.java: -------------------------------------------------------------------------------- 1 | package cn.jk.kaoyandanci.ui.activity; 2 | 3 | import android.os.Bundle; 4 | import android.view.Menu; 5 | import android.view.MenuItem; 6 | 7 | import org.greenrobot.greendao.query.QueryBuilder; 8 | 9 | import cn.jk.kaoyandanci.R; 10 | import cn.jk.kaoyandanci.model.Word; 11 | import cn.jk.kaoyandanci.model.WordDao; 12 | import cn.jk.kaoyandanci.ui.dialog.AddWordDialog; 13 | import cn.jk.kaoyandanci.util.Config; 14 | 15 | public class MyWordListActivity extends BaseWordListActivity { 16 | 17 | 18 | 19 | @Override 20 | protected void onCreate(Bundle savedInstanceState) { 21 | super.onCreate(savedInstanceState); 22 | wordType = "我的单词"; 23 | QueryBuilder queryBuilder = wordDao.queryBuilder(); 24 | words = queryBuilder.where(WordDao.Properties.Collect.eq(1)).list(); 25 | showWord(); 26 | 27 | } 28 | 29 | @Override 30 | public boolean onCreateOptionsMenu(Menu menu) { 31 | 32 | getMenuInflater().inflate(R.menu.menu_my_word_list, menu); 33 | MenuItem showChineseChk = menu.findItem(R.id.showChineseChk); 34 | showChineseChk.setChecked(Config.getShowChinese()); 35 | return true; 36 | } 37 | 38 | @Override 39 | public boolean onOptionsItemSelected(MenuItem item) { 40 | switch (item.getItemId()) { 41 | 42 | case R.id.addWord: 43 | new AddWordDialog().show(getFragmentManager(), "addWordDialog"); 44 | default: 45 | return super.onOptionsItemSelected(item); 46 | } 47 | } 48 | 49 | 50 | @Override 51 | int getContentViewId() { 52 | return R.layout.activity_my_word_list; 53 | } 54 | 55 | public void addWord(Word word) { 56 | words.add(0, word); 57 | showWord(); 58 | 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /app/src/main/java/cn/jk/kaoyandanci/ui/activity/SearchWordActivity.java: -------------------------------------------------------------------------------- 1 | package cn.jk.kaoyandanci.ui.activity; 2 | 3 | import android.content.Context; 4 | import android.content.Intent; 5 | import android.os.Bundle; 6 | import android.support.v4.view.MenuItemCompat; 7 | import android.support.v7.app.ActionBar; 8 | import android.support.v7.widget.LinearLayoutManager; 9 | import android.support.v7.widget.RecyclerView; 10 | import android.support.v7.widget.SearchView; 11 | import android.view.Menu; 12 | import android.view.MenuItem; 13 | import android.view.View; 14 | 15 | import java.util.ArrayList; 16 | import java.util.List; 17 | import java.util.regex.Pattern; 18 | 19 | import butterknife.BindView; 20 | import butterknife.ButterKnife; 21 | import cn.jk.kaoyandanci.InitApplication; 22 | import cn.jk.kaoyandanci.R; 23 | import cn.jk.kaoyandanci.model.DaoSession; 24 | import cn.jk.kaoyandanci.model.Word; 25 | import cn.jk.kaoyandanci.model.WordDao; 26 | import cn.jk.kaoyandanci.ui.adapter.WordListAdapter; 27 | import cn.jk.kaoyandanci.ui.dialog.WebSearchTipDialog; 28 | import cn.jk.kaoyandanci.util.Config; 29 | import cn.jk.kaoyandanci.util.Constant; 30 | import cn.jk.kaoyandanci.util.ToastUtil; 31 | 32 | 33 | public class SearchWordActivity extends BaseActivity implements SearchView.OnQueryTextListener { 34 | 35 | DaoSession daoSession; 36 | WordDao wordDao; 37 | Context context; 38 | SearchView wordSearchView; 39 | 40 | @BindView(R.id.candidateWordView) 41 | RecyclerView candidateWordView; 42 | 43 | WordListAdapter wordListAdapter; 44 | 45 | @Override 46 | protected void onCreate(Bundle savedInstanceState) { 47 | super.onCreate(savedInstanceState); 48 | 49 | context = getApplicationContext(); 50 | daoSession = ((InitApplication) getApplication()).getDaoSession(); 51 | wordDao = daoSession.getWordDao(); 52 | 53 | setContentView(R.layout.activity_search_word); 54 | ButterKnife.bind(this); 55 | 56 | 57 | wordListAdapter = new WordListAdapter(new ArrayList(), this); 58 | candidateWordView.setHasFixedSize(true); 59 | candidateWordView.setLayoutManager(new LinearLayoutManager(context)); 60 | candidateWordView.setAdapter(wordListAdapter); 61 | 62 | } 63 | 64 | @Override 65 | public boolean onCreateOptionsMenu(Menu menu) { 66 | 67 | getMenuInflater().inflate(R.menu.search_word_menu, menu); 68 | ActionBar actionBar = getSupportActionBar(); 69 | if (actionBar != null) { 70 | getSupportActionBar().setDisplayShowTitleEnabled(false); 71 | getSupportActionBar().setDisplayHomeAsUpEnabled(true); 72 | getSupportActionBar().setDisplayShowHomeEnabled(true); 73 | } 74 | final MenuItem searchItem = menu.findItem(R.id.searchWordView); 75 | wordSearchView = (SearchView) MenuItemCompat.getActionView(searchItem); 76 | wordSearchView.setOnQueryTextListener(this); 77 | wordSearchView.setIconified(false); 78 | wordSearchView.setOnQueryTextFocusChangeListener(new View.OnFocusChangeListener() { 79 | @Override 80 | public void onFocusChange(View v, boolean hasFocus) { 81 | if (!hasFocus) { 82 | finish(); 83 | } 84 | } 85 | }); 86 | return true; 87 | } 88 | 89 | @Override 90 | public boolean onOptionsItemSelected(MenuItem item) { 91 | // handle arrow click here 92 | if (item.getItemId() == android.R.id.home) { 93 | finish(); // close this activity and return to preview activity (if there is any) 94 | } 95 | return super.onOptionsItemSelected(item); 96 | } 97 | 98 | @Override 99 | public boolean onQueryTextSubmit(String query) { 100 | 101 | Intent intent = new Intent(context, YoudaoWordActivity.class); 102 | intent.putExtra(Constant.ENGLISH, query); 103 | startActivity(intent); 104 | return true; 105 | } 106 | 107 | @Override 108 | public boolean onQueryTextChange(String newText) { 109 | 110 | String toQuery = wordSearchView.getQuery().toString(); 111 | if (toQuery.equals("")) { 112 | wordListAdapter.setWordList(new ArrayList()); 113 | wordListAdapter.notifyDataSetChanged(); 114 | return false; 115 | } 116 | if (!Pattern.compile("^[\\u4e00-\\u9fa5_a-zA-Z]+$").matcher(toQuery).matches()) { 117 | ToastUtil.showShort(context, "只能输入中英文"); 118 | return false; 119 | } 120 | if (Pattern.compile("^[\\u4e00-\\u9fa5]+$").matcher(toQuery).matches()) { 121 | 122 | return false; 123 | } 124 | if (Pattern.compile("^[a-zA-Z]+$").matcher(toQuery).matches()) { 125 | String whereCondition = " where english like '" + toQuery + "%' COLLATE NOCASE limit 10"; 126 | List words = wordDao.queryRaw(whereCondition); 127 | wordListAdapter.setWordList(words); 128 | 129 | wordListAdapter.notifyDataSetChanged(); 130 | if (words.size() == 0) { 131 | if (Config.shouldSearchTipShow()) { 132 | new WebSearchTipDialog().show(getFragmentManager(), "webSearchTip"); 133 | return false; 134 | } 135 | } 136 | return false; 137 | } 138 | return false; 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /app/src/main/java/cn/jk/kaoyandanci/ui/activity/SolutionActivity.java: -------------------------------------------------------------------------------- 1 | package cn.jk.kaoyandanci.ui.activity; 2 | 3 | import android.os.Bundle; 4 | import android.widget.TextView; 5 | 6 | import butterknife.BindView; 7 | import butterknife.ButterKnife; 8 | import cn.jk.kaoyandanci.R; 9 | import cn.jk.kaoyandanci.model.CommonQuestion; 10 | import cn.jk.kaoyandanci.util.Constant; 11 | 12 | public class SolutionActivity extends BaseActivity { 13 | 14 | @BindView(R.id.questionTxt) 15 | TextView questionTxt; 16 | @BindView(R.id.solutionTxt) 17 | TextView solutionTxt; 18 | 19 | @Override 20 | protected void onCreate(Bundle savedInstanceState) { 21 | super.onCreate(savedInstanceState); 22 | setContentView(R.layout.activity_solution); 23 | ButterKnife.bind(this); 24 | CommonQuestion commonQuestion = (CommonQuestion) getIntent().getSerializableExtra(Constant.QUESTION); 25 | questionTxt.setText(commonQuestion.getQuestion()); 26 | solutionTxt.setText(" " + commonQuestion.getSolution()); 27 | getSupportActionBar().setTitle("问题解答"); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /app/src/main/java/cn/jk/kaoyandanci/ui/activity/WordListActivity.java: -------------------------------------------------------------------------------- 1 | package cn.jk.kaoyandanci.ui.activity; 2 | 3 | import android.os.Bundle; 4 | 5 | import com.tencent.cos.xml.utils.StringUtils; 6 | 7 | import cn.jk.kaoyandanci.R; 8 | import cn.jk.kaoyandanci.model.Queries; 9 | import cn.jk.kaoyandanci.util.Config; 10 | import cn.jk.kaoyandanci.util.Constant; 11 | 12 | public class WordListActivity extends BaseWordListActivity { 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | @Override 22 | protected void onCreate(Bundle savedInstanceState) { 23 | super.onCreate(savedInstanceState); 24 | String label = getIntent().getStringExtra(Constant.WORD_LIST_LBL); 25 | boolean coreMode = Config.coreModeIsOn(); 26 | boolean easyMode = Config.easyModeIsOn(); 27 | 28 | getSupportActionBar().setTitle(label); 29 | Queries queries = Queries.getInstance(daoSession); 30 | wordType = label.replaceAll("\\d", ""); 31 | String wordCountStr = label.replaceAll(wordType, ""); 32 | if (!StringUtils.isEmpty(wordCountStr)) { 33 | wordCount = Integer.valueOf(wordCountStr); 34 | } 35 | words = queries.getList(wordType, coreMode, easyMode); 36 | 37 | showWord(); 38 | } 39 | 40 | 41 | 42 | 43 | @Override 44 | int getContentViewId() { 45 | return R.layout.activity_word_list; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /app/src/main/java/cn/jk/kaoyandanci/ui/adapter/QuestionAdapter.java: -------------------------------------------------------------------------------- 1 | package cn.jk.kaoyandanci.ui.adapter; 2 | 3 | import android.content.Context; 4 | import android.content.Intent; 5 | import android.support.v7.widget.RecyclerView; 6 | import android.view.LayoutInflater; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | import android.widget.TextView; 10 | 11 | import java.util.List; 12 | 13 | import butterknife.BindView; 14 | import butterknife.ButterKnife; 15 | import cn.jk.kaoyandanci.R; 16 | import cn.jk.kaoyandanci.model.CommonQuestion; 17 | import cn.jk.kaoyandanci.ui.activity.SolutionActivity; 18 | import cn.jk.kaoyandanci.util.Constant; 19 | 20 | /** 21 | * Created by Administrator on 2017/6/30. 22 | */ 23 | 24 | public class QuestionAdapter extends RecyclerView.Adapter { 25 | 26 | List questions; 27 | Context context; 28 | 29 | public QuestionAdapter(List commonQuestions, Context context) { 30 | this.questions = commonQuestions; 31 | this.context = context; 32 | } 33 | 34 | @Override 35 | public QuestionAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 36 | // create a new view 37 | View v = LayoutInflater.from(parent.getContext()) 38 | .inflate(R.layout.layout_question, parent, false); 39 | 40 | return new ViewHolder(v); 41 | } 42 | 43 | @Override 44 | public void onBindViewHolder(QuestionAdapter.ViewHolder holder, int position) { 45 | final CommonQuestion commonQuestion = questions.get(position); 46 | holder.questionTxt.setText(commonQuestion.getQuestion()); 47 | ((View) holder.questionTxt.getParent()).setOnClickListener(new View.OnClickListener() { 48 | @Override 49 | public void onClick(View v) { 50 | Intent intent = new Intent(context, SolutionActivity.class); 51 | intent.putExtra(Constant.QUESTION, commonQuestion); 52 | context.startActivity(intent); 53 | } 54 | }); 55 | } 56 | 57 | @Override 58 | public int getItemCount() { 59 | return questions.size(); 60 | } 61 | 62 | public static class ViewHolder extends RecyclerView.ViewHolder { 63 | 64 | @BindView(R.id.questionTxt) 65 | TextView questionTxt; 66 | 67 | public ViewHolder(View itemView) { 68 | super(itemView); 69 | ButterKnife.bind(this, itemView); 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /app/src/main/java/cn/jk/kaoyandanci/ui/dialog/AddWordDialog.java: -------------------------------------------------------------------------------- 1 | package cn.jk.kaoyandanci.ui.dialog; 2 | 3 | import android.app.AlertDialog; 4 | import android.app.Dialog; 5 | import android.app.DialogFragment; 6 | import android.content.DialogInterface; 7 | import android.os.Bundle; 8 | import android.view.LayoutInflater; 9 | import android.view.View; 10 | import android.widget.EditText; 11 | 12 | import butterknife.BindView; 13 | import butterknife.ButterKnife; 14 | import cn.jk.kaoyandanci.R; 15 | import cn.jk.kaoyandanci.model.Word; 16 | import cn.jk.kaoyandanci.model.WordDao; 17 | import cn.jk.kaoyandanci.ui.activity.MyWordListActivity; 18 | import cn.jk.kaoyandanci.util.ToastUtil; 19 | 20 | /** 21 | * Created by jack on 2017/11/24. 22 | */ 23 | 24 | public class AddWordDialog extends DialogFragment { 25 | 26 | MyWordListActivity context; 27 | WordDao wordDao; 28 | @BindView(R.id.englishTxt) 29 | EditText englishTxt; 30 | @BindView(R.id.chineseTxt) 31 | EditText chineseTxt; 32 | 33 | 34 | @Override 35 | public Dialog onCreateDialog(Bundle savedInstanceState) { 36 | context = (MyWordListActivity) getActivity(); 37 | wordDao = context.getWordDao(); 38 | AlertDialog.Builder builder = new AlertDialog.Builder(context); 39 | // Get the layout inflater 40 | LayoutInflater inflater = getActivity().getLayoutInflater(); 41 | View view = inflater.inflate(R.layout.dialog_add_word, null); 42 | // Inflate and set the layout for the dialog 43 | // Pass null as the parent view because its going in the dialog layout 44 | builder.setView(view); 45 | 46 | builder.setPositiveButton(R.string.confirm, new DialogInterface.OnClickListener() { 47 | @Override 48 | public void onClick(DialogInterface dialog, int id) { 49 | addWord(); 50 | } 51 | }) 52 | .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { 53 | public void onClick(DialogInterface dialog, int id) { 54 | 55 | } 56 | }); 57 | ButterKnife.bind(this, view); 58 | //异步联网拿到中文.考完在做. 59 | // englishTxt.setOnFocusChangeListener(new View.OnFocusChangeListener() { 60 | // @Override 61 | // public void onFocusChange(View v, boolean hasFocus) { 62 | // String english = englishTxt.getText().toString(); 63 | // if (!hasFocus) { 64 | // 65 | // if (english == null || english.isEmpty()) { 66 | // return; 67 | // } 68 | // } 69 | // String queryUrl = Constant.cibaUrl + english.toLowerCase(); 70 | // JSONObject queryResult = new JSONObject(); 71 | // try { 72 | // queryResult = JsonReader.readJsonFromUrl(queryUrl); 73 | // queryResult 74 | // } catch (IOException e) { 75 | // e.printStackTrace(); 76 | // } catch (JSONException e) { 77 | // e.printStackTrace(); 78 | // } 79 | // } 80 | // }); 81 | return builder.create(); 82 | 83 | } 84 | 85 | private void addWord() { 86 | String english = englishTxt.getText().toString(); 87 | if (english == null || english.isEmpty()) { 88 | ToastUtil.showShort(context, "英文不能为空"); 89 | return; 90 | } 91 | boolean alreadyExist = (1 == wordDao.queryBuilder().where(WordDao.Properties.English.eq(english)).list().size()); 92 | if (alreadyExist) { 93 | ToastUtil.showShort(context, "单词表中已经有这个单词了"); 94 | return; 95 | } 96 | String chinese = chineseTxt.getText().toString(); 97 | if (chinese == null || chinese.isEmpty()) { 98 | ToastUtil.showShort(context, "中文不能为空"); 99 | return; 100 | } 101 | Word word = new Word(); 102 | word.setEnglish(english); 103 | word.setChinese(chinese); 104 | word.setCollect(1); 105 | word.setEasy(false); 106 | wordDao.insert(word); 107 | context.addWord(word); 108 | ToastUtil.showShort(context, "添加成功"); 109 | } 110 | 111 | 112 | } 113 | -------------------------------------------------------------------------------- /app/src/main/java/cn/jk/kaoyandanci/ui/dialog/ChoosePlanDialog.java: -------------------------------------------------------------------------------- 1 | package cn.jk.kaoyandanci.ui.dialog; 2 | 3 | import android.app.AlertDialog; 4 | import android.app.Dialog; 5 | import android.app.DialogFragment; 6 | import android.content.DialogInterface; 7 | import android.os.Bundle; 8 | import android.text.Editable; 9 | import android.text.TextWatcher; 10 | import android.view.LayoutInflater; 11 | import android.view.View; 12 | import android.widget.EditText; 13 | import android.widget.TextView; 14 | 15 | import java.util.Calendar; 16 | 17 | import butterknife.BindView; 18 | import butterknife.ButterKnife; 19 | import butterknife.OnTextChanged; 20 | import cn.jk.kaoyandanci.InitApplication; 21 | import cn.jk.kaoyandanci.R; 22 | import cn.jk.kaoyandanci.model.Queries; 23 | import cn.jk.kaoyandanci.model.WordDao; 24 | import cn.jk.kaoyandanci.ui.activity.MainActivity; 25 | import cn.jk.kaoyandanci.util.Config; 26 | import cn.jk.kaoyandanci.util.Constant; 27 | import cn.jk.kaoyandanci.util.DayUtil; 28 | import cn.jk.kaoyandanci.util.ToastUtil; 29 | 30 | /** 31 | * Created by Administrator on 2017/7/10. 32 | */ 33 | 34 | public class ChoosePlanDialog extends DialogFragment { 35 | @BindView(R.id.learnPerDayTxt) 36 | EditText learnPerDayTxt; 37 | @BindView(R.id.needDayTxt) 38 | EditText needDayTxt; 39 | @BindView(R.id.finishTimeTxt) 40 | TextView finishTimeTxt; 41 | MainActivity context; 42 | WordDao wordDao; 43 | //未掌握单词数目. 44 | int unGraspCount = 0; 45 | int learnPerDayRecord = -1; 46 | int needDayRecord = -1; 47 | 48 | @Override 49 | public Dialog onCreateDialog(Bundle savedInstanceState) { 50 | context = (MainActivity) getActivity(); 51 | wordDao = context.getWordDao(); 52 | AlertDialog.Builder builder = new AlertDialog.Builder(context); 53 | // Get the layout inflater 54 | LayoutInflater inflater = getActivity().getLayoutInflater(); 55 | View view = inflater.inflate(R.layout.dialog_plan_learn, null); 56 | // Inflate and set the layout for the dialog 57 | // Pass null as the parent view because its going in the dialog layout 58 | builder.setView(view); 59 | // Add action buttons 60 | builder.setPositiveButton(R.string.confirm, new DialogInterface.OnClickListener() { 61 | @Override 62 | public void onClick(DialogInterface dialog, int id) { 63 | Config.setPlanShouldLearn(learnPerDayTxt.getText().toString()); 64 | } 65 | }) 66 | .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { 67 | public void onClick(DialogInterface dialog, int id) { 68 | 69 | } 70 | }); 71 | ButterKnife.bind(this, view); 72 | 73 | 74 | boolean isCoreMode = Config.coreModeIsOn(); 75 | boolean isEasyMode = Config.easyModeIsOn(); 76 | 77 | Queries queries = Queries.getInstance(((InitApplication) getActivity().getApplication()).getDaoSession()); 78 | unGraspCount = queries.getList(Constant.NEED_LEARN, isCoreMode, isEasyMode).size(); 79 | 80 | int learnPerDay = Config.getPlanShouldLearn(); 81 | learnPerDayTxt.setText(String.valueOf(learnPerDay)); 82 | learnPerDayTxt.addTextChangedListener(new TextWatcher() { 83 | @Override 84 | public void beforeTextChanged(CharSequence s, int start, int count, int after) { 85 | 86 | } 87 | 88 | @Override 89 | public void onTextChanged(CharSequence s, int start, int before, int count) { 90 | 91 | } 92 | 93 | @Override 94 | public void afterTextChanged(Editable s) { 95 | 96 | } 97 | }); 98 | return builder.create(); 99 | } 100 | 101 | @OnTextChanged(R.id.learnPerDayTxt) 102 | void onLearnPerDayChange(CharSequence learnPerDayStr, int start, int count, int after) { 103 | 104 | if (learnPerDayStr == null || learnPerDayStr.toString().isEmpty()) { 105 | return; 106 | } 107 | int learnPerDay = Integer.valueOf(learnPerDayStr.toString()); 108 | if (learnPerDay <= 0) { 109 | ToastUtil.showShort(context, "每天学习单词数目不能小于1"); 110 | return; 111 | } 112 | if (learnPerDay == learnPerDayRecord) { 113 | return; 114 | } 115 | int needDay = unGraspCount / learnPerDay + 1; 116 | 117 | needDayRecord = needDay; 118 | learnPerDayRecord = learnPerDay; 119 | 120 | needDayTxt.setText(String.valueOf(needDay)); 121 | Calendar calendar = Calendar.getInstance(); 122 | calendar.add(Calendar.DAY_OF_MONTH, needDay); 123 | finishTimeTxt.setText(DayUtil.getFormatDate(calendar)); 124 | 125 | } 126 | 127 | @OnTextChanged(R.id.needDayTxt) 128 | void onNeedDayTxtChanged(CharSequence needDayStr, int start, int count, int after) { 129 | if (needDayStr == null || needDayStr.toString().isEmpty()) { 130 | return; 131 | } 132 | int needDay = Integer.valueOf(needDayStr.toString()); 133 | if (needDay == needDayRecord) { 134 | return; 135 | } 136 | if (needDay < 0) { 137 | ToastUtil.showShort(context, "学习天数不能小于0"); 138 | return; 139 | } 140 | 141 | int learnPerDay = unGraspCount / needDay + 1; 142 | 143 | needDayRecord = needDay; 144 | learnPerDayRecord = learnPerDay; 145 | } 146 | } -------------------------------------------------------------------------------- /app/src/main/java/cn/jk/kaoyandanci/ui/dialog/DownloadDialog.java: -------------------------------------------------------------------------------- 1 | package cn.jk.kaoyandanci.ui.dialog; 2 | 3 | import android.app.Dialog; 4 | import android.app.DialogFragment; 5 | import android.app.ProgressDialog; 6 | import android.content.DialogInterface; 7 | import android.os.AsyncTask; 8 | import android.os.Bundle; 9 | 10 | import cn.jk.kaoyandanci.R; 11 | 12 | /** 13 | * Created by Administrator on 2017/7/22. 14 | */ 15 | 16 | public class DownloadDialog extends DialogFragment { 17 | 18 | public ProgressDialog progressDialog; 19 | private AsyncTask asyncTask; 20 | 21 | @Override 22 | public Dialog onCreateDialog(Bundle savedInstanceState) { 23 | progressDialog = new ProgressDialog(getActivity()); 24 | progressDialog.setMessage("下载语音包中"); 25 | progressDialog.setCancelable(true); 26 | progressDialog.setMax(100); 27 | 28 | return progressDialog; 29 | } 30 | 31 | public void setTask(AsyncTask asyncTask) { 32 | this.asyncTask = asyncTask; 33 | } 34 | 35 | public void setProgress(int progress) { 36 | if (progress == 99) { 37 | progressDialog.setMessage(getString(R.string.unziping)); 38 | } else { 39 | progressDialog.setMessage("下载语音包中" + progress + "/100"); 40 | } 41 | } 42 | 43 | @Override 44 | public void onDismiss(final DialogInterface dialog) { 45 | super.onDismiss(dialog); 46 | asyncTask.cancel(true); 47 | } 48 | 49 | 50 | public void setMessage(String s) { 51 | progressDialog.setMessage(s); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /app/src/main/java/cn/jk/kaoyandanci/ui/dialog/NeverShowWordDialog.java: -------------------------------------------------------------------------------- 1 | package cn.jk.kaoyandanci.ui.dialog; 2 | 3 | import android.app.AlertDialog; 4 | import android.app.Dialog; 5 | import android.app.DialogFragment; 6 | import android.content.DialogInterface; 7 | import android.os.Bundle; 8 | 9 | import cn.jk.kaoyandanci.R; 10 | import cn.jk.kaoyandanci.ui.activity.LearnWordActivity; 11 | 12 | /** 13 | * Created by Administrator on 2017/6/23. 14 | */ 15 | 16 | public class NeverShowWordDialog extends DialogFragment { 17 | 18 | @Override 19 | public Dialog onCreateDialog(Bundle savedInstanceState) { 20 | // Use the Builder class for convenient dialog construction 21 | AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); 22 | builder.setMessage(R.string.tips_never_show) 23 | .setPositiveButton(R.string.confirm_never_show, new DialogInterface.OnClickListener() { 24 | public void onClick(DialogInterface dialog, int id) { 25 | ((LearnWordActivity) getActivity()).currentNeverShow(); 26 | } 27 | }) 28 | .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { 29 | public void onClick(DialogInterface dialog, int id) { 30 | // User cancelled the dialog 31 | } 32 | }); 33 | // Create the AlertDialog object and return it 34 | return builder.create(); 35 | } 36 | } -------------------------------------------------------------------------------- /app/src/main/java/cn/jk/kaoyandanci/ui/dialog/PleaseDonateDialog.java: -------------------------------------------------------------------------------- 1 | package cn.jk.kaoyandanci.ui.dialog; 2 | 3 | import android.app.AlertDialog; 4 | import android.app.Dialog; 5 | import android.app.DialogFragment; 6 | import android.content.DialogInterface; 7 | import android.os.Bundle; 8 | 9 | import cn.jk.kaoyandanci.R; 10 | import cn.jk.kaoyandanci.ui.fragment.AdvanceSettingFragment; 11 | 12 | /** 13 | * Created by Administrator on 2017/6/29. 14 | */ 15 | 16 | public class PleaseDonateDialog extends DialogFragment { 17 | 18 | @Override 19 | public Dialog onCreateDialog(Bundle savedInstanceState) { 20 | // Use the Builder class for convenient dialog construction 21 | AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); 22 | builder.setMessage(R.string.pleaseDonate) 23 | .setPositiveButton(R.string.confirm_use_voice_pack, new DialogInterface.OnClickListener() { 24 | public void onClick(DialogInterface dialog, int id) { 25 | AdvanceSettingFragment fragment = (AdvanceSettingFragment) getActivity().getFragmentManager().findFragmentById(R.id.content_frames); 26 | fragment.startDownload(); 27 | } 28 | }) 29 | .setNegativeButton(R.string.cancel_use_voice_pack, new DialogInterface.OnClickListener() { 30 | public void onClick(DialogInterface dialog, int id) { 31 | // User cancelled the dialog 32 | } 33 | }); 34 | // Create the AlertDialog object and return it 35 | return builder.create(); 36 | } 37 | } -------------------------------------------------------------------------------- /app/src/main/java/cn/jk/kaoyandanci/ui/dialog/WebSearchTipDialog.java: -------------------------------------------------------------------------------- 1 | package cn.jk.kaoyandanci.ui.dialog; 2 | 3 | import android.app.AlertDialog; 4 | import android.app.Dialog; 5 | import android.app.DialogFragment; 6 | import android.content.DialogInterface; 7 | import android.os.Bundle; 8 | 9 | import cn.jk.kaoyandanci.R; 10 | import cn.jk.kaoyandanci.util.Config; 11 | 12 | /** 13 | * Created by Administrator on 2017/6/29. 14 | */ 15 | 16 | public class WebSearchTipDialog extends DialogFragment { 17 | 18 | @Override 19 | public Dialog onCreateDialog(Bundle savedInstanceState) { 20 | // Use the Builder class for convenient dialog construction 21 | AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); 22 | builder.setMessage(R.string.searchTips) 23 | .setPositiveButton(R.string.confirm, new DialogInterface.OnClickListener() { 24 | public void onClick(DialogInterface dialog, int id) { 25 | Config.setSearchTipShow(false); 26 | } 27 | }) 28 | .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { 29 | public void onClick(DialogInterface dialog, int id) { 30 | // User cancelled the dialog 31 | } 32 | }); 33 | // Create the AlertDialog object and return it 34 | return builder.create(); 35 | } 36 | } -------------------------------------------------------------------------------- /app/src/main/java/cn/jk/kaoyandanci/ui/fragment/Intro1Fragment.java: -------------------------------------------------------------------------------- 1 | package cn.jk.kaoyandanci.ui.fragment; 2 | 3 | 4 | import android.os.Bundle; 5 | import android.support.v4.app.Fragment; 6 | import android.view.LayoutInflater; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | 10 | import cn.jk.kaoyandanci.R; 11 | 12 | /** 13 | * A simple {@link Fragment} subclass. 14 | */ 15 | public class Intro1Fragment extends Fragment { 16 | 17 | 18 | public Intro1Fragment() { 19 | // Required empty public constructor 20 | } 21 | 22 | 23 | @Override 24 | public View onCreateView(LayoutInflater inflater, ViewGroup container, 25 | Bundle savedInstanceState) { 26 | // Inflate the layout for this fragment 27 | return inflater.inflate(R.layout.fragment_intro1, container, false); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /app/src/main/java/cn/jk/kaoyandanci/ui/fragment/Intro2Fragment.java: -------------------------------------------------------------------------------- 1 | package cn.jk.kaoyandanci.ui.fragment; 2 | 3 | 4 | import android.os.Bundle; 5 | import android.support.v4.app.Fragment; 6 | import android.view.LayoutInflater; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | 10 | import cn.jk.kaoyandanci.R; 11 | 12 | /** 13 | * A simple {@link Fragment} subclass. 14 | */ 15 | public class Intro2Fragment extends Fragment { 16 | 17 | 18 | public Intro2Fragment() { 19 | // Required empty public constructor 20 | } 21 | 22 | 23 | @Override 24 | public View onCreateView(LayoutInflater inflater, ViewGroup container, 25 | Bundle savedInstanceState) { 26 | // Inflate the layout for this fragment 27 | return inflater.inflate(R.layout.fragment_intro2, container, false); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /app/src/main/java/cn/jk/kaoyandanci/ui/fragment/Intro3Fragment.java: -------------------------------------------------------------------------------- 1 | package cn.jk.kaoyandanci.ui.fragment; 2 | 3 | 4 | import android.os.Bundle; 5 | import android.support.v4.app.Fragment; 6 | import android.view.LayoutInflater; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | 10 | import cn.jk.kaoyandanci.R; 11 | 12 | /** 13 | * A simple {@link Fragment} subclass. 14 | */ 15 | public class Intro3Fragment extends Fragment { 16 | 17 | 18 | public Intro3Fragment() { 19 | // Required empty public constructor 20 | } 21 | 22 | 23 | @Override 24 | public View onCreateView(LayoutInflater inflater, ViewGroup container, 25 | Bundle savedInstanceState) { 26 | // Inflate the layout for this fragment 27 | return inflater.inflate(R.layout.fragment_intro3, container, false); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /app/src/main/java/cn/jk/kaoyandanci/ui/fragment/SettingFragment.java: -------------------------------------------------------------------------------- 1 | package cn.jk.kaoyandanci.ui.fragment; 2 | 3 | 4 | import android.app.Fragment; 5 | import android.content.Intent; 6 | import android.os.Bundle; 7 | import android.preference.Preference; 8 | import android.preference.PreferenceFragment; 9 | import android.preference.SwitchPreference; 10 | 11 | import com.afollestad.aesthetic.Aesthetic; 12 | 13 | import cn.jk.kaoyandanci.R; 14 | import cn.jk.kaoyandanci.ui.activity.AboutActivity; 15 | import cn.jk.kaoyandanci.ui.activity.DisplaySettingActivity; 16 | import cn.jk.kaoyandanci.ui.activity.MainActivity; 17 | import cn.jk.kaoyandanci.ui.activity.MyWordListActivity; 18 | import cn.jk.kaoyandanci.ui.dialog.ChoosePlanDialog; 19 | import cn.jk.kaoyandanci.util.Constant; 20 | 21 | /** 22 | * A simple {@link Fragment} subclass. 23 | */ 24 | public class SettingFragment extends PreferenceFragment { 25 | 26 | 27 | public SettingFragment() { 28 | // Required empty public constructor 29 | } 30 | 31 | 32 | // @Override 33 | // public View onCreateView(LayoutInflater inflater, ViewGroup container, 34 | // Bundle savedInstanceState) { 35 | // 36 | // return inflater.inflate(R.layout.fragment_setting, container, false); 37 | // } 38 | @Override 39 | public void onCreate(Bundle savedInstanceState) { 40 | super.onCreate(savedInstanceState); 41 | 42 | addPreferencesFromResource(R.xml.setting); 43 | SwitchPreference darkThemPreference = (SwitchPreference) findPreference(getActivity().getString(R.string.dark_theme_on)); 44 | darkThemPreference.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { 45 | @Override 46 | public boolean onPreferenceChange(Preference preference, Object o) { 47 | boolean darkThemeOn = (boolean) o; 48 | if (darkThemeOn) { 49 | Aesthetic.get() 50 | .activityTheme(R.style.AppThemeDark_ActionBar) 51 | .isDark(true) 52 | .textColorPrimaryRes(R.color.text_color_primary_dark) 53 | .textColorSecondaryRes(R.color.text_color_secondary_dark) 54 | .apply(); 55 | } else { 56 | Aesthetic.get() 57 | .activityTheme(R.style.AppTheme_ActionBar) 58 | .isDark(false) 59 | .textColorPrimaryRes(R.color.text_color_primary) 60 | .textColorSecondaryRes(R.color.text_color_secondary) 61 | .apply(); 62 | } 63 | return true; 64 | } 65 | }); 66 | 67 | 68 | Preference displaySetPref = findPreference(Constant.DISPLAY_SETTING); 69 | displaySetPref.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { 70 | @Override 71 | public boolean onPreferenceClick(Preference preference) { 72 | startActivity(new Intent(getActivity(), DisplaySettingActivity.class)); 73 | return false; 74 | } 75 | }); 76 | Preference planLearnPref = findPreference(getString(R.string.should_learn)); 77 | planLearnPref.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { 78 | @Override 79 | public boolean onPreferenceClick(Preference preference) { 80 | new ChoosePlanDialog().show(getFragmentManager(), "choosePlan"); 81 | 82 | return false; 83 | } 84 | }); 85 | Preference aboutPref = findPreference(getString(R.string.about_app)); 86 | aboutPref.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { 87 | @Override 88 | public boolean onPreferenceClick(Preference preference) { 89 | startActivity(new Intent(getActivity(), AboutActivity.class)); 90 | return false; 91 | } 92 | }); 93 | Preference myWordPref = findPreference(getString(R.string.my_word_list)); 94 | myWordPref.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { 95 | @Override 96 | public boolean onPreferenceClick(Preference preference) { 97 | startActivity(new Intent(getActivity(), MyWordListActivity.class)); 98 | return false; 99 | } 100 | }); 101 | Preference advanceSettingPref = findPreference(getString(R.string.advance_setting)); 102 | advanceSettingPref.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { 103 | @Override 104 | public boolean onPreferenceClick(Preference preference) { 105 | ((MainActivity) getActivity()).startAdvancedSettingActivityWithPermissionCheck(); 106 | return false; 107 | } 108 | }); 109 | 110 | 111 | } 112 | 113 | 114 | } 115 | -------------------------------------------------------------------------------- /app/src/main/java/cn/jk/kaoyandanci/ui/preference/ColorPickerPreference.java: -------------------------------------------------------------------------------- 1 | package cn.jk.kaoyandanci.ui.preference; 2 | 3 | import android.content.Context; 4 | import android.preference.Preference; 5 | import android.util.AttributeSet; 6 | import android.view.View; 7 | import android.widget.ImageView; 8 | 9 | import com.afollestad.aesthetic.Aesthetic; 10 | 11 | import cn.jk.kaoyandanci.R; 12 | import io.reactivex.Observable; 13 | import io.reactivex.annotations.NonNull; 14 | import io.reactivex.functions.Consumer; 15 | 16 | /** 17 | * Created by Administrator on 2017/7/2. 18 | */ 19 | 20 | public class ColorPickerPreference extends Preference { 21 | 22 | ImageView imageView; 23 | 24 | public ColorPickerPreference(Context context) { 25 | this(context, null, 0); 26 | init(context, null); 27 | } 28 | 29 | public ColorPickerPreference(Context context, AttributeSet attrs) { 30 | this(context, attrs, 0); 31 | init(context, attrs); 32 | } 33 | 34 | public ColorPickerPreference(Context context, AttributeSet attrs, int defStyleAttr) { 35 | super(context, attrs, defStyleAttr); 36 | init(context, attrs); 37 | 38 | } 39 | 40 | private void init(Context context, AttributeSet attrs) { 41 | setLayoutResource(R.layout.ate_preference_custom); 42 | setWidgetLayoutResource(R.layout.ate_preference_widget); 43 | setPersistent(false); 44 | 45 | } 46 | 47 | public void setColor(int color) { 48 | imageView.setBackgroundColor(color); 49 | } 50 | 51 | @Override 52 | protected void onBindView(View view) { 53 | super.onBindView(view); 54 | String key = getKey(); 55 | Context context = getContext(); 56 | String primaryKey = context.getString(R.string.primary_color_key); 57 | String accentKey = context.getString(R.string.accent_color_key); 58 | String textPrimaryKey = context.getString(R.string.text_primary_color_key); 59 | String textSecondKey = context.getString(R.string.text_second_color_key); 60 | imageView = (ImageView) view.findViewById(R.id.circle); 61 | Observable color = Aesthetic.get().colorPrimary(); 62 | if (key.equals(primaryKey)) { 63 | color = Aesthetic.get().colorPrimary(); 64 | } else if (key.equals(accentKey)) { 65 | color = Aesthetic.get().colorAccent(); 66 | } else if (key.equals(textPrimaryKey)) { 67 | color = Aesthetic.get().textColorPrimary(); 68 | } else if (key.equals(textSecondKey)) { 69 | color = Aesthetic.get().textColorSecondary(); 70 | } 71 | color.take(1).subscribe(new Consumer() { 72 | @Override 73 | public void accept(@NonNull Integer integer) throws Exception { 74 | imageView.setBackgroundColor(integer); 75 | 76 | } 77 | }); 78 | } 79 | 80 | } -------------------------------------------------------------------------------- /app/src/main/java/cn/jk/kaoyandanci/ui/preference/DatePreference.java: -------------------------------------------------------------------------------- 1 | package cn.jk.kaoyandanci.ui.preference; 2 | 3 | import android.content.Context; 4 | import android.content.res.TypedArray; 5 | import android.preference.DialogPreference; 6 | import android.util.AttributeSet; 7 | import android.view.View; 8 | import android.widget.DatePicker; 9 | 10 | import java.text.SimpleDateFormat; 11 | import java.util.Calendar; 12 | 13 | public class DatePreference extends DialogPreference { 14 | private int lastDate = 0; 15 | private int lastMonth = 0; 16 | private int lastYear = 0; 17 | private String dateValue; 18 | private CharSequence mSummary; 19 | private DatePicker picker = null; 20 | 21 | public DatePreference(Context context, AttributeSet attrs) { 22 | super(context, attrs); 23 | 24 | setPositiveButtonText("应用"); 25 | setNegativeButtonText("取消"); 26 | } 27 | 28 | public static int getYear(String dateval) { 29 | String[] pieces = dateval.split("-"); 30 | return (Integer.parseInt(pieces[0])); 31 | } 32 | 33 | public static int getMonth(String dateval) { 34 | String[] pieces = dateval.split("-"); 35 | return (Integer.parseInt(pieces[1])); 36 | } 37 | 38 | public static int getDate(String dateval) { 39 | String[] pieces = dateval.split("-"); 40 | return (Integer.parseInt(pieces[2])); 41 | } 42 | 43 | @Override 44 | protected View onCreateDialogView() { 45 | picker = new DatePicker(getContext()); 46 | return (picker); 47 | } 48 | 49 | @Override 50 | protected void onBindDialogView(View v) { 51 | super.onBindDialogView(v); 52 | 53 | picker.updateDate(lastYear, lastMonth - 1, lastDate); 54 | } 55 | 56 | @Override 57 | protected void onDialogClosed(boolean positiveResult) { 58 | super.onDialogClosed(positiveResult); 59 | 60 | if (positiveResult) { 61 | lastYear = picker.getYear(); 62 | lastMonth = picker.getMonth() + 1; 63 | lastDate = picker.getDayOfMonth(); 64 | 65 | String dateval = String.valueOf(lastYear) + "-" 66 | + String.valueOf(lastMonth) + "-" 67 | + String.valueOf(lastDate); 68 | 69 | if (callChangeListener(dateval)) { 70 | persistString(dateval); 71 | } 72 | } 73 | } 74 | 75 | @Override 76 | protected Object onGetDefaultValue(TypedArray a, int index) { 77 | return (a.getString(index)); 78 | } 79 | 80 | @Override 81 | protected void onSetInitialValue(boolean restoreValue, Object defaultValue) { 82 | dateValue = null; 83 | 84 | if (restoreValue) { 85 | if (defaultValue == null) { 86 | Calendar cal = Calendar.getInstance(); 87 | SimpleDateFormat format1 = new SimpleDateFormat("yyyy-MM-dd"); 88 | String formatted = format1.format(cal.getTime()); 89 | dateValue = getPersistedString(formatted); 90 | } else { 91 | dateValue = getPersistedString(defaultValue.toString()); 92 | } 93 | } else { 94 | dateValue = defaultValue.toString(); 95 | } 96 | lastYear = getYear(dateValue); 97 | lastMonth = getMonth(dateValue); 98 | lastDate = getDate(dateValue); 99 | } 100 | 101 | public String getText() { 102 | return dateValue; 103 | } 104 | 105 | public void setText(String text) { 106 | final boolean wasBlocking = shouldDisableDependents(); 107 | 108 | dateValue = text; 109 | 110 | persistString(text); 111 | 112 | final boolean isBlocking = shouldDisableDependents(); 113 | if (isBlocking != wasBlocking) { 114 | notifyDependencyChange(isBlocking); 115 | } 116 | } 117 | 118 | public CharSequence getSummary() { 119 | return mSummary; 120 | } 121 | 122 | public void setSummary(CharSequence summary) { 123 | if (summary == null && mSummary != null || summary != null 124 | && !summary.equals(mSummary)) { 125 | mSummary = summary; 126 | notifyChanged(); 127 | } 128 | } 129 | } -------------------------------------------------------------------------------- /app/src/main/java/cn/jk/kaoyandanci/util/AssetsUtil.java: -------------------------------------------------------------------------------- 1 | package cn.jk.kaoyandanci.util; 2 | 3 | import android.content.Context; 4 | 5 | import com.google.gson.Gson; 6 | import com.google.gson.reflect.TypeToken; 7 | 8 | import java.io.IOException; 9 | import java.io.InputStream; 10 | import java.lang.reflect.Type; 11 | import java.util.List; 12 | 13 | import cn.jk.kaoyandanci.model.CommonQuestion; 14 | 15 | 16 | /** 17 | * Created by Administrator on 2017/4/20. 18 | */ 19 | 20 | public class AssetsUtil { 21 | public static String loadStringFromAsset(String fileName, Context context) { 22 | String json; 23 | try { 24 | InputStream is = context.getAssets().open(fileName); 25 | json = FileUtil.streamToString(is); 26 | } catch (IOException ex) { 27 | ex.printStackTrace(); 28 | return null; 29 | } 30 | return json; 31 | } 32 | 33 | public static List loadCardFromFile(Context context, String filePath) { 34 | String allCollectibleCard = loadStringFromAsset(filePath, context); 35 | Type typeOfListOfFoo = new TypeToken>() { 36 | }.getType(); 37 | List jsonObjectList = new Gson().fromJson(allCollectibleCard, typeOfListOfFoo); 38 | return jsonObjectList; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /app/src/main/java/cn/jk/kaoyandanci/util/ChineseCheck.java: -------------------------------------------------------------------------------- 1 | package cn.jk.kaoyandanci.util; 2 | 3 | import java.util.regex.Matcher; 4 | import java.util.regex.Pattern; 5 | 6 | /** 7 | * Created by Administrator on 2017/6/27. 8 | */ 9 | 10 | public class ChineseCheck { 11 | static String regEx = "[\u4e00-\u9fa5]"; 12 | static Pattern pat = Pattern.compile(regEx); 13 | 14 | public static boolean containChinese(String str) { 15 | Matcher matcher = pat.matcher(str); 16 | boolean flg = false; 17 | if (matcher.find()) { 18 | flg = true; 19 | } 20 | return flg; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /app/src/main/java/cn/jk/kaoyandanci/util/ColorUtil.java: -------------------------------------------------------------------------------- 1 | package cn.jk.kaoyandanci.util; 2 | 3 | import android.content.res.ColorStateList; 4 | import android.graphics.PorterDuff; 5 | import android.os.Build; 6 | import android.widget.ProgressBar; 7 | 8 | /** 9 | * Created by Administrator on 2017/7/11. 10 | */ 11 | 12 | public class ColorUtil { 13 | 14 | public static void setColor(ProgressBar progressBar, int color, boolean skipIndeterminate) { 15 | ColorStateList sl = ColorStateList.valueOf(color); 16 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 17 | progressBar.setProgressTintList(sl); 18 | progressBar.setSecondaryProgressTintList(sl); 19 | if (!skipIndeterminate) { 20 | progressBar.setIndeterminateTintList(sl); 21 | } 22 | } else { 23 | PorterDuff.Mode mode = PorterDuff.Mode.SRC_IN; 24 | if (!skipIndeterminate && progressBar.getIndeterminateDrawable() != null) { 25 | progressBar.getIndeterminateDrawable().setColorFilter(color, mode); 26 | } 27 | if (progressBar.getProgressDrawable() != null) { 28 | progressBar.getProgressDrawable().setColorFilter(color, mode); 29 | } 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /app/src/main/java/cn/jk/kaoyandanci/util/Constant.java: -------------------------------------------------------------------------------- 1 | package cn.jk.kaoyandanci.util; 2 | 3 | /** 4 | * Created by Administrator on 2017/4/13. 5 | */ 6 | 7 | public class Constant { 8 | 9 | 10 | public static final String SERVER_URL = "http://123.206.13.73/kydc/"; 11 | 12 | public static final String FEEDBACK_URL = SERVER_URL + "feedback/add"; 13 | public static final String ADD_EASY_WORD_URL = SERVER_URL + "easyWord/add"; 14 | 15 | public static final String MODE = "mode"; 16 | 17 | public static final String REVIEW_DATE = "REVIEW_DATE"; 18 | 19 | 20 | public static final String REVIEW_MODE = "review"; 21 | public static final String LEARN_MODE = "learn"; 22 | public static final String EXAM_DATE = "examDate"; 23 | public static final String DATABASE_NAME = "word.db"; 24 | public static final String ENGLISH = "english"; 25 | public static final String TIPS_OF_NEVER_SHOW = "TIPS_OF_NEVER_SHOW"; 26 | public static final String AUTO_DISPLAY = "autoDisplay"; 27 | public static final String PIE_WORD = "pieWord"; 28 | public static final String QUESTION = "QUESTION"; 29 | public static final String youdaoVoiceUrl = "http://dict.youdao.com//dictvoice?type=2&audio="; 30 | public static final String shanbeiVoiceUrl = "https://media.shanbay.com/audio/us/"; 31 | public static String cibaUrl= "http://dict-co.iciba.com/api/dictionary.php?key=AA6C7429C3884C9E766C51187BD1D86F&type=json&w="; 32 | public static final String PLAN_LEARN = "shouldLearn"; 33 | public static final String SHOULD_SHOW_SETTING_FRAGMENT = "SHOULD_SHOW_SETTING_FRAGMENT"; 34 | public static final String COMMON_QUESTION = "commonQuestion"; 35 | public static final String DISPLAY_SETTING = "displaySetting"; 36 | public static final String AUTO_REVIEW_MODE = "AUTO_REVIEW_MODE"; 37 | public static final String ENGLISH_FILE_DIR = "/Android/data/cn.jk.kaoyandanci/cache/video-cache"; 38 | public static final String ENGLISH_ZIP_PATH = ENGLISH_FILE_DIR + "/english.zip"; 39 | public static final String VOICE_PACK_MD5 = "e11f8c98076f134da51fe22b2262dd85";//TODO; 40 | public static final String GUID = "GUID"; 41 | public static final String PROJECT_ID = "kydc"; 42 | public static final Object DEFAULT_GUID = "DEFAULT_GUID"; 43 | public static final String SMART_REVIEW_TIP = "SMART_REVIEW_TIP"; 44 | public static final String NEVER_SHOW = "已掌握"; 45 | public static final String KNOWED = "已认识"; 46 | public static final String UNKNOWN = "不认识"; 47 | public static final String NOT_LEARNED = "未学习"; 48 | 49 | public static final String WORD_LIST_LBL = "WORD_LIST_LBL"; 50 | public static final String WORD_LIST= "WORD_LIST"; 51 | public static final String[] ENCOURAGE_SENTENCE = {"敢想不敢为者,终困身牢笼", "想要和得到 ,中间还有两个字,就是做到", 52 | "又怎会晓得执着的人 拥有隐形翅膀", "若一去不回,便一去不回", "大丈夫当提三尺剑,立不世功", 53 | "夫学须静也,才须学也,非学无以广才,非志无以成学", "时人不识凌云木,直待凌云始道高", 54 | "What hurts more, the pain of hard work or the pain of regret ? ", "All things come to those who wait", 55 | "Nothing is impossible!", "Keep on going never give up", "Nothing for nothing. ", 56 | "What is the man's first duty? The answer is brief: to be himself. " 57 | , "要努力 要奋斗.:<"}; 58 | public static final String QUERY_SQL = "querySql"; 59 | public static final String TITLE = "TITLE"; 60 | public static final String QUERY_BUILDER = "QUERY_BUILDER"; 61 | public static final String EASY ="easy" ; 62 | public static final String SHOW_CHINESE_LIST = "SHOW_CHINESE_LIST"; 63 | public static final String NEED_LEARN = "NEED_LEARN"; 64 | 65 | public static String FIRST_OPEN = "firstOpen"; 66 | 67 | public static int nextDelay = 1500; 68 | public static int allWordCount = 5492; 69 | public static int PLAN_LEARN_NO = 10; 70 | public static String youdaoWordPageUrl = "https://m.youdao.com/dict?le=eng&q="; 71 | public static String cibaWordPageUrl = "https://m.iciba.com/"; 72 | public static String kesilinPageUrl="https://www.collinsdictionary.com/zh/dictionary/english/"; 73 | public static String searchTipShow = "searchTipShow"; 74 | public static String shouldShowGuide = "shouldShowGuide"; 75 | public static String downloadVoicePackUrl = "https://kydc-1253381140.costj.myqcloud.com/english.zip"; 76 | 77 | 78 | 79 | 80 | } 81 | -------------------------------------------------------------------------------- /app/src/main/java/cn/jk/kaoyandanci/util/DateLongGson.java: -------------------------------------------------------------------------------- 1 | package cn.jk.kaoyandanci.util; 2 | 3 | import com.google.gson.Gson; 4 | import com.google.gson.GsonBuilder; 5 | import com.google.gson.JsonDeserializationContext; 6 | import com.google.gson.JsonDeserializer; 7 | import com.google.gson.JsonElement; 8 | import com.google.gson.JsonParseException; 9 | import com.google.gson.JsonPrimitive; 10 | import com.google.gson.JsonSerializationContext; 11 | import com.google.gson.JsonSerializer; 12 | 13 | import java.lang.reflect.Type; 14 | import java.util.Date; 15 | 16 | /** 17 | *
18 |  *     author : jiakang
19 |  *     e-mail : 1079153785@qq.com
20 |  *     time   : 2018/07/29
21 |  *     desc   :
22 |  *     version: 1.0
23 |  * 
24 | */ 25 | public class DateLongGson { 26 | static JsonSerializer ser = new JsonSerializer() { 27 | @Override 28 | public JsonElement serialize(Date src, Type typeOfSrc, JsonSerializationContext 29 | context) { 30 | return src == null ? null : new JsonPrimitive(src.getTime()); 31 | } 32 | }; 33 | 34 | static JsonDeserializer deser = new JsonDeserializer() { 35 | @Override 36 | public Date deserialize(JsonElement json, Type typeOfT, 37 | JsonDeserializationContext context) throws JsonParseException { 38 | return json == null ? null : new Date(json.getAsLong()); 39 | } 40 | }; 41 | 42 | public static Gson gson = new GsonBuilder() 43 | .registerTypeAdapter(Date.class, ser) 44 | .registerTypeAdapter(Date.class, deser).create(); 45 | } 46 | -------------------------------------------------------------------------------- /app/src/main/java/cn/jk/kaoyandanci/util/DayUtil.java: -------------------------------------------------------------------------------- 1 | package cn.jk.kaoyandanci.util; 2 | 3 | import java.text.SimpleDateFormat; 4 | import java.util.Calendar; 5 | import java.util.Date; 6 | 7 | /** 8 | * Created by Administrator on 2017/6/12. 9 | */ 10 | 11 | public class DayUtil { 12 | public static Date getEndOfDay(Date date) { 13 | Calendar calendar = Calendar.getInstance(); 14 | calendar.setTime(date); 15 | calendar.set(Calendar.HOUR_OF_DAY, 23); 16 | calendar.set(Calendar.MINUTE, 59); 17 | calendar.set(Calendar.SECOND, 59); 18 | calendar.set(Calendar.MILLISECOND, 999); 19 | return calendar.getTime(); 20 | } 21 | 22 | public static Date getStartOfDay(Date date) { 23 | Calendar calendar = Calendar.getInstance(); 24 | calendar.setTime(date); 25 | calendar.set(Calendar.HOUR_OF_DAY, 0); 26 | calendar.set(Calendar.MINUTE, 0); 27 | calendar.set(Calendar.SECOND, 0); 28 | calendar.set(Calendar.MILLISECOND, 0); 29 | return calendar.getTime(); 30 | } 31 | 32 | public static Date getStartOfYesterday() { 33 | final Calendar cal = Calendar.getInstance(); 34 | cal.add(Calendar.DATE, -1); 35 | Date yesterday = cal.getTime(); 36 | return getStartOfDay(yesterday); 37 | } 38 | 39 | public static Date getEndOfYesterday() { 40 | final Calendar cal = Calendar.getInstance(); 41 | cal.add(Calendar.DATE, -1); 42 | Date yesterday = cal.getTime(); 43 | return getEndOfDay(yesterday); 44 | } 45 | 46 | public static String getFormatDate(Calendar calendar) { 47 | SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm"); 48 | return simpleDateFormat.format(calendar.getTime()); 49 | } 50 | 51 | public static Date getFirstDayOfMonth(int year, int month) { 52 | Calendar calendar = Calendar.getInstance(); 53 | calendar.set(Calendar.YEAR, year); 54 | calendar.set(Calendar.MONTH, month); 55 | calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMinimum(Calendar.DAY_OF_MONTH)); 56 | return calendar.getTime(); 57 | } 58 | 59 | public static Date getLastDayOfMonth(int year, int month) { 60 | Calendar calendar = Calendar.getInstance(); 61 | calendar.set(Calendar.YEAR, year); 62 | calendar.set(Calendar.MONTH, month); 63 | calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DAY_OF_MONTH)); 64 | calendar.set(Calendar.HOUR_OF_DAY, 23); 65 | calendar.set(Calendar.MINUTE, 59); 66 | calendar.set(Calendar.SECOND, 59); 67 | 68 | return calendar.getTime(); 69 | } 70 | 71 | public static final String formatDay(Date date) { 72 | return new SimpleDateFormat("yyyy-MM-dd").format(date); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /app/src/main/java/cn/jk/kaoyandanci/util/EmptyNetListener.java: -------------------------------------------------------------------------------- 1 | package cn.jk.kaoyandanci.util; 2 | 3 | import com.android.volley.Response; 4 | import com.android.volley.VolleyError; 5 | 6 | /** 7 | * Created by Administrator on 2017/7/22. 8 | */ 9 | 10 | public class EmptyNetListener { 11 | public static Response.Listener emptyResponseListener = new Response.Listener() { 12 | @Override 13 | public void onResponse(String response) { 14 | } 15 | }; 16 | public static Response.ErrorListener emptyErrorListener = new Response.ErrorListener() { 17 | @Override 18 | public void onErrorResponse(VolleyError error) { 19 | } 20 | }; 21 | 22 | } 23 | -------------------------------------------------------------------------------- /app/src/main/java/cn/jk/kaoyandanci/util/JsonReader.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | * @(#) JsonReader.java 4 | * @Package cn.jk.EnglishUtil 5 | * 6 | * Copyright © SingleWindow Corporation. All rights reserved. 7 | * 8 | */ 9 | 10 | package cn.jk.kaoyandanci.util; 11 | 12 | import java.io.BufferedReader; 13 | import java.io.IOException; 14 | import java.io.InputStream; 15 | import java.io.InputStreamReader; 16 | import java.io.Reader; 17 | import java.net.URL; 18 | import java.net.URLConnection; 19 | import java.nio.charset.Charset; 20 | 21 | import org.json.JSONException; 22 | import org.json.JSONObject; 23 | 24 | /** 25 | * Description : 26 | * 27 | * @author: Jia Kang 28 | * 29 | * History: 2017年4月17日 下午5:51:22 Jia Kang Created. 30 | * 31 | */ 32 | public class JsonReader { 33 | 34 | private static String readAllByChar(BufferedReader rd) throws IOException { 35 | StringBuilder sb = new StringBuilder(); 36 | int cp; 37 | while ((cp = rd.read()) != -1) { 38 | sb.append((char) cp); 39 | } 40 | return sb.toString(); 41 | } 42 | 43 | private static String readAllByLine(BufferedReader rd) throws IOException { 44 | StringBuilder sb = new StringBuilder(); 45 | String line; 46 | 47 | // read from the urlconnection via the bufferedreader 48 | while ((line = rd.readLine()) != null) { 49 | sb.append(line + "\n"); 50 | } 51 | 52 | return sb.toString(); 53 | } 54 | 55 | public static JSONObject readJsonFromUrl(String urlS) throws IOException, JSONException { 56 | 57 | // create a url object 58 | URL url = new URL(urlS); 59 | 60 | // create a urlconnection object 61 | URLConnection urlConnection = url.openConnection(); 62 | 63 | // wrap the urlconnection in a bufferedreader 64 | BufferedReader rd = new BufferedReader(new InputStreamReader(urlConnection.getInputStream())); 65 | 66 | String jsonText = readAllByLine(rd); 67 | 68 | 69 | return new JSONObject(jsonText); 70 | 71 | } 72 | 73 | public static String getUrlContents(String theUrl) { 74 | StringBuilder content = new StringBuilder(); 75 | 76 | // many of these calls can throw exceptions, so i've just 77 | // wrapped them all in one try/catch statement. 78 | try { 79 | // create a url object 80 | URL url = new URL(theUrl); 81 | 82 | // create a urlconnection object 83 | URLConnection urlConnection = url.openConnection(); 84 | 85 | // wrap the urlconnection in a bufferedreader 86 | BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream())); 87 | 88 | content.append(readAllByLine(bufferedReader)); 89 | bufferedReader.close(); 90 | } catch (Exception e) { 91 | e.printStackTrace(); 92 | } 93 | return content.toString(); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /app/src/main/java/cn/jk/kaoyandanci/util/MD5.java: -------------------------------------------------------------------------------- 1 | package cn.jk.kaoyandanci.util; 2 | 3 | import android.text.TextUtils; 4 | import android.util.Log; 5 | 6 | import java.io.File; 7 | import java.io.FileInputStream; 8 | import java.io.FileNotFoundException; 9 | import java.io.IOException; 10 | import java.io.InputStream; 11 | import java.math.BigInteger; 12 | import java.security.MessageDigest; 13 | import java.security.NoSuchAlgorithmException; 14 | 15 | /** 16 | * Created by Administrator on 2017/7/22. 17 | */ 18 | 19 | public class MD5 { 20 | private static final String TAG = "MD5"; 21 | 22 | public static boolean checkMD5(String md5, File updateFile) { 23 | if (TextUtils.isEmpty(md5) || updateFile == null) { 24 | Log.e(TAG, "MD5 string empty or updateFile null"); 25 | return false; 26 | } 27 | 28 | String calculatedDigest = calculateMD5(updateFile); 29 | if (calculatedDigest == null) { 30 | Log.e(TAG, "calculatedDigest null"); 31 | return false; 32 | } 33 | 34 | Log.v(TAG, "Calculated digest: " + calculatedDigest); 35 | Log.v(TAG, "Provided digest: " + md5); 36 | 37 | return calculatedDigest.equalsIgnoreCase(md5); 38 | } 39 | 40 | public static String calculateMD5(File updateFile) { 41 | MessageDigest digest; 42 | try { 43 | digest = MessageDigest.getInstance("MD5"); 44 | } catch (NoSuchAlgorithmException e) { 45 | Log.e(TAG, "Exception while getting digest", e); 46 | return null; 47 | } 48 | 49 | InputStream is; 50 | try { 51 | is = new FileInputStream(updateFile); 52 | } catch (FileNotFoundException e) { 53 | Log.e(TAG, "Exception while getting FileInputStream", e); 54 | return null; 55 | } 56 | 57 | byte[] buffer = new byte[8192]; 58 | int read; 59 | try { 60 | while ((read = is.read(buffer)) > 0) { 61 | digest.update(buffer, 0, read); 62 | } 63 | byte[] md5sum = digest.digest(); 64 | BigInteger bigInt = new BigInteger(1, md5sum); 65 | String output = bigInt.toString(16); 66 | // Fill to 32 chars 67 | output = String.format("%32s", output).replace(' ', '0'); 68 | return output; 69 | } catch (IOException e) { 70 | throw new RuntimeException("Unable to process file for MD5", e); 71 | } finally { 72 | try { 73 | is.close(); 74 | } catch (IOException e) { 75 | Log.e(TAG, "Exception on closing MD5 input stream", e); 76 | } 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /app/src/main/java/cn/jk/kaoyandanci/util/MediaFileNameGenerator.java: -------------------------------------------------------------------------------- 1 | package cn.jk.kaoyandanci.util; 2 | 3 | /** 4 | * Created by Administrator on 2017/7/11. 5 | */ 6 | 7 | import android.net.Uri; 8 | 9 | import com.danikula.videocache.file.FileNameGenerator; 10 | 11 | public class MediaFileNameGenerator implements FileNameGenerator { 12 | 13 | // Urls contain mutable parts (parameter 'sessionToken') and stable video's id (parameter 'videoId'). 14 | // e. g. http://example.com?videoId=abcqaz&sessionToken=xyz987 15 | public String generate(String url) { 16 | Uri uri = Uri.parse(url); 17 | String videoId = uri.getLastPathSegment(); 18 | return videoId; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /app/src/main/java/cn/jk/kaoyandanci/util/MediaUtil.java: -------------------------------------------------------------------------------- 1 | package cn.jk.kaoyandanci.util; 2 | 3 | import android.content.Context; 4 | import android.media.MediaPlayer; 5 | import android.util.Log; 6 | 7 | import com.danikula.videocache.HttpProxyCacheServer; 8 | 9 | import java.io.IOException; 10 | import java.util.logging.Logger; 11 | 12 | import cn.jk.kaoyandanci.InitApplication; 13 | 14 | /** 15 | * Created by Administrator on 2017/7/11. 16 | */ 17 | 18 | public class MediaUtil { 19 | static MediaPlayer mediaPlayer = new MediaPlayer(); 20 | 21 | public static boolean display(String url, final Context context) { 22 | HttpProxyCacheServer proxy = ((InitApplication) context.getApplicationContext()).getProxy(context); 23 | final String proxyUrl = proxy.getProxyUrl(url); 24 | if (!proxy.isCached(proxyUrl)) { 25 | if (!NetWorkUtil.isOnline(context)) { 26 | return false; 27 | } 28 | } 29 | mediaPlayer.reset(); 30 | 31 | 32 | try { 33 | mediaPlayer.setDataSource(proxyUrl); 34 | mediaPlayer.prepareAsync(); 35 | mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { 36 | @Override 37 | public void onPrepared(MediaPlayer player) { 38 | player.start(); 39 | 40 | } 41 | }); 42 | } catch (Exception e) { 43 | Log.d("error ", e.toString()); 44 | } 45 | return true; 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /app/src/main/java/cn/jk/kaoyandanci/util/NetWorkSingleton.java: -------------------------------------------------------------------------------- 1 | package cn.jk.kaoyandanci.util; 2 | 3 | import android.content.Context; 4 | 5 | import com.android.volley.Request; 6 | import com.android.volley.RequestQueue; 7 | import com.android.volley.toolbox.Volley; 8 | 9 | /** 10 | * Created by Administrator on 2017/7/22. 11 | */ 12 | 13 | public class NetWorkSingleton { 14 | private static NetWorkSingleton mInstance; 15 | private static Context mCtx; 16 | private RequestQueue mRequestQueue; 17 | 18 | private NetWorkSingleton(Context context) { 19 | mCtx = context; 20 | mRequestQueue = getRequestQueue(); 21 | 22 | } 23 | 24 | public static synchronized NetWorkSingleton getInstance(Context context) { 25 | if (mInstance == null) { 26 | mInstance = new NetWorkSingleton(context); 27 | } 28 | return mInstance; 29 | } 30 | 31 | public RequestQueue getRequestQueue() { 32 | if (mRequestQueue == null) { 33 | // getApplicationContext() is key, it keeps you from leaking the 34 | // Activity or BroadcastReceiver if someone passes one in. 35 | mRequestQueue = Volley.newRequestQueue(mCtx.getApplicationContext()); 36 | } 37 | return mRequestQueue; 38 | } 39 | 40 | public void addToRequestQueue(Request req) { 41 | getRequestQueue().add(req); 42 | } 43 | 44 | 45 | } -------------------------------------------------------------------------------- /app/src/main/java/cn/jk/kaoyandanci/util/NetWorkUtil.java: -------------------------------------------------------------------------------- 1 | package cn.jk.kaoyandanci.util; 2 | 3 | import android.content.Context; 4 | import android.net.ConnectivityManager; 5 | import android.net.NetworkInfo; 6 | 7 | /** 8 | * Created by Administrator on 2017/6/3. 9 | */ 10 | 11 | public class NetWorkUtil { 12 | public static boolean isOnline(Context context) { 13 | ConnectivityManager cm = 14 | (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); 15 | NetworkInfo netInfo = cm.getActiveNetworkInfo(); 16 | if (netInfo == null) { 17 | return false; 18 | } else { 19 | return netInfo.isConnectedOrConnecting(); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /app/src/main/java/cn/jk/kaoyandanci/util/OnSwipeTouchListener.java: -------------------------------------------------------------------------------- 1 | package cn.jk.kaoyandanci.util; 2 | 3 | import android.content.Context; 4 | import android.view.GestureDetector; 5 | import android.view.MotionEvent; 6 | import android.view.View; 7 | 8 | /** 9 | * Created by Administrator on 2017/7/11. 10 | */ 11 | 12 | public class OnSwipeTouchListener implements View.OnTouchListener { 13 | 14 | private final GestureDetector gestureDetector; 15 | 16 | public OnSwipeTouchListener(Context ctx) { 17 | gestureDetector = new GestureDetector(ctx, new GestureListener()); 18 | } 19 | 20 | @Override 21 | public boolean onTouch(View v, MotionEvent event) { 22 | return gestureDetector.onTouchEvent(event); 23 | } 24 | 25 | public void onSwipeRight() { 26 | } 27 | 28 | public void onSwipeLeft() { 29 | } 30 | 31 | public void onSwipeTop() { 32 | } 33 | 34 | public void onSwipeBottom() { 35 | } 36 | 37 | private final class GestureListener extends GestureDetector.SimpleOnGestureListener { 38 | 39 | private static final int SWIPE_THRESHOLD = 100; 40 | private static final int SWIPE_VELOCITY_THRESHOLD = 100; 41 | 42 | @Override 43 | public boolean onDown(MotionEvent e) { 44 | return true; 45 | } 46 | 47 | @Override 48 | public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { 49 | boolean result = false; 50 | try { 51 | float diffY = e2.getY() - e1.getY(); 52 | float diffX = e2.getX() - e1.getX(); 53 | if (Math.abs(diffX) > Math.abs(diffY)) { 54 | if (Math.abs(diffX) > SWIPE_THRESHOLD && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) { 55 | if (diffX > 0) { 56 | onSwipeRight(); 57 | } else { 58 | onSwipeLeft(); 59 | } 60 | result = true; 61 | } 62 | } else if (Math.abs(diffY) > SWIPE_THRESHOLD && Math.abs(velocityY) > SWIPE_VELOCITY_THRESHOLD) { 63 | if (diffY > 0) { 64 | onSwipeBottom(); 65 | } else { 66 | onSwipeTop(); 67 | } 68 | result = true; 69 | } 70 | } catch (Exception exception) { 71 | exception.printStackTrace(); 72 | } 73 | return result; 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /app/src/main/java/cn/jk/kaoyandanci/util/SPUtil.java: -------------------------------------------------------------------------------- 1 | package cn.jk.kaoyandanci.util; 2 | 3 | import android.content.Context; 4 | import android.content.SharedPreferences; 5 | 6 | import java.lang.reflect.InvocationTargetException; 7 | import java.lang.reflect.Method; 8 | import java.util.Map; 9 | 10 | /** 11 | * 简化SharedPreferences的帮助类. 12 | * 13 | * @author unknow 14 | * @date 2015/5/14 15 | * @see "http://blog.csdn.net/lmj623565791/article/details/38965311" 16 | */ 17 | public class SPUtil { 18 | 19 | /** 20 | * SharedPreferences存储在sd卡中的文件名字 21 | */ 22 | private static String getSpName(Context context) { 23 | return context.getPackageName() + "_preferences"; 24 | } 25 | 26 | /** 27 | * 保存数据的方法,我们需要拿到保存数据的具体类型,然后根据类型调用不同的保存方法 28 | */ 29 | public static void putAndApply(Context context, String key, Object object) { 30 | SharedPreferences sp = context.getSharedPreferences(getSpName(context), Context.MODE_PRIVATE); 31 | SharedPreferences.Editor editor = sp.edit(); 32 | 33 | if (object instanceof String) { 34 | editor.putString(key, (String) object); 35 | } else if (object instanceof Integer) { 36 | editor.putInt(key, (Integer) object); 37 | } else if (object instanceof Boolean) { 38 | editor.putBoolean(key, (Boolean) object); 39 | } else if (object instanceof Float) { 40 | editor.putFloat(key, (Float) object); 41 | } else if (object instanceof Long) { 42 | editor.putLong(key, (Long) object); 43 | } else { 44 | editor.putString(key, object.toString()); 45 | } 46 | 47 | SharedPreferencesCompat.apply(editor); 48 | } 49 | 50 | /** 51 | * 得到保存数据的方法,我们根据默认值得到保存的数据的具体类型,然后调用相对于的方法获取值 52 | */ 53 | public static Object get(Context context, String key, Object defaultObject) { 54 | SharedPreferences sp = context.getSharedPreferences(getSpName(context), Context.MODE_PRIVATE); 55 | 56 | if (defaultObject instanceof String) { 57 | return sp.getString(key, (String) defaultObject); 58 | } else if (defaultObject instanceof Integer) { 59 | return sp.getInt(key, (Integer) defaultObject); 60 | } else if (defaultObject instanceof Boolean) { 61 | return sp.getBoolean(key, (Boolean) defaultObject); 62 | } else if (defaultObject instanceof Float) { 63 | return sp.getFloat(key, (Float) defaultObject); 64 | } else if (defaultObject instanceof Long) { 65 | return sp.getLong(key, (Long) defaultObject); 66 | } else { 67 | return null; 68 | } 69 | } 70 | 71 | /** 72 | * 移除某个key值已经对应的值 73 | */ 74 | public static void remove(Context context, String key) { 75 | SharedPreferences sp = context.getSharedPreferences(getSpName(context), Context.MODE_PRIVATE); 76 | SharedPreferences.Editor editor = sp.edit(); 77 | editor.remove(key); 78 | SharedPreferencesCompat.apply(editor); 79 | } 80 | 81 | /** 82 | * 清除所有数据 83 | */ 84 | public static void clear(Context context) { 85 | SharedPreferences sp = context.getSharedPreferences(getSpName(context), Context.MODE_PRIVATE); 86 | SharedPreferences.Editor editor = sp.edit(); 87 | editor.clear(); 88 | SharedPreferencesCompat.apply(editor); 89 | } 90 | 91 | /** 92 | * 查询某个key是否已经存在 93 | */ 94 | public static boolean contains(Context context, String key) { 95 | SharedPreferences sp = context.getSharedPreferences(getSpName(context), Context.MODE_PRIVATE); 96 | return sp.contains(key); 97 | } 98 | 99 | /** 100 | * 返回所有的键值对 101 | */ 102 | public static Map getAll(Context context) { 103 | SharedPreferences sp = context.getSharedPreferences(getSpName(context), Context.MODE_PRIVATE); 104 | return sp.getAll(); 105 | } 106 | 107 | /** 108 | * 创建一个解决SharedPreferencesCompat.apply方法的一个兼容类 109 | * 110 | * @author zhy 111 | */ 112 | private static class SharedPreferencesCompat { 113 | 114 | private static final Method sApplyMethod = findApplyMethod(); 115 | 116 | /** 117 | * 反射查找apply的方法 118 | */ 119 | @SuppressWarnings({"unchecked", "rawtypes"}) 120 | private static Method findApplyMethod() { 121 | try { 122 | Class clz = SharedPreferences.Editor.class; 123 | return clz.getMethod("apply"); 124 | } catch (NoSuchMethodException e) { 125 | } 126 | 127 | return null; 128 | } 129 | 130 | /** 131 | * 如果找到则使用apply执行,否则使用commit 132 | */ 133 | public static void apply(SharedPreferences.Editor editor) { 134 | try { 135 | if (sApplyMethod != null) { 136 | sApplyMethod.invoke(editor); 137 | return; 138 | } 139 | } catch (IllegalArgumentException expected) { 140 | } catch (IllegalAccessException expected) { 141 | } catch (InvocationTargetException expected) { 142 | } 143 | editor.commit(); 144 | } 145 | } 146 | 147 | 148 | } 149 | -------------------------------------------------------------------------------- /app/src/main/java/cn/jk/kaoyandanci/util/ShadowImageView.java: -------------------------------------------------------------------------------- 1 | package cn.jk.kaoyandanci.util; 2 | 3 | import android.content.Context; 4 | import android.graphics.Color; 5 | import android.graphics.Rect; 6 | import android.util.AttributeSet; 7 | import android.view.MotionEvent; 8 | import android.view.View; 9 | 10 | /** 11 | *
12 |  *     author : jiakang
13 |  *     e-mail : 1079153785@qq.com
14 |  *     time   : 2018/07/12
15 |  *     desc   :
16 |  *     version: 1.0
17 |  * 
18 | */ 19 | public class ShadowImageView extends android.support.v7.widget.AppCompatImageView { 20 | 21 | public ShadowImageView(Context context) { 22 | super(context); 23 | } 24 | 25 | public ShadowImageView(Context context, AttributeSet attrs) { 26 | super(context, attrs); 27 | setShadowWhenPress(null); 28 | } 29 | 30 | public ShadowImageView(Context context, AttributeSet attrs, int defStyleAttr) { 31 | super(context, attrs, defStyleAttr); 32 | setShadowWhenPress(null); 33 | } 34 | 35 | /** 36 | * @param outRect 传入为空 则范围为本view. 37 | * 不为空则为传入的view. 38 | */ 39 | public void setShadowWhenPress(final Rect outRect) { 40 | setOnTouchListener(new OnTouchListener() { 41 | private Rect rect; 42 | 43 | @Override 44 | public boolean onTouch(View v, MotionEvent event) { 45 | if (event.getAction() == MotionEvent.ACTION_DOWN) { 46 | setColorFilter(Color.argb(100, 0, 0, 0)); 47 | if (outRect != null) { 48 | rect = outRect; 49 | } else { 50 | rect = new Rect(v.getLeft(), v.getTop(), v.getRight(), v.getBottom()); 51 | } 52 | 53 | } 54 | if (event.getAction() == MotionEvent.ACTION_UP) { 55 | setColorFilter(Color.argb(0, 0, 0, 0)); 56 | } 57 | if (event.getAction() == MotionEvent.ACTION_MOVE) { 58 | if (!rect.contains(v.getLeft() + (int) event.getX(), v.getTop() + (int) event.getY())) { 59 | setColorFilter(Color.argb(0, 0, 0, 0)); 60 | } 61 | } 62 | return false; 63 | } 64 | }); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /app/src/main/java/cn/jk/kaoyandanci/util/ToastUtil.java: -------------------------------------------------------------------------------- 1 | package cn.jk.kaoyandanci.util; 2 | 3 | import android.content.Context; 4 | import android.os.Handler; 5 | import android.os.Looper; 6 | import android.support.annotation.IntDef; 7 | import android.support.annotation.NonNull; 8 | import android.view.View; 9 | import android.widget.Toast; 10 | 11 | /** 12 | * 让toast变得更简易的封装类,可以提供线程中使用的toast。还可以通过showByDuration()来设置toast的显示时间. 13 | * 14 | * @author Jack Tony 15 | * @date 2015/4/29 16 | */ 17 | public class ToastUtil { 18 | 19 | private final int DEFAULT = 2000; 20 | private Toast mToast = null; 21 | 22 | private Handler mHandler = null; 23 | 24 | private int duration = 0; 25 | 26 | private int currDuration = 0; 27 | private Runnable mToastThread = new Runnable() { 28 | 29 | public void run() { 30 | mToast.show(); 31 | mHandler.postDelayed(mToastThread, DEFAULT);// 每隔2秒显示一次 32 | if (duration != 0) { 33 | if (currDuration <= duration) { 34 | currDuration += DEFAULT; 35 | } else { 36 | cancel(); 37 | } 38 | } 39 | } 40 | }; 41 | 42 | public ToastUtil(Context context) { 43 | currDuration = DEFAULT; 44 | mHandler = new Handler(context.getMainLooper()); 45 | mToast = Toast.makeText(context, "", Toast.LENGTH_LONG); 46 | } 47 | 48 | /** 49 | * 短暂显示toast 50 | */ 51 | public static void showShort(@NonNull Context context, int msg) { 52 | showShort(context, String.valueOf(msg)); 53 | } 54 | 55 | /** 56 | * 短暂显示toast 57 | */ 58 | public static void showShort(@NonNull Context context, String msg) { 59 | Toast.makeText(context, msg, Toast.LENGTH_SHORT).show(); 60 | } 61 | 62 | /** 63 | * 显示toast 64 | * 65 | * @param length toast的显示的时间长度:{Toast.LENGTH_SHORT, Toast.LENGTH_LONG} 66 | */ 67 | public static void show(@NonNull Context context, int msg, @Length int length) { 68 | show(context, String.valueOf(msg), length); 69 | } 70 | 71 | /** 72 | * 显示toast 73 | * 74 | * @param length toast的显示的时间长度:{Toast.LENGTH_SHORT, Toast.LENGTH_LONG} 75 | */ 76 | public static void show(@NonNull Context context, String msg, @Length int length) { 77 | if (length == Toast.LENGTH_SHORT || length == Toast.LENGTH_LONG) { 78 | Toast.makeText(context, msg, length).show(); 79 | } 80 | } 81 | 82 | /** 83 | * 当你在线程中使用toast时,请使用这个方法 84 | */ 85 | public static void showShortInThread(@NonNull final Context context, int msg) { 86 | showShortInThread(context, String.valueOf(msg)); 87 | } 88 | 89 | /** 90 | * 当你在线程中使用toast时,请使用这个方法 91 | */ 92 | public static void showShortInThread(@NonNull Context context, String msg) { 93 | showInThread(context, msg, Toast.LENGTH_SHORT); 94 | } 95 | 96 | /** 97 | * 当你在线程中使用toast时,请使用这个方法(可以控制显示多长时间) 98 | */ 99 | public static void showInThread(@NonNull Context context, int msg, @Length int length) { 100 | showInThread(context, String.valueOf(msg), length); 101 | } 102 | 103 | //// 封装的静态方法 ////// 104 | 105 | /** 106 | * 当你在线程中使用toast时,请使用这个方法(可以控制显示多长时间) 107 | */ 108 | public static void showInThread(@NonNull final Context context, final String msg, @Length final int length) { 109 | new Thread() { 110 | @Override 111 | public void run() { 112 | Looper.prepare();//先移除 113 | Toast.makeText(context, msg, length).show(); 114 | Looper.loop();// 进入loop中的循环,查看消息队列 115 | } 116 | }.start(); 117 | } 118 | 119 | public static void showLong(Context context, String s) { 120 | Toast.makeText(context, s, Toast.LENGTH_LONG).show(); 121 | } 122 | 123 | /** 124 | * 返回内部的toast对象。可以进行多样化的设置 125 | */ 126 | public Toast getToast() { 127 | return mToast; 128 | } 129 | 130 | /** 131 | * 设置toast的文字 132 | */ 133 | public void setText(String text) { 134 | mToast.setText(text); 135 | } 136 | 137 | /** 138 | * 显示toast 139 | * 140 | * @param duration toast显示的时间(单位:ms) 141 | */ 142 | public void showByDuration(int duration) { 143 | this.duration = duration; 144 | mHandler.post(mToastThread); 145 | } 146 | 147 | /** 148 | * 设置toast显示的位置 149 | * 150 | * @param gravity 位置,可以是Gravity.CENTER等 151 | * @param xOffset x轴的偏移量 152 | * @param yOffset y轴的偏移量 153 | */ 154 | public void setGravity(int gravity, int xOffset, int yOffset) { 155 | mToast.setGravity(gravity, xOffset, yOffset); 156 | } 157 | 158 | /** 159 | * 设置toast的view 160 | */ 161 | public void setView(View view) { 162 | mToast.setView(view); 163 | } 164 | 165 | /** 166 | * 让toast消失的方法 167 | */ 168 | public void cancel() { 169 | mHandler.removeCallbacks(mToastThread);// 先把显示线程删除 170 | mToast.cancel();// 把最后一个线程的显示效果cancel掉,就一了百了了 171 | currDuration = DEFAULT; 172 | } 173 | 174 | @IntDef({Toast.LENGTH_SHORT, Toast.LENGTH_LONG}) 175 | private @interface Length { 176 | 177 | } 178 | } 179 | -------------------------------------------------------------------------------- /app/src/main/java/cn/jk/kaoyandanci/util/WordDatabase.java: -------------------------------------------------------------------------------- 1 | package cn.jk.kaoyandanci.util; 2 | 3 | import android.content.Context; 4 | import android.database.sqlite.SQLiteDatabase; 5 | 6 | import com.readystatesoftware.sqliteasset.SQLiteAssetHelper; 7 | 8 | /** 9 | * Created by Administrator on 2017/4/12. 10 | */ 11 | 12 | public class WordDatabase extends SQLiteAssetHelper { 13 | 14 | private static final int DATABASE_VERSION = 4; 15 | Context context; 16 | 17 | public WordDatabase(Context context) { 18 | super(context, Constant.DATABASE_NAME, null, DATABASE_VERSION); 19 | 20 | } 21 | 22 | @Override 23 | public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 24 | super.onUpgrade(db, oldVersion, newVersion); 25 | //印象中开始上架version就是2 26 | if (oldVersion < 2) { 27 | db.execSQL("ALTER TABLE word ADD COLUMN LAST_LEARN_TIME INTEGER DEFAULT 0"); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-night-xxhdpi/ic_volume.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HIjack2015/KaoYanDanci/4fe402844f173d92e4e49365a458b983b5b97490/app/src/main/res/drawable-night-xxhdpi/ic_volume.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/app_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HIjack2015/KaoYanDanci/4fe402844f173d92e4e49365a458b983b5b97490/app/src/main/res/drawable-xxhdpi/app_icon.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/blue_star.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/donate_alipay.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HIjack2015/KaoYanDanci/4fe402844f173d92e4e49365a458b983b5b97490/app/src/main/res/drawable-xxhdpi/donate_alipay.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/donate_weixin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HIjack2015/KaoYanDanci/4fe402844f173d92e4e49365a458b983b5b97490/app/src/main/res/drawable-xxhdpi/donate_weixin.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_delete_blue_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_home_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_keyboard_arrow_right_black_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HIjack2015/KaoYanDanci/4fe402844f173d92e4e49365a458b983b5b97490/app/src/main/res/drawable-xxhdpi/ic_keyboard_arrow_right_black_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_rate_review_black_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HIjack2015/KaoYanDanci/4fe402844f173d92e4e49365a458b983b5b97490/app/src/main/res/drawable-xxhdpi/ic_rate_review_black_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_settings_black_24dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HIjack2015/KaoYanDanci/4fe402844f173d92e4e49365a458b983b5b97490/app/src/main/res/drawable-xxhdpi/ic_settings_black_24dp.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/ic_volume.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HIjack2015/KaoYanDanci/4fe402844f173d92e4e49365a458b983b5b97490/app/src/main/res/drawable-xxhdpi/ic_volume.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/intro_back1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HIjack2015/KaoYanDanci/4fe402844f173d92e4e49365a458b983b5b97490/app/src/main/res/drawable-xxhdpi/intro_back1.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/intro_back2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HIjack2015/KaoYanDanci/4fe402844f173d92e4e49365a458b983b5b97490/app/src/main/res/drawable-xxhdpi/intro_back2.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-xxhdpi/intro_back3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HIjack2015/KaoYanDanci/4fe402844f173d92e4e49365a458b983b5b97490/app/src/main/res/drawable-xxhdpi/intro_back3.jpg -------------------------------------------------------------------------------- /app/src/main/res/drawable/empty.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HIjack2015/KaoYanDanci/4fe402844f173d92e4e49365a458b983b5b97490/app/src/main/res/drawable/empty.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_add.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_delete_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_restore_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_search_black_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_star_border_blue_24dp.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/star.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/into_back2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HIjack2015/KaoYanDanci/4fe402844f173d92e4e49365a458b983b5b97490/app/src/main/res/into_back2.jpg -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_advance_setting.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_common_question.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_display_setting.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_donate.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 21 | 22 | 26 | 27 | 28 | 29 | 42 | 43 | 55 | 56 |