├── .gitignore ├── .idea ├── .name ├── codeStyles │ ├── Project.xml │ └── codeStyleConfig.xml ├── dictionaries │ └── Administrator.xml ├── gradle.xml ├── misc.xml ├── render.experimental.xml ├── runConfigurations.xml └── vcs.xml ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── we │ │ └── zxlite │ │ └── ExampleInstrumentedTest.kt │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── we │ │ │ └── zxlite │ │ │ ├── GlideModule.kt │ │ │ ├── activity │ │ │ ├── AnalyzeActivity.kt │ │ │ ├── BaseActivity.kt │ │ │ ├── GuessActivity.kt │ │ │ ├── InitActivity.kt │ │ │ ├── LoginActivity.kt │ │ │ ├── MainActivity.kt │ │ │ ├── PaperActivity.kt │ │ │ ├── RegisterActivity.kt │ │ │ └── ReportActivity.kt │ │ │ ├── adapter │ │ │ ├── AnalyzeListAdapter.kt │ │ │ ├── AnalyzePageAdapter.kt │ │ │ ├── ExamListAdapter.kt │ │ │ ├── GuessItemAdapter.kt │ │ │ ├── ReportItemAdapter.kt │ │ │ └── ReportPageAdapter.kt │ │ │ ├── bean │ │ │ ├── AnalyzeListBean.kt │ │ │ ├── AnalyzePageBean.kt │ │ │ ├── ReportListBean.kt │ │ │ ├── ReportPageBean.kt │ │ │ └── UserConfigBean.kt │ │ │ ├── dialog │ │ │ ├── AboutDialog.kt │ │ │ ├── AccountDialog.kt │ │ │ ├── BaseAlertDialog.kt │ │ │ ├── BaseSheetDialog.kt │ │ │ ├── BindDialog.kt │ │ │ ├── ModifyDialog.kt │ │ │ └── SelectFriendsDialog.kt │ │ │ ├── utils │ │ │ ├── BaseUtils.kt │ │ │ ├── GetterUtils.kt │ │ │ ├── HttpUtils.kt │ │ │ ├── SqlUtils.kt │ │ │ └── UserUtils.kt │ │ │ └── view │ │ │ ├── ProgressBar.kt │ │ │ ├── ScoreChart.kt │ │ │ └── ShadowView.kt │ └── res │ │ ├── drawable │ │ ├── edit_line.xml │ │ ├── ic_arrow.xml │ │ ├── ic_arrow_back.xml │ │ ├── ic_launcher.xml │ │ ├── ic_launcher_foreground.xml │ │ ├── nav_text_color.xml │ │ ├── shadow_btm.xml │ │ └── shadow_top.xml │ │ ├── layout │ │ ├── activity_analyze.xml │ │ ├── activity_guess.xml │ │ ├── activity_init.xml │ │ ├── activity_login.xml │ │ ├── activity_main.xml │ │ ├── activity_paper.xml │ │ ├── activity_register.xml │ │ ├── activity_report.xml │ │ ├── dialog_about.xml │ │ ├── dialog_bind.xml │ │ ├── dialog_modify.xml │ │ ├── fragment_analyze.xml │ │ ├── fragment_report.xml │ │ ├── fragment_report_general.xml │ │ ├── header_main.xml │ │ ├── item_analyze.xml │ │ ├── item_general.xml │ │ ├── item_guess.xml │ │ ├── item_report.xml │ │ └── item_tab.xml │ │ ├── menu │ │ ├── menu_main.xml │ │ └── menu_report.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ └── values │ │ ├── attrs.xml │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── we │ └── zxlite │ └── ExampleUnitTest.kt ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/caches 5 | /.idea/libraries 6 | /.idea/modules.xml 7 | /.idea/workspace.xml 8 | /.idea/navEditor.xml 9 | /.idea/assetWizardSettings.xml 10 | .DS_Store 11 | /build 12 | /captures 13 | .externalNativeBuild 14 | .cxx 15 | -------------------------------------------------------------------------------- /.idea/.name: -------------------------------------------------------------------------------- 1 | 智学网 -------------------------------------------------------------------------------- /.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 9 | 10 | 11 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | xmlns:android 20 | 21 | ^$ 22 | 23 | 24 | 25 |
26 |
27 | 28 | 29 | 30 | xmlns:.* 31 | 32 | ^$ 33 | 34 | 35 | BY_NAME 36 | 37 |
38 |
39 | 40 | 41 | 42 | .*:id 43 | 44 | http://schemas.android.com/apk/res/android 45 | 46 | 47 | 48 |
49 |
50 | 51 | 52 | 53 | .*:name 54 | 55 | http://schemas.android.com/apk/res/android 56 | 57 | 58 | 59 |
60 |
61 | 62 | 63 | 64 | name 65 | 66 | ^$ 67 | 68 | 69 | 70 |
71 |
72 | 73 | 74 | 75 | style 76 | 77 | ^$ 78 | 79 | 80 | 81 |
82 |
83 | 84 | 85 | 86 | .* 87 | 88 | ^$ 89 | 90 | 91 | BY_NAME 92 | 93 |
94 |
95 | 96 | 97 | 98 | .* 99 | 100 | http://schemas.android.com/apk/res/android 101 | 102 | 103 | ANDROID_ATTRIBUTE_ORDER 104 | 105 |
106 |
107 | 108 | 109 | 110 | .* 111 | 112 | .* 113 | 114 | 115 | BY_NAME 116 | 117 |
118 |
119 |
120 |
121 | 122 | 124 |
125 |
-------------------------------------------------------------------------------- /.idea/codeStyles/codeStyleConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /.idea/dictionaries/Administrator.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | authbizcode 5 | authguid 6 | authtimestamp 7 | authtoken 8 | choo 9 | dandroid 10 | dapp 11 | disp 12 | dtos 13 | fcgi 14 | ffrom 15 | iflytek 16 | knowledges 17 | mqqopensdkapi 18 | passwd 19 | pressenter 20 | recyclerview 21 | zxlite 22 | 23 | 24 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 18 | 19 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 9 | -------------------------------------------------------------------------------- /.idea/render.experimental.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 智学网Lite 2 | ### 更新日志 3 | * 优化登录失败逻辑 4 | * 修复阴影显示问题 5 | * 新增题目解析 6 | * 新增全科显示 7 | * 新增好友伴学 8 | -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | apply plugin: 'kotlin-android' 4 | 5 | apply plugin: 'kotlin-kapt' 6 | 7 | apply plugin: 'kotlin-android-extensions' 8 | 9 | android { 10 | compileSdkVersion 29 11 | buildToolsVersion "29.0.2" 12 | defaultConfig { 13 | applicationId "we.zxlite" 14 | minSdkVersion 15 15 | targetSdkVersion 29 16 | versionCode 1 17 | versionName "1.0" 18 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 19 | } 20 | buildTypes { 21 | release { 22 | minifyEnabled true 23 | zipAlignEnabled true 24 | shrinkResources true 25 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 26 | } 27 | } 28 | } 29 | 30 | dependencies { 31 | implementation fileTree(dir: 'libs', include: ['*.jar']) 32 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" 33 | implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlinx_version" 34 | implementation "org.jetbrains.anko:anko-sqlite:$anko_version" 35 | implementation 'com.github.PhilJay:MPAndroidChart:v3.1.0' 36 | implementation 'com.github.bumptech.glide:glide:4.9.0' 37 | implementation 'com.google.android.material:material:1.2.0-alpha01' 38 | implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0-alpha03' 39 | implementation 'androidx.appcompat:appcompat:1.1.0' 40 | implementation 'androidx.core:core-ktx:1.1.0' 41 | implementation 'androidx.constraintlayout:constraintlayout:1.1.3' 42 | testImplementation 'junit:junit:4.12' 43 | androidTestImplementation 'androidx.test.ext:junit:1.1.1' 44 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' 45 | kapt 'com.github.bumptech.glide:compiler:4.9.0' 46 | } 47 | 48 | repositories { 49 | maven { url 'https://jitpack.io' } 50 | } 51 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /app/src/androidTest/java/we/zxlite/ExampleInstrumentedTest.kt: -------------------------------------------------------------------------------- 1 | package we.zxlite 2 | 3 | import androidx.test.platform.app.InstrumentationRegistry 4 | import androidx.test.ext.junit.runners.AndroidJUnit4 5 | 6 | import org.junit.Test 7 | import org.junit.runner.RunWith 8 | 9 | import org.junit.Assert.* 10 | 11 | /** 12 | * Instrumented test, which will execute on an Android device. 13 | * 14 | * See [testing documentation](http://d.android.com/tools/testing). 15 | */ 16 | @RunWith(AndroidJUnit4::class) 17 | class ExampleInstrumentedTest { 18 | @Test 19 | fun useAppContext() { 20 | // Context of the app under test. 21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext 22 | assertEquals("we.zxlite", appContext.packageName) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 14 | 17 | 20 | 23 | 26 | 29 | 32 | 35 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /app/src/main/java/we/zxlite/GlideModule.kt: -------------------------------------------------------------------------------- 1 | package we.zxlite 2 | 3 | import android.content.Context 4 | import android.graphics.drawable.Drawable 5 | import com.bumptech.glide.GlideBuilder 6 | import com.bumptech.glide.annotation.GlideModule 7 | import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions.withCrossFade 8 | import com.bumptech.glide.module.AppGlideModule 9 | 10 | @GlideModule 11 | class GlideModule : AppGlideModule() { 12 | override fun applyOptions(ctx: Context, builder: GlideBuilder) { 13 | super.applyOptions(ctx, builder) 14 | builder.setDefaultTransitionOptions(Drawable::class.java, withCrossFade()) //增加渐变动画 15 | } 16 | } -------------------------------------------------------------------------------- /app/src/main/java/we/zxlite/activity/AnalyzeActivity.kt: -------------------------------------------------------------------------------- 1 | package we.zxlite.activity 2 | 3 | import android.graphics.Color.RED 4 | import android.os.Bundle 5 | import android.view.View 6 | import android.widget.TextView 7 | import com.google.android.material.tabs.TabLayoutMediator 8 | import com.google.android.material.tabs.TabLayoutMediator.TabConfigurationStrategy 9 | import kotlinx.android.synthetic.main.activity_analyze.* 10 | import kotlinx.coroutines.Dispatchers.Main 11 | import kotlinx.coroutines.launch 12 | import kotlinx.coroutines.withContext 13 | import org.jetbrains.anko.toast 14 | import org.json.JSONObject 15 | import we.zxlite.R 16 | import we.zxlite.adapter.AnalyzePageAdapter 17 | import we.zxlite.bean.AnalyzePageBean 18 | import we.zxlite.utils.BaseUtils.color 19 | import we.zxlite.utils.HttpUtils.Error 20 | import we.zxlite.utils.HttpUtils.Type.JsonObject 21 | import we.zxlite.utils.HttpUtils.api 22 | import kotlin.Comparator 23 | import kotlin.collections.ArrayList 24 | 25 | class AnalyzeActivity : BaseActivity() { 26 | 27 | companion object { 28 | //解析URL 29 | private const val ANALYZE_URL = 30 | "https://www.zhixue.com/zhixuebao/report/getPaperAnalysis" 31 | //原卷id 32 | private const val PAPER_ID = "paperId" 33 | // 类型主题分析 34 | private const val TYPE_TOPIC = "typeTopicAnalysis" 35 | //主题分析 36 | private const val TYPE_DTOS = "topicAnalysisDTOs" 37 | //题号 38 | private const val DIS_TITLE_NUMBER = "disTitleNumber" 39 | //答案类型 40 | private const val ANSWER_TYPE = "answerType" 41 | //答案Html 42 | private const val ANALYSIS_HTML = "analysisHtml" 43 | //答案Html 44 | private const val ANSWER_HTML = "answerHtml" 45 | //题头 46 | private const val TOPIC_NUMBER = "topicNumber" 47 | //主题id 48 | private const val TOPIC_ID = "topicId" 49 | //主题id 50 | private const val TOPIC_SET_ID = "topicSetId" 51 | //主题分数 52 | private const val TOPIC_SCORE_DTOS = "topicScoreDTOs" 53 | //标准答案 54 | private const val STANDARD_ANSWER = "standardAnswer" 55 | //用户答案 56 | private const val USER_ANSWER = "userAnswer" 57 | //用户答案 58 | private const val USER_ANSWERS = "userAnswers" 59 | //图像答案 60 | private const val IMAGE_ANSWER = "imageAnswer" 61 | //标准分数 62 | private const val STANDARD_SCORE = "standardScore" 63 | //分数 64 | private const val SCORE = "score" 65 | //题目 66 | private const val CONTENT_HTML = "contentHtml" 67 | //知识点 68 | private const val KNOWLEDGE_GROUPS = "relatedKnowledgeGroups" 69 | } 70 | 71 | //解析页列表 72 | private val analyzePageList = ArrayList() 73 | //解析参数 74 | private val analyzeParams get() = "?paperId=${intent.getStringExtra(PAPER_ID)}" 75 | 76 | override fun onCreate(savedInstanceState: Bundle?) { 77 | super.onCreate(savedInstanceState) 78 | setContentView(R.layout.activity_analyze) 79 | loadAnalyze() 80 | } 81 | 82 | override fun initView() { 83 | setSupportActionBar(analyzeBar) 84 | analyzeBar.setNavigationOnClickListener { onBackPressed() } 85 | analyzePager.adapter = AnalyzePageAdapter(analyzePageList) 86 | analyzePager.offscreenPageLimit = 3 87 | TabLayoutMediator(analyzeTab, analyzePager, TabConfigurationStrategy { tab, position -> 88 | val tabView = View.inflate(this, R.layout.item_tab, null) as TextView 89 | tabView.text = analyzePageList[position].disTitleNumber 90 | when { 91 | analyzePageList[position].score == analyzePageList[position].standardScore -> 92 | tab.tag = 0 93 | analyzePageList[position].score == 0.0 -> { 94 | tab.tag = 1 95 | tabView.setTextColor(RED) 96 | } 97 | else -> { 98 | tab.tag = 2 99 | tabView.setTextColor(color(R.color.colorDeepYellow)) 100 | } 101 | } 102 | tab.customView = tabView 103 | }).attach() 104 | } 105 | 106 | private fun loadAnalyze() { 107 | launch { 108 | api(ANALYZE_URL + analyzeParams, null, true, JsonObject).let { 109 | if (it is JSONObject) { 110 | val topicAnalysis = it.optJSONArray(TYPE_TOPIC) 111 | for (i in 0 until topicAnalysis!!.length()) { 112 | val topicDTOs = 113 | topicAnalysis.optJSONObject(i).optJSONArray(TYPE_DTOS) 114 | for (dto in 0 until topicDTOs!!.length()) { 115 | val topic = topicDTOs.optJSONObject(dto) 116 | analyzePageList.add( 117 | AnalyzePageBean( 118 | disTitleNumber = topic.optString(DIS_TITLE_NUMBER), 119 | topicNumber = topic.optInt(TOPIC_NUMBER), 120 | topicScoreDTOs = topic.optString(TOPIC_SCORE_DTOS), 121 | topicId = topic.optString(TOPIC_ID), 122 | topicSetId = topic.optString(TOPIC_SET_ID), 123 | analysisHtml = topic.optString(ANALYSIS_HTML), 124 | contentHtml = topic.optString(CONTENT_HTML), 125 | answerType = topic.optString(ANSWER_TYPE), 126 | answerHtml = topic.optString(ANSWER_HTML), 127 | standardAnswer = topic.optString(STANDARD_ANSWER), 128 | standardScore = topic.optDouble(STANDARD_SCORE), 129 | score = topic.optDouble(SCORE), 130 | userAnswer = topic.optString(USER_ANSWER), 131 | userAnswers = topic.optString(USER_ANSWERS), 132 | imageAnswers = topic.optString(IMAGE_ANSWER), 133 | relatedKnowledgeGroups = topic.optString(KNOWLEDGE_GROUPS) 134 | ) 135 | ) 136 | } 137 | } 138 | analyzePageList.sortWith(Comparator { o1, o2 -> 139 | if (o1.topicNumber > o2.topicNumber) 1 else -1 140 | }) 141 | withContext(Main) { 142 | analyzePager.adapter!!.notifyItemRangeInserted(0, analyzePageList.size) 143 | } 144 | } else toast((it as Error).message) 145 | } 146 | } 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /app/src/main/java/we/zxlite/activity/BaseActivity.kt: -------------------------------------------------------------------------------- 1 | package we.zxlite.activity 2 | 3 | import android.os.Build.VERSION.SDK_INT 4 | import android.os.Build.VERSION_CODES.LOLLIPOP 5 | import android.os.Build.VERSION_CODES.M 6 | import android.os.Bundle 7 | import android.view.View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR 8 | import android.view.Window 9 | import androidx.appcompat.app.AppCompatActivity 10 | import kotlinx.coroutines.CoroutineScope 11 | import kotlinx.coroutines.MainScope 12 | import kotlinx.coroutines.cancel 13 | import we.zxlite.R 14 | import we.zxlite.utils.BaseUtils.color 15 | 16 | abstract class BaseActivity : AppCompatActivity(), CoroutineScope by MainScope() { 17 | 18 | override fun onCreate(savedInstanceState: Bundle?) { 19 | super.onCreate(savedInstanceState) 20 | window.initStatusBar() 21 | } 22 | 23 | override fun setContentView(layoutResID: Int) { 24 | super.setContentView(layoutResID) 25 | initView() 26 | } 27 | 28 | override fun onDestroy() { 29 | super.onDestroy() 30 | cancel() 31 | } 32 | 33 | /** 初始化状态栏 34 | * Android 6.0 白底黑字状态栏 35 | * Android 5.0 暗色状态栏 36 | */ 37 | private fun Window.initStatusBar() { 38 | if (SDK_INT >= M) { 39 | decorView.systemUiVisibility = SYSTEM_UI_FLAG_LIGHT_STATUS_BAR 40 | } else if (SDK_INT >= LOLLIPOP) { 41 | statusBarColor = color(R.color.colorGreyBar) 42 | } 43 | } 44 | 45 | /** 初始化界面 */ 46 | abstract fun initView() 47 | } -------------------------------------------------------------------------------- /app/src/main/java/we/zxlite/activity/GuessActivity.kt: -------------------------------------------------------------------------------- 1 | package we.zxlite.activity 2 | 3 | import android.os.Bundle 4 | import kotlinx.android.synthetic.main.activity_guess.* 5 | import kotlinx.coroutines.Dispatchers.Main 6 | import kotlinx.coroutines.launch 7 | import kotlinx.coroutines.withContext 8 | import org.jetbrains.anko.toast 9 | import org.json.JSONArray 10 | import org.json.JSONObject 11 | import we.zxlite.R 12 | import we.zxlite.adapter.GuessItemAdapter 13 | import we.zxlite.dialog.SelectFriendsDialog 14 | import we.zxlite.utils.BaseUtils.EMPTY_STR 15 | import we.zxlite.utils.HttpUtils.Error 16 | import we.zxlite.utils.HttpUtils.Type.JsonObject 17 | import we.zxlite.utils.HttpUtils.Type.JsonArray 18 | import we.zxlite.utils.HttpUtils.api 19 | import we.zxlite.utils.UserUtils.cfg 20 | 21 | class GuessActivity : BaseActivity() { 22 | 23 | companion object { 24 | //获取好友 25 | private const val FRIENDS_URL = "https://app.zhixue.com/study/social/t/getFriends?" 26 | //获取分数 27 | private const val GUESS_URL = "https://app.zhixue.com/study/social/getGuessScore" 28 | //获取班级 29 | private const val GRADE_URL = "https://www.zhixue.com/zhixuebao/studentPK/getClazzByGradeId" 30 | //获取同学 31 | private const val CLAZZ_URL = 32 | "https://www.zhixue.com/zhixuebao/studentPK/getStudentByClazzId" 33 | 34 | private const val SUBJECT_LIST = "subjectList" 35 | private const val SUBJECT_CODE = "subjectCode" 36 | private const val STUDENT_PK_DTOS = "studentPKDTOs" 37 | private const val EXAM_ID = "examId" 38 | private const val FRIENDS = "friends" 39 | private const val USER_NAME = "userName" 40 | private const val USER_ID = "userId" 41 | private const val NAME_LIST = "nameList" 42 | private const val IS_SELF = "isSelf" 43 | private const val CLAZZ_ID = "clazzId" 44 | private const val STUDENT_ID = "studentId" 45 | private const val STUDENT_NAME = "studentName" 46 | } 47 | 48 | private var friendsId = mutableListOf() 49 | private var friendsName = mutableListOf() 50 | 51 | private var mList = mutableMapOf() 52 | private var fList = mutableMapOf() 53 | 54 | override fun onCreate(savedInstanceState: Bundle?) { 55 | super.onCreate(savedInstanceState) 56 | setContentView(R.layout.activity_guess) 57 | loadFriends() 58 | } 59 | 60 | override fun initView() { 61 | setSupportActionBar(guessBar) 62 | guessBar.setNavigationOnClickListener { onBackPressed() } 63 | guessRecycler.adapter = GuessItemAdapter(mList, fList) 64 | guessSelect.setOnClickListener { 65 | if (friendsId.isNotEmpty() && friendsName.isNotEmpty()) SelectFriendsDialog { i -> 66 | mList.clear() 67 | fList.clear() 68 | guessSelectText.text = friendsName[i] 69 | guessRecycler.adapter!!.notifyDataSetChanged() 70 | loadScores(i) 71 | }.apply { 72 | arguments = Bundle().apply { putStringArray(NAME_LIST, friendsName.toTypedArray()) } 73 | }.show(supportFragmentManager, EMPTY_STR) 74 | else toast(R.string.noFriends) 75 | } 76 | guessSelect.setOnLongClickListener { 77 | toast(R.string.toastWait) 78 | launch { 79 | api(GRADE_URL, "token=${cfg.serviceToken}", true, JsonArray).let { 80 | if (it is JSONArray) 81 | for (i in 0 until it.length()) { 82 | val clazz = it.optJSONObject(i) 83 | if (clazz.optBoolean(IS_SELF)) 84 | return@let clazz.optString(CLAZZ_ID) 85 | } else null 86 | }?.let { 87 | api(CLAZZ_URL, "clazzId=$it&token=${cfg.serviceToken}", true, JsonArray).run { 88 | if (this is JSONArray) { 89 | friendsId.clear() 90 | friendsName.clear() 91 | for (i in 0 until length()) { 92 | val friends = optJSONObject(i).optJSONArray(FRIENDS) 93 | for (f in 0 until friends!!.length()) { 94 | val friend = friends.optJSONObject(f) 95 | friendsId.add(f, friend.optString(STUDENT_ID)) 96 | friendsName.add(f, friend.optString(STUDENT_NAME)) 97 | } 98 | } 99 | withContext(Main) { 100 | toast(R.string.addSuccess) 101 | } 102 | } 103 | } 104 | } 105 | } 106 | return@setOnLongClickListener true 107 | } 108 | } 109 | 110 | private fun loadScores(position: Int) { 111 | launch { 112 | val guessParams = 113 | "examId=${intent.getStringExtra(EXAM_ID)}&guessUserId=${friendsId[position]}" 114 | api(GUESS_URL, guessParams, true, JsonObject).let { 115 | if (it is JSONObject) { 116 | val dtos = it.optJSONArray(STUDENT_PK_DTOS) 117 | if (dtos != null) { 118 | val mScores = dtos.optJSONObject(0).optJSONArray(SUBJECT_LIST) 119 | for (i in 0 until mScores!!.length()) { 120 | mList[i] = mScores.optJSONObject(i) 121 | } 122 | 123 | val fScores = dtos.optJSONObject(1).optJSONArray(SUBJECT_LIST) 124 | for (i in 0 until fScores!!.length()) { 125 | val json = fScores.optJSONObject(i) 126 | val code = json.optString(SUBJECT_CODE, "0") 127 | fList[code] = json 128 | } 129 | 130 | withContext(Main) { 131 | guessRecycler.adapter!!.notifyItemRangeInserted(0, mList.size) 132 | } 133 | } else Unit 134 | } else withContext(Main) { 135 | toast((it as Error).message) 136 | } 137 | } 138 | } 139 | } 140 | 141 | private fun loadFriends() { 142 | launch { 143 | api(FRIENDS_URL, null, true, JsonObject).let { 144 | if (it is JSONObject) { 145 | val friendArray = it.optJSONArray(FRIENDS) 146 | for (i in 0 until friendArray!!.length()) { 147 | val friend = friendArray.optJSONObject(i) 148 | friendsId.add(i, friend.optString(USER_ID)) 149 | friendsName.add(i, friend.optString(USER_NAME)) 150 | } 151 | } 152 | } 153 | } 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /app/src/main/java/we/zxlite/activity/InitActivity.kt: -------------------------------------------------------------------------------- 1 | package we.zxlite.activity 2 | 3 | import android.os.Bundle 4 | import kotlinx.coroutines.Dispatchers.Main 5 | import kotlinx.coroutines.launch 6 | import kotlinx.coroutines.withContext 7 | import org.jetbrains.anko.startActivity 8 | import we.zxlite.R 9 | import we.zxlite.utils.UserUtils.login 10 | import we.zxlite.utils.UserUtils.updateConfig 11 | 12 | class InitActivity : BaseActivity() { 13 | 14 | override fun onCreate(savedInstanceState: Bundle?) { 15 | super.onCreate(savedInstanceState) 16 | setContentView(R.layout.activity_init) 17 | } 18 | 19 | override fun initView() { 20 | launch { 21 | updateConfig() 22 | withContext(Main) { 23 | if (login()) startActivity() else startActivity() 24 | finish() 25 | } 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /app/src/main/java/we/zxlite/activity/LoginActivity.kt: -------------------------------------------------------------------------------- 1 | package we.zxlite.activity 2 | 3 | import android.os.Bundle 4 | import android.text.Editable 5 | import android.text.TextWatcher 6 | import com.google.android.material.snackbar.BaseTransientBottomBar.LENGTH_SHORT 7 | import com.google.android.material.snackbar.Snackbar 8 | import kotlinx.android.synthetic.main.activity_login.* 9 | import kotlinx.coroutines.Dispatchers.Main 10 | import kotlinx.coroutines.launch 11 | import kotlinx.coroutines.withContext 12 | import org.jetbrains.anko.browse 13 | import org.jetbrains.anko.db.replace 14 | import org.jetbrains.anko.db.select 15 | import org.jetbrains.anko.startActivity 16 | import we.zxlite.R 17 | import we.zxlite.utils.BaseUtils.EMPTY_STR 18 | import we.zxlite.utils.BaseUtils.db 19 | import we.zxlite.utils.SqlUtils.Helper.Companion.ITEM_NAME 20 | import we.zxlite.utils.SqlUtils.Helper.Companion.ITEM_VALUE 21 | import we.zxlite.utils.SqlUtils.Helper.Companion.SELECT_USER 22 | import we.zxlite.utils.SqlUtils.Helper.Companion.TABLE_CFG 23 | import we.zxlite.utils.SqlUtils.Helper.Companion.TABLE_RMB 24 | import we.zxlite.utils.UserUtils.login 25 | 26 | class LoginActivity : BaseActivity() { 27 | 28 | companion object { 29 | private const val FORGET_URL = 30 | "http://pass.changyan.com/forget?customConfig=e3ZpZXdfdHlwZTogIkg1IixoaWRkZW5fbW9kdWxlOiAiZm9yZ2V0QWNjb3VudCIsbG9nbzoiemhpeHVlIix0aGVtZToiZ3JlZW4iLGNhbGxiYWNrX3R5cGU6InBvc3RNZXNzYWdlIixsb2dpbl90eXBlOiJtYW51YWwifQ==" //忘记密码 31 | } 32 | 33 | private val logUserName //获取编辑框账号参数 34 | get() = loginUsername.text.toString() 35 | 36 | private val logUserPwd //获取编辑框密码参数 37 | get() = loginPassword.text.toString() 38 | 39 | override fun onCreate(savedInstanceState: Bundle?) { 40 | super.onCreate(savedInstanceState) 41 | setContentView(R.layout.activity_login) 42 | } 43 | 44 | override fun initView() { 45 | loginUsername.addTextChangedListener(object : TextWatcher { 46 | override fun afterTextChanged(s: Editable) { 47 | if (s.length > 6) db.use { 48 | select(TABLE_RMB, ITEM_VALUE) 49 | .whereSimple("$ITEM_NAME = '${logUserName}'") 50 | .exec { if (moveToFirst()) getString(0) else EMPTY_STR } 51 | .let { loginPassword.setText(it) } 52 | } 53 | } 54 | 55 | override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {} 56 | 57 | override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {} 58 | }) 59 | loginForget.setOnClickListener { browse(FORGET_URL) } 60 | loginReg.setOnClickListener { startActivity() } 61 | loginBtn.setOnClickListener { onLogin() } 62 | db.use { 63 | select(TABLE_CFG, ITEM_VALUE) 64 | .whereSimple("$ITEM_NAME = '$SELECT_USER'") 65 | .exec { if (moveToFirst()) loginUsername.setText(getString(0)) else null } 66 | } 67 | } 68 | 69 | /**检查登录参数 70 | * @param loginName 用户名 71 | * @param loginPwd 用户密码 72 | */ 73 | private fun onLogin(loginName: String = logUserName, loginPwd: String = logUserPwd) { 74 | loginBtn.isEnabled = false 75 | launch { 76 | if (login(loginName, loginPwd)) { 77 | db.use { 78 | replace(TABLE_RMB, ITEM_NAME to loginName, ITEM_VALUE to loginPwd) 79 | replace(TABLE_CFG, ITEM_NAME to SELECT_USER, ITEM_VALUE to loginName) 80 | } 81 | withContext(Main) { 82 | startActivity() 83 | finish() 84 | } 85 | } else withContext(Main) { 86 | loginBtn.isEnabled = true 87 | Snackbar.make(loginBtn, R.string.loginFailed, LENGTH_SHORT).show() 88 | } 89 | } 90 | } 91 | } -------------------------------------------------------------------------------- /app/src/main/java/we/zxlite/activity/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package we.zxlite.activity 2 | 3 | import android.os.Bundle 4 | import android.view.MenuItem 5 | import androidx.appcompat.app.ActionBarDrawerToggle 6 | import com.google.android.material.internal.NavigationMenuView 7 | import com.google.android.material.navigation.NavigationView 8 | import com.google.android.material.snackbar.BaseTransientBottomBar.* 9 | import com.google.android.material.snackbar.Snackbar 10 | import kotlinx.android.synthetic.main.activity_main.* 11 | import kotlinx.android.synthetic.main.header_main.view.* 12 | import org.jetbrains.anko.db.delete 13 | import org.jetbrains.anko.db.replace 14 | import org.jetbrains.anko.db.select 15 | import org.jetbrains.anko.startActivity 16 | import we.zxlite.R 17 | import we.zxlite.dialog.BindDialog 18 | import we.zxlite.dialog.ModifyDialog 19 | import we.zxlite.utils.BaseUtils.EMPTY_STR 20 | import we.zxlite.utils.BaseUtils.db 21 | import we.zxlite.utils.SqlUtils.Helper.Companion.ITEM_NAME 22 | import we.zxlite.utils.SqlUtils.Helper.Companion.ITEM_VALUE 23 | import we.zxlite.utils.SqlUtils.Helper.Companion.REPORT_TYPE 24 | import we.zxlite.utils.SqlUtils.Helper.Companion.SELECT_USER 25 | import we.zxlite.utils.SqlUtils.Helper.Companion.TABLE_CFG 26 | import we.zxlite.utils.UserUtils.cfg 27 | import android.content.Intent 28 | import android.net.Uri 29 | import androidx.swiperefreshlayout.widget.SwipeRefreshLayout 30 | import kotlinx.coroutines.Dispatchers.Main 31 | import kotlinx.coroutines.launch 32 | import kotlinx.coroutines.withContext 33 | import org.jetbrains.anko.email 34 | import org.json.JSONObject 35 | import we.zxlite.adapter.ExamListAdapter 36 | import we.zxlite.adapter.ExamListAdapter.ItemDecoration 37 | import we.zxlite.bean.ReportListBean 38 | import we.zxlite.dialog.AboutDialog 39 | import we.zxlite.dialog.AccountDialog 40 | import we.zxlite.utils.HttpUtils.Error 41 | import we.zxlite.utils.HttpUtils.Type.JsonObject 42 | import we.zxlite.utils.HttpUtils.api 43 | 44 | class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedListener, 45 | SwipeRefreshLayout.OnRefreshListener { 46 | 47 | companion object { 48 | //考试报告 49 | private const val EXAM_TYPE = "EXAM_TYPE" 50 | //作业报告 51 | private const val HOMEWORK_TYPE = "HOMEWORK_TYPE" 52 | //考试列表 53 | private const val EXAM_INFO_LIST = "examInfoList" 54 | //考试id 55 | private const val EXAM_ID = "examId" 56 | //考试名称 57 | private const val EXAM_NAME = "examName" 58 | //考试时间 59 | private const val CREATE_TIME = "examCreateDateTime" 60 | //考试 61 | private const val EXAM = "exam" 62 | //作业 63 | private const val HOMEWORK = "homework" 64 | //页面列表 65 | private const val LIST_URL = "https://www.zhixue.com/zhixuebao/report/getPageExamList" 66 | 67 | private const val QQ_GROUP = 68 | "mqqopensdkapi://bizAgent/qm/qr?url=http%3A%2F%2Fqm.qq.com%2Fcgi-bin%2Fqm%2Fqr%3Ffrom%3Dapp%26p%3Dandroid%26k%3D668tQMrX050v9ChooYRBaRA137b5YbOb" 69 | } 70 | 71 | //报告类型 72 | private val reportType get() = if (mainNav.checkedItem!!.itemId == R.id.menuReportExam) EXAM else HOMEWORK 73 | //报告列表 74 | private val reportList = ArrayList() 75 | //报告页码 76 | private val reportIndex get() = reportList.size / 10 + 1 77 | //报告参数 78 | private val reportParams get() = "reportType=$reportType&pageIndex=$reportIndex&pageSize=10&actualPosition=0" 79 | 80 | override fun onCreate(savedInstanceState: Bundle?) { 81 | super.onCreate(savedInstanceState) 82 | setContentView(R.layout.activity_main) 83 | loadList() 84 | } 85 | 86 | override fun initView() { 87 | setSupportActionBar(mainBar) 88 | val toggle = 89 | ActionBarDrawerToggle(this, mainDrawer, mainBar, R.string.appName, R.string.appName) 90 | val menuView = mainNav.getChildAt(0) as NavigationMenuView 91 | mainDrawer.addDrawerListener(toggle) 92 | toggle.syncState() 93 | menuView.isVerticalScrollBarEnabled = false 94 | mainNav.getHeaderView(0).headerTitle.text = cfg.curName 95 | db.use { 96 | select(TABLE_CFG, ITEM_VALUE) 97 | .whereSimple("$ITEM_NAME = '$REPORT_TYPE'") 98 | .exec { if (moveToFirst()) getString(0) else EXAM_TYPE } 99 | .let { mainNav.setCheckedItem(if (it == EXAM_TYPE) R.id.menuReportExam else R.id.menuReportHomework) } 100 | } 101 | mainNav.setNavigationItemSelectedListener(this) 102 | mainRefresh.setOnRefreshListener(this) 103 | mainFab.setOnClickListener { if (!mainRefresh.isRefreshing) loadList() } 104 | mainRecycler.addItemDecoration(ItemDecoration()) 105 | mainRecycler.adapter = ExamListAdapter(reportList) { examId, examName -> 106 | startActivity(EXAM_ID to examId, EXAM_NAME to examName) 107 | } 108 | } 109 | 110 | override fun onNavigationItemSelected(item: MenuItem): Boolean { 111 | when (item.itemId) { 112 | R.id.menuReportExam -> changeReportType(EXAM_TYPE, item) 113 | R.id.menuReportHomework -> changeReportType(HOMEWORK_TYPE, item) 114 | R.id.menuUpdate -> onUpdate() 115 | R.id.menuLogout -> onLogout() 116 | R.id.menuFeedback -> onFeedback() 117 | R.id.menuSwitchAccount -> AccountDialog().show(supportFragmentManager, EMPTY_STR) 118 | R.id.menuAbout -> AboutDialog().show(supportFragmentManager, EMPTY_STR) 119 | R.id.menuBindMobile -> BindDialog().show(supportFragmentManager, EMPTY_STR) 120 | R.id.menuModifyPwd -> ModifyDialog().show(supportFragmentManager, EMPTY_STR) 121 | else -> Unit 122 | } 123 | return true 124 | } 125 | 126 | override fun onRefresh() { 127 | if (reportList.size == 0) loadList() else mainRefresh.isRefreshing = false 128 | } 129 | 130 | /** 改变报告类型 131 | * @param type 报告类型 132 | * @param item 菜单项 133 | */ 134 | private fun changeReportType(type: String, item: MenuItem) { 135 | db.use { replace(TABLE_CFG, ITEM_NAME to REPORT_TYPE, ITEM_VALUE to type) } 136 | mainNav.setCheckedItem(item) 137 | mainFab.hide() 138 | mainDrawer.closeDrawers() 139 | mainRecycler.adapter!!.notifyItemRangeRemoved(0, reportList.size) 140 | reportList.clear() 141 | loadList() 142 | } 143 | 144 | /** 加载报告 */ 145 | private fun loadList() { 146 | mainRefresh.isRefreshing = true 147 | launch { 148 | api(LIST_URL, reportParams, true, JsonObject).let { 149 | if (it is JSONObject) { 150 | val listOldSize = reportList.size 151 | val examInfoList = it.optJSONArray(EXAM_INFO_LIST) 152 | for (i in 0 until examInfoList!!.length()) { 153 | val item = examInfoList.optJSONObject(i) 154 | reportList.add( 155 | ReportListBean( 156 | examId = item.optString(EXAM_ID), 157 | examName = item.optString(EXAM_NAME), 158 | examCreateTime = item.optLong(CREATE_TIME) 159 | ) 160 | ) 161 | } 162 | withContext(Main) { 163 | if (reportList.size % 10 == 0) mainFab.show() else mainFab.hide() 164 | mainRefresh.isRefreshing = false 165 | mainRecycler.adapter!!.notifyItemRangeInserted( 166 | listOldSize, 167 | reportList.size - listOldSize 168 | ) 169 | } 170 | } else if (it is Error) withContext(Main) { 171 | mainRefresh.isRefreshing = false 172 | Snackbar.make(mainDrawer, it.message, LENGTH_SHORT).show() 173 | } 174 | } 175 | } 176 | } 177 | 178 | /** 意见反馈 */ 179 | private fun onFeedback() { 180 | Snackbar 181 | .make(mainDrawer, R.string.toastFeedback, LENGTH_LONG) 182 | .setAction(R.string.actionConfirm) { 183 | if (!email("mail-westudio@gmail.com", "智学网Lite意见反馈")) { 184 | Snackbar.make(mainDrawer, R.string.invokeMailFailed, LENGTH_SHORT).show() 185 | } 186 | } 187 | .show() 188 | } 189 | 190 | /** 检测更新 */ 191 | private fun onUpdate() { 192 | Snackbar 193 | .make(mainDrawer, R.string.toastUpdate, LENGTH_LONG) 194 | .setAction(R.string.actionConfirm) { 195 | try { 196 | startActivity(Intent().apply { data = Uri.parse(QQ_GROUP) }) 197 | } catch (e: Exception) { 198 | Snackbar.make(mainDrawer, R.string.invokeQQFailed, LENGTH_SHORT).show() 199 | } 200 | } 201 | .show() 202 | } 203 | 204 | /** 注销登录 */ 205 | private fun onLogout() { 206 | Snackbar 207 | .make(mainDrawer, R.string.toastLogout, LENGTH_LONG) 208 | .setAction(R.string.actionConfirm) { 209 | cfg.clean()//清空当前信息 210 | db.use { 211 | delete(TABLE_CFG, "$ITEM_NAME = {$SELECT_USER}", SELECT_USER to SELECT_USER) 212 | } 213 | startActivity() 214 | finish() 215 | } 216 | .show() 217 | } 218 | } 219 | -------------------------------------------------------------------------------- /app/src/main/java/we/zxlite/activity/PaperActivity.kt: -------------------------------------------------------------------------------- 1 | package we.zxlite.activity 2 | 3 | import android.annotation.SuppressLint 4 | import android.os.Bundle 5 | import kotlinx.android.synthetic.main.activity_paper.* 6 | import we.zxlite.R 7 | import we.zxlite.utils.UserUtils.cfg 8 | 9 | class PaperActivity : BaseActivity() { 10 | 11 | companion object { 12 | //原卷 13 | private const val PAPER_URL = "https://www.zhixue.com/studentanswer/index.html" 14 | //原卷id 15 | private const val PAPER_ID = "paperId" 16 | } 17 | 18 | //原卷URL 19 | private val paperUrl get() = "$PAPER_URL?token=${cfg.serviceToken}&paperId=$paperId" 20 | //原卷id 21 | private val paperId get() = intent.getStringExtra(PAPER_ID) 22 | 23 | override fun onCreate(savedInstanceState: Bundle?) { 24 | super.onCreate(savedInstanceState) 25 | setContentView(R.layout.activity_paper) 26 | paperWeb.loadUrl(paperUrl) 27 | } 28 | 29 | @SuppressLint("SetJavaScriptEnabled") 30 | override fun initView() { 31 | setSupportActionBar(paperBar) 32 | paperBar.setNavigationOnClickListener { onBackPressed() } 33 | paperWeb.settings.apply { 34 | setSupportZoom(true) 35 | javaScriptEnabled = true 36 | builtInZoomControls = true 37 | displayZoomControls = false 38 | loadWithOverviewMode = true 39 | useWideViewPort = true 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /app/src/main/java/we/zxlite/activity/RegisterActivity.kt: -------------------------------------------------------------------------------- 1 | package we.zxlite.activity 2 | 3 | import android.graphics.drawable.ColorDrawable 4 | import android.os.Bundle 5 | import com.bumptech.glide.load.resource.bitmap.CenterCrop 6 | import com.bumptech.glide.load.resource.bitmap.RoundedCorners 7 | import com.google.android.material.snackbar.BaseTransientBottomBar.LENGTH_SHORT 8 | import com.google.android.material.snackbar.Snackbar 9 | import kotlinx.android.synthetic.main.activity_register.* 10 | import kotlinx.coroutines.Dispatchers.Main 11 | import kotlinx.coroutines.launch 12 | import kotlinx.coroutines.withContext 13 | import org.json.JSONObject 14 | import we.zxlite.GlideApp 15 | import we.zxlite.R 16 | import we.zxlite.utils.BaseUtils.EMPTY_STR 17 | import we.zxlite.utils.BaseUtils.color 18 | import we.zxlite.utils.BaseUtils.bitmap 19 | import we.zxlite.utils.BaseUtils.rc4 20 | import we.zxlite.utils.HttpUtils.Error 21 | import we.zxlite.utils.HttpUtils.Type.JsonObject 22 | import we.zxlite.utils.HttpUtils.connApi 23 | 24 | class RegisterActivity : BaseActivity() { 25 | 26 | //获取图像标识 27 | private var sid = EMPTY_STR 28 | //获取图像 29 | private var img = EMPTY_STR 30 | //获取编辑框手机号码 31 | private val regPhone get() = regPhoneNumber.text.toString() 32 | //获取编辑框密码 33 | private val regPwd get() = regPassword.text.toString().rc4 34 | //获取编辑框图形验证码 35 | private val regImage get() = regImgCode.text.toString() 36 | //获取编辑框手机验证码 37 | private val regSms get() = regSmsCode.text.toString() 38 | //短信参数 39 | private val smsParams get() = "checkCode=$regImage&mobile=$regPhone&passwd=$regPwd&sid=$sid" 40 | //注册参数 41 | private val regParams get() = "passwd=$regPwd&role=parent&smsCode=$regSms&sid=$sid" 42 | 43 | companion object { 44 | private const val REG_URL = "https://www.zhixue.com/container/app/reg/register" //注册账号 45 | private const val IMG_URL = 46 | "https://www.zhixue.com/container/app/reg/getImageCode" //获取图像验证码 47 | private const val SMS_URL = "https://www.zhixue.com/container/app/reg/getSmsCode" //获取手机验证码 48 | 49 | private const val IMG = "image" 50 | private const val SID = "sid" 51 | } 52 | 53 | override fun onCreate(savedInstanceState: Bundle?) { 54 | super.onCreate(savedInstanceState) 55 | setContentView(R.layout.activity_register) 56 | loadCode() //加载验证码 57 | } 58 | 59 | override fun initView() { 60 | regImgBtn.setOnClickListener { loadCode() } 61 | regSmsBtn.setOnClickListener { getSms() } 62 | regBtn.setOnClickListener { onReg() } 63 | } 64 | 65 | /**获取图形验证码*/ 66 | private fun loadCode() = launch { 67 | connApi(IMG_URL, EMPTY_STR, false, JsonObject).let { 68 | if (it is JSONObject) { 69 | sid = it.optString(SID) 70 | img = it.optString(IMG) 71 | GlideApp 72 | .with(this@RegisterActivity) 73 | .load(img.bitmap) 74 | .transform(CenterCrop(), RoundedCorners(8)) 75 | .into(regImg) 76 | } else { 77 | GlideApp 78 | .with(this@RegisterActivity) 79 | .load(ColorDrawable(color(R.color.colorSubTitle))) 80 | .transform(CenterCrop(), RoundedCorners(8)) 81 | .into(regImg) 82 | } 83 | } 84 | } 85 | 86 | /** 获取短信验证码 */ 87 | private fun getSms() { 88 | if (regPhone.isNotEmpty() && regPwd.isNotEmpty() && regImage.isNotEmpty()) launch { 89 | connApi(SMS_URL, smsParams, false, JsonObject).let { 90 | withContext(Main) { 91 | if (it is JSONObject) 92 | Snackbar.make(regSmsBtn, R.string.smsSuccess, LENGTH_SHORT).show() 93 | else if (it is Error) { 94 | loadCode() 95 | Snackbar.make(regSmsBtn, it.message, LENGTH_SHORT).show() 96 | } 97 | } 98 | } 99 | } else Snackbar.make(regSmsBtn, R.string.valueIncorrect, LENGTH_SHORT).show() 100 | } 101 | 102 | /** 注册账号 */ 103 | private fun onReg() { 104 | regBtn.isEnabled = false 105 | launch { 106 | connApi(REG_URL, regParams, false, JsonObject).let { 107 | withContext(Main) { 108 | if (it is JSONObject) 109 | Snackbar.make(regSmsBtn, R.string.regSuccess, Snackbar.LENGTH_INDEFINITE) 110 | .setAction(R.string.actionReturn) { finish() } 111 | .show() 112 | else if (it is Error) 113 | Snackbar.make(regBtn, it.message, LENGTH_SHORT).show() 114 | regBtn.isEnabled = true 115 | } 116 | } 117 | } 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /app/src/main/java/we/zxlite/activity/ReportActivity.kt: -------------------------------------------------------------------------------- 1 | package we.zxlite.activity 2 | 3 | import android.os.Bundle 4 | import android.view.Menu 5 | import android.view.MenuItem 6 | import com.github.mikephil.charting.data.Entry 7 | import com.google.android.material.tabs.TabLayoutMediator 8 | import com.google.android.material.tabs.TabLayoutMediator.TabConfigurationStrategy 9 | import kotlinx.android.synthetic.main.activity_report.* 10 | import kotlinx.coroutines.Dispatchers.Main 11 | import kotlinx.coroutines.launch 12 | import kotlinx.coroutines.withContext 13 | import org.jetbrains.anko.startActivity 14 | import org.jetbrains.anko.toast 15 | import org.json.JSONObject 16 | import we.zxlite.R 17 | import we.zxlite.adapter.ReportPageAdapter 18 | import we.zxlite.bean.ReportPageBean 19 | import we.zxlite.utils.BaseUtils.EMPTY_STR 20 | import we.zxlite.utils.HttpUtils.Error 21 | import we.zxlite.utils.HttpUtils.api 22 | import we.zxlite.utils.HttpUtils.Type.JsonObject 23 | 24 | class ReportActivity : BaseActivity() { 25 | 26 | companion object { 27 | //报告 28 | private const val REPORT_URL = "https://www.zhixue.com/zhixuebao/report/exam/getReportMain" 29 | //表 30 | private const val CHART_URL = "https://www.zhixue.com/zhixuebao/report/paper/getLevelTrend" 31 | //报告列表 32 | private const val PAPER_LIST = "paperList" 33 | //列表 34 | private const val LIST = "list" 35 | //报告id 36 | private const val EXAM_ID = "examId" 37 | //报告名称 38 | private const val EXAM_NAME = "examName" 39 | //标题 40 | private const val TITLE = "title" 41 | //考卷id 42 | private const val PAPER_ID = "paperId" 43 | //考卷名 44 | private const val PAPER_NAME = "paperName" 45 | //总分 46 | private const val STANDARD_SCORE = "standardScore" 47 | //用户得分 48 | private const val USER_SCORE = "userScore" 49 | //学科码 50 | private const val SUBJECT_CODE = "subjectCode" 51 | // 学科名 52 | private const val SUBJECT_NAME = "subjectName" 53 | //数据列表 54 | private const val DATA_LIST = "dataList" 55 | //等级 56 | private const val LEVEL = "level" 57 | //标识 58 | private const val TAG = "tag" 59 | //名称 60 | private const val NAME = "name" 61 | //全科 62 | private const val GENERAL_SUBJECT = "全科" 63 | } 64 | 65 | //报告页列表 66 | private val reportPageList = ArrayList() 67 | //报告id 68 | private val examId get() = intent.getStringExtra(EXAM_ID) 69 | //水平趋势 70 | private val String.levelTrend: Float 71 | get() { 72 | return when (this) { 73 | "A等" -> 8F 74 | "A1" -> 8F 75 | "A2" -> 7.6F 76 | "A3" -> 7.2F 77 | "A4" -> 6.8F 78 | "A5" -> 6.4F 79 | "B等" -> 6F 80 | "B1" -> 6F 81 | "B2" -> 5.6F 82 | "B3" -> 5.2F 83 | "B4" -> 4.8F 84 | "B5" -> 4.4F 85 | "C等" -> 4F 86 | "C1" -> 4F 87 | "C2" -> 3.6F 88 | "C3" -> 3.2F 89 | "C4" -> 2.8F 90 | "C5" -> 2.4F 91 | "D等" -> 2F 92 | "D1" -> 2F 93 | "D2" -> 1.6F 94 | "D3" -> 1.2F 95 | "D4" -> 0.8F 96 | "D5" -> 0.4F 97 | else -> 0.15F 98 | } 99 | } 100 | 101 | override fun onCreate(savedInstanceState: Bundle?) { 102 | super.onCreate(savedInstanceState) 103 | setContentView(R.layout.activity_report) 104 | loadReport() 105 | } 106 | 107 | override fun onCreateOptionsMenu(menu: Menu?): Boolean { 108 | menuInflater.inflate(R.menu.menu_report, menu) 109 | return true 110 | } 111 | 112 | override fun onOptionsItemSelected(item: MenuItem): Boolean { 113 | val selected = reportPageList[reportPager.currentItem].paperId 114 | if (selected.isEmpty() && item.itemId != R.id.menuGuess) { 115 | toast(R.string.showError) 116 | return true 117 | } 118 | when (item.itemId) { 119 | R.id.menuAnalyze -> startActivity(PAPER_ID to selected) 120 | R.id.menuPaper -> startActivity(PAPER_ID to selected) 121 | R.id.menuGuess -> startActivity(EXAM_ID to examId) 122 | } 123 | return true 124 | } 125 | 126 | override fun initView() { 127 | setSupportActionBar(reportBar) 128 | reportBar.setNavigationOnClickListener { onBackPressed() } 129 | reportPager.offscreenPageLimit = 5 130 | reportPager.adapter = ReportPageAdapter(reportPageList) { chart, id -> 131 | launch { 132 | val chartParams = "paperId=$id&pageIndex=1&pageSize=5&examId=$examId" 133 | api(CHART_URL, chartParams, true, JsonObject).let { 134 | if (it is JSONObject) { 135 | val chartList = it.optJSONArray(LIST) 136 | for (i in 0 until chartList!!.length()) { 137 | val entries = ArrayList() 138 | val item = chartList.optJSONObject(i) 139 | val itemName = item.optJSONObject(TAG)!!.optString(NAME) 140 | val dataList = item.optJSONArray(DATA_LIST) 141 | for (data in 0 until dataList!!.length()) { 142 | val levelTrend = 143 | dataList.optJSONObject(data).optString(LEVEL).levelTrend 144 | entries.add(Entry(data * 2f, levelTrend)) 145 | } 146 | chart.addLine(itemName, entries, i * 5f) 147 | } 148 | withContext(Main) { 149 | chart.tag = true 150 | chart.legend.setCustom(chart.legendEntries) 151 | chart.notifyDataSetChanged() 152 | chart.invalidate() 153 | } 154 | } 155 | } 156 | } 157 | } 158 | TabLayoutMediator(reportTab, reportPager, TabConfigurationStrategy { tab, position -> 159 | tab.text = reportPageList[position].title 160 | }).attach() 161 | } 162 | 163 | /** 加载报告 */ 164 | private fun loadReport() { 165 | launch { 166 | val reportParams = "examId=$examId" 167 | api(REPORT_URL, reportParams, true, JsonObject).let { 168 | if (it is JSONObject) { 169 | val reportList = it.optJSONArray(PAPER_LIST) 170 | var totalStandardScore = 0.00 171 | var totalUserScore = 0.00 172 | for (i in 0 until reportList!!.length()) { 173 | val item = reportList.optJSONObject(i) 174 | if (item.optString(TITLE) != "理综" && item.optString(TITLE) != "文综") { 175 | totalStandardScore += item.optDouble(STANDARD_SCORE) 176 | totalUserScore += item.optDouble(USER_SCORE) 177 | } 178 | reportPageList.add( 179 | ReportPageBean( 180 | title = item.optString(TITLE), 181 | paperId = item.optString(PAPER_ID), 182 | paperName = item.optString(PAPER_NAME), 183 | standardScore = item.optDouble(STANDARD_SCORE), 184 | userScore = item.optDouble(USER_SCORE), 185 | subjectCode = item.optInt(SUBJECT_CODE), 186 | subjectName = item.optString(SUBJECT_NAME) 187 | ) 188 | ) 189 | } 190 | if (reportList.length() > 1) 191 | reportPageList.add( 192 | 0, 193 | ReportPageBean( 194 | title = GENERAL_SUBJECT, 195 | paperId = EMPTY_STR, 196 | paperName = intent.getStringExtra(EXAM_NAME)!!, 197 | standardScore = totalStandardScore, 198 | userScore = totalUserScore, 199 | subjectCode = -1, 200 | subjectName = EMPTY_STR 201 | ) 202 | ) 203 | withContext(Main) { 204 | reportPager.adapter!!.notifyItemRangeInserted(0, reportPageList.size) 205 | } 206 | } else withContext(Main) { 207 | toast((it as Error).message) 208 | } 209 | } 210 | } 211 | } 212 | } 213 | -------------------------------------------------------------------------------- /app/src/main/java/we/zxlite/adapter/AnalyzeListAdapter.kt: -------------------------------------------------------------------------------- 1 | package we.zxlite.adapter 2 | 3 | import android.text.Html.TagHandler 4 | import android.view.LayoutInflater.from 5 | import android.view.View 6 | import android.view.ViewGroup 7 | import android.widget.TextView 8 | import androidx.core.text.HtmlCompat 9 | import androidx.core.text.HtmlCompat.FROM_HTML_MODE_LEGACY 10 | import androidx.recyclerview.widget.RecyclerView 11 | import kotlinx.android.synthetic.main.item_analyze.view.* 12 | import we.zxlite.R 13 | import we.zxlite.bean.AnalyzeListBean 14 | import we.zxlite.utils.GetterUtils.ImageGetter 15 | 16 | class AnalyzeListAdapter(private val analyzeList: ArrayList) : 17 | RecyclerView.Adapter() { 18 | 19 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = 20 | ViewHolder(from(parent.context).inflate(R.layout.item_analyze, parent, false)) 21 | 22 | override fun onBindViewHolder(holder: ViewHolder, position: Int) { 23 | holder.itemTitle.text = analyzeList[position].title 24 | holder.itemContent.text = HtmlCompat.fromHtml(analyzeList[position].content, 25 | FROM_HTML_MODE_LEGACY, 26 | ImageGetter(holder.itemContent), 27 | TagHandler { opening, tag, output, _ -> 28 | if (!opening && tag != null && tag.contentEquals("td")) output.append('\n') 29 | }) 30 | } 31 | 32 | override fun getItemCount() = analyzeList.size 33 | 34 | class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { 35 | val itemTitle: TextView = itemView.itemTitle 36 | val itemContent: TextView = itemView.itemContent 37 | } 38 | } -------------------------------------------------------------------------------- /app/src/main/java/we/zxlite/adapter/AnalyzePageAdapter.kt: -------------------------------------------------------------------------------- 1 | package we.zxlite.adapter 2 | 3 | import android.graphics.Rect 4 | import android.view.View 5 | import android.view.ViewGroup 6 | import android.view.LayoutInflater.from 7 | import androidx.recyclerview.widget.RecyclerView 8 | import kotlinx.coroutines.Dispatchers.Main 9 | import kotlinx.coroutines.GlobalScope 10 | import kotlinx.coroutines.launch 11 | import kotlinx.coroutines.withContext 12 | import org.json.JSONArray 13 | import we.zxlite.R 14 | import we.zxlite.bean.AnalyzeListBean 15 | import we.zxlite.bean.AnalyzePageBean 16 | 17 | class AnalyzePageAdapter(private val analyzeList: ArrayList) : 18 | RecyclerView.Adapter() { 19 | 20 | companion object { 21 | private const val TITLE_TOPIC = "题目" 22 | private const val TITLE_MY_SCORE = "我的得分" 23 | private const val TITLE_MY_ANSWER = "我的答案" 24 | private const val TITLE_ANALYSIS = "题目解析" 25 | private const val TITLE_CORRECT = "正确答案" 26 | private const val TITLE_KNOW_LEDGES = "知识点" 27 | 28 | private const val SCORE = "score" 29 | private const val NAME = "name" 30 | private const val TOPIC_NUM = "topicNum" 31 | private const val USER_ANSWER = "userAnswer" 32 | private const val STAND_SCORE = "standScore" 33 | private const val DISP_TITLE = "dispTitle" 34 | private const val KNOW_LEDGES = "relatedKnowledges" 35 | } 36 | 37 | private val Int.topic get() = AnalyzeListBean(TITLE_TOPIC, analyzeList[this].contentHtml) 38 | 39 | private val String.analysis get() = AnalyzeListBean(TITLE_ANALYSIS, this) 40 | 41 | private val String.imgAnswer: AnalyzeListBean 42 | get() { 43 | val array = JSONArray(this) 44 | val answers = StringBuilder() 45 | for (i in 0 until array.length()) { 46 | answers.append("") 47 | } 48 | return AnalyzeListBean(TITLE_MY_ANSWER, answers.toString()) 49 | } 50 | 51 | private val String.answer: AnalyzeListBean? 52 | get() { 53 | val mAnswers = StringBuilder() 54 | val answers = JSONArray(this) 55 | for (i in 0 until answers.length()) { 56 | val item = answers.getJSONObject(i) 57 | mAnswers.append("${item.optInt(TOPIC_NUM)}.${item.optString(USER_ANSWER)};") 58 | } 59 | return if (mAnswers.isNotEmpty()) 60 | AnalyzeListBean(TITLE_MY_ANSWER, mAnswers.toString()) 61 | else null 62 | } 63 | 64 | private val String.standard: AnalyzeListBean 65 | get() { 66 | var answer = this 67 | if (this.startsWith("https://")) answer = "" 68 | return AnalyzeListBean(TITLE_CORRECT, answer) 69 | } 70 | 71 | private val String.knowledge: AnalyzeListBean 72 | get() { 73 | val buffer = StringBuilder() 74 | val groups = JSONArray(this) 75 | for (i in 0 until groups.length()) { 76 | val knowledge = groups.optJSONObject(i) 77 | val dispTitle = knowledge.optString(DISP_TITLE) 78 | val knowledges = knowledge.optJSONArray(KNOW_LEDGES) 79 | if (dispTitle.isNotEmpty() && groups.length() != 1) 80 | buffer.append("第 $dispTitle 题: ") 81 | for (it in 0 until knowledges!!.length()) { 82 | buffer.append(knowledges.optJSONObject(it).optString(NAME)) 83 | if (it != knowledges.length() - 1) buffer.append(";") 84 | } 85 | buffer.append("
") 86 | } 87 | return AnalyzeListBean(TITLE_KNOW_LEDGES, buffer.toString()) 88 | } 89 | 90 | private val String.score: AnalyzeListBean? 91 | get() { 92 | return if (this.isNotEmpty()) { 93 | val array = JSONArray(this) 94 | val scores = StringBuilder() 95 | for (i in 0 until array.length()) { 96 | val item = array.optJSONObject(i) 97 | scores.append( 98 | "第 ${item.optString(DISP_TITLE)} 题:  " + 99 | "${item.optString(SCORE)} 分 / " + 100 | "${item.optString(STAND_SCORE)} 分" 101 | ) 102 | if (array.length() != i + 1) scores.append("
") 103 | } 104 | AnalyzeListBean(TITLE_MY_SCORE, scores.toString()) 105 | } else null 106 | } 107 | 108 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder = 109 | ViewHolder((from(parent.context) 110 | .inflate(R.layout.fragment_analyze, parent, false) as RecyclerView).apply { 111 | addItemDecoration(ItemDecoration()) 112 | setHasFixedSize(true) 113 | }) 114 | 115 | override fun getItemCount() = analyzeList.size 116 | 117 | override fun onBindViewHolder(holder: ViewHolder, i: Int) { 118 | GlobalScope.launch { 119 | val list = ArrayList() 120 | analyzeList[i].run { 121 | if (contentHtml.isNotEmpty()) list.add(i.topic) 122 | if (topicScoreDTOs.score == null) { 123 | list.add( 124 | AnalyzeListBean( 125 | TITLE_MY_SCORE, 126 | "第 $disTitleNumber 题:  $score 分 / $standardScore 分" 127 | ) 128 | ) 129 | } else list.add(topicScoreDTOs.score!!) 130 | if (answerType == "s01Text") 131 | list.add(AnalyzeListBean(TITLE_MY_ANSWER, userAnswer)) 132 | else if (userAnswers.isNotEmpty() && userAnswers.answer != null) 133 | list.add(userAnswers.answer!!) 134 | if (imageAnswers.isNotEmpty()) list.add(imageAnswers.imgAnswer) 135 | if (standardAnswer.isNotEmpty() && answerHtml == "略") 136 | list.add(standardAnswer.standard) 137 | else 138 | list.add(AnalyzeListBean(TITLE_CORRECT, answerHtml)) 139 | if (analysisHtml.isNotEmpty()) list.add(analysisHtml.analysis) 140 | if (relatedKnowledgeGroups.isNotEmpty()) list.add(relatedKnowledgeGroups.knowledge) 141 | } 142 | withContext(Main) { 143 | (holder.itemView as RecyclerView).adapter = AnalyzeListAdapter(list) 144 | } 145 | } 146 | } 147 | 148 | class ViewHolder(itemView: RecyclerView) : RecyclerView.ViewHolder(itemView) 149 | 150 | class ItemDecoration : RecyclerView.ItemDecoration() { 151 | override fun getItemOffsets( 152 | outRect: Rect, 153 | view: View, 154 | parent: RecyclerView, 155 | state: RecyclerView.State 156 | ) { 157 | super.getItemOffsets(outRect, view, parent, state) 158 | outRect.top = 159 | if (parent.getChildAdapterPosition(view) == 0) 56 else 24 160 | outRect.bottom = 24 161 | outRect.left = 48 162 | outRect.right = 48 163 | } 164 | } 165 | } -------------------------------------------------------------------------------- /app/src/main/java/we/zxlite/adapter/ExamListAdapter.kt: -------------------------------------------------------------------------------- 1 | package we.zxlite.adapter 2 | 3 | import android.graphics.Rect 4 | import android.view.LayoutInflater.from 5 | import android.view.View 6 | import android.view.ViewGroup 7 | import android.widget.TextView 8 | import androidx.recyclerview.widget.RecyclerView 9 | import kotlinx.android.synthetic.main.item_report.view.* 10 | import we.zxlite.R 11 | import we.zxlite.bean.ReportListBean 12 | import java.text.SimpleDateFormat 13 | import java.util.* 14 | import java.util.Locale.getDefault 15 | import kotlin.collections.ArrayList 16 | 17 | class ExamListAdapter( 18 | private var reportList: ArrayList, 19 | private val callback: (String, String) -> Unit 20 | ) : RecyclerView.Adapter(), View.OnClickListener { 21 | 22 | companion object { 23 | private const val minute = 60 * 1000L //分 24 | private const val hour = 60 * minute //时 25 | private const val day = 24 * hour //日 26 | private const val month = 30 * day // 月 27 | private const val year = 12 * month//年 28 | } 29 | 30 | /** 获取Num */ 31 | private val Int.num: String 32 | get() = when { 33 | this < 10 -> "0$this" 34 | this in 10..99 -> this.toString() 35 | else -> "9+" 36 | } 37 | 38 | /** 获取时间字符 */ 39 | private val Long.timeFormat: String 40 | get() { 41 | val date = Date().time - Date(this).time 42 | return when { 43 | date > year -> "${date / year} 年前" 44 | date > month -> "${date / month} 个月前" 45 | date > day -> "${date / day} 天前" 46 | date > hour -> "${date / hour} 小时前" 47 | date > minute -> "${date / minute} 分钟前" 48 | else -> "刚刚" 49 | } + " | " + SimpleDateFormat("yyyy-MM-dd", getDefault()).format(this) 50 | } 51 | 52 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = 53 | ViewHolder(from(parent.context).inflate(R.layout.item_report, parent, false)) 54 | 55 | override fun onBindViewHolder(holder: ViewHolder, position: Int) { 56 | val reportItem = reportList[position] 57 | holder.itemNum.text = (position + 1).num 58 | holder.itemTitle.text = reportItem.examName 59 | holder.itemSubTitle.text = reportItem.examCreateTime.timeFormat 60 | 61 | holder.itemView.tag = reportItem.examId 62 | holder.itemView.setOnClickListener(this@ExamListAdapter) 63 | } 64 | 65 | override fun getItemCount() = reportList.size 66 | 67 | override fun onClick(v: View) { 68 | callback(v.tag.toString(), v.itemTitle.text.toString()) 69 | } 70 | 71 | class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { 72 | val itemNum: TextView = itemView.itemNum 73 | val itemTitle: TextView = itemView.itemTitle 74 | val itemSubTitle: TextView = itemView.itemSubTitle 75 | } 76 | 77 | class ItemDecoration : RecyclerView.ItemDecoration() { 78 | override fun getItemOffsets( 79 | outRect: Rect, 80 | view: View, 81 | parent: RecyclerView, 82 | state: RecyclerView.State 83 | ) { 84 | super.getItemOffsets(outRect, view, parent, state) 85 | outRect.top = if (parent.getChildAdapterPosition(view) == 0) 16 else 8 86 | outRect.bottom = 8 87 | } 88 | } 89 | } -------------------------------------------------------------------------------- /app/src/main/java/we/zxlite/adapter/GuessItemAdapter.kt: -------------------------------------------------------------------------------- 1 | package we.zxlite.adapter 2 | 3 | import android.graphics.Color 4 | import android.view.LayoutInflater.from 5 | import android.view.View 6 | import android.view.ViewGroup 7 | import android.widget.TextView 8 | import androidx.recyclerview.widget.RecyclerView 9 | import kotlinx.android.synthetic.main.item_guess.view.* 10 | import org.json.JSONObject 11 | import we.zxlite.R 12 | 13 | class GuessItemAdapter( 14 | private val mList: Map, 15 | private val fList: Map 16 | ) : 17 | RecyclerView.Adapter() { 18 | 19 | companion object { 20 | private const val SUBJECT_NAME = "subjectName" 21 | private const val SUBJECT_CODE = "subjectCode" 22 | private const val SCORE = "score" 23 | } 24 | 25 | private var correctColor = Color.DKGRAY 26 | private var mistakeColor = Color.RED 27 | 28 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = 29 | ViewHolder(from(parent.context).inflate(R.layout.item_guess, parent, false)) 30 | 31 | override fun getItemCount() = mList.size 32 | 33 | override fun onBindViewHolder(holder: ViewHolder, position: Int) { 34 | val value = mList.getValue(position) 35 | val code = value.optString(SUBJECT_CODE, "0") 36 | val mScore = value.optDouble(SCORE) 37 | val fScore = fList[code]?.optDouble(SCORE) ?: 0.0 38 | holder.itemSubject.text = value.optString(SUBJECT_NAME) 39 | holder.itemMyScore.text = 40 | mScore.toBigDecimal().stripTrailingZeros().toPlainString() 41 | holder.itemGuessScore.text = 42 | fScore.toBigDecimal().stripTrailingZeros().toPlainString() 43 | when { 44 | mScore > fScore -> { 45 | holder.itemMyScore.setTextColor(correctColor) 46 | holder.itemGuessScore.setTextColor(mistakeColor) 47 | } 48 | mScore < fScore -> { 49 | holder.itemMyScore.setTextColor(mistakeColor) 50 | holder.itemGuessScore.setTextColor(correctColor) 51 | } 52 | else -> { 53 | holder.itemMyScore.setTextColor(correctColor) 54 | holder.itemGuessScore.setTextColor(correctColor) 55 | } 56 | } 57 | } 58 | 59 | class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { 60 | val itemMyScore: TextView = itemView.itemMyScore 61 | val itemGuessScore: TextView = itemView.itemGuessScore 62 | val itemSubject: TextView = itemView.itemSubject 63 | } 64 | } -------------------------------------------------------------------------------- /app/src/main/java/we/zxlite/adapter/ReportItemAdapter.kt: -------------------------------------------------------------------------------- 1 | package we.zxlite.adapter 2 | 3 | import android.view.LayoutInflater.from 4 | import android.view.View 5 | import android.view.ViewGroup 6 | import android.widget.TextView 7 | import androidx.recyclerview.widget.RecyclerView 8 | import kotlinx.android.synthetic.main.item_general.view.* 9 | import we.zxlite.R 10 | import we.zxlite.adapter.ReportItemAdapter.ViewHolder 11 | 12 | class ReportItemAdapter(private var reportList: ArrayList) : 13 | RecyclerView.Adapter() { 14 | 15 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = 16 | ViewHolder(from(parent.context).inflate(R.layout.item_general, parent, false)) 17 | 18 | override fun onBindViewHolder(holder: ViewHolder, position: Int) { 19 | holder.itemTitle.text = reportList[position] 20 | } 21 | 22 | override fun getItemCount() = reportList.size 23 | 24 | class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { 25 | val itemTitle: TextView = itemView.itemTitle 26 | } 27 | } -------------------------------------------------------------------------------- /app/src/main/java/we/zxlite/adapter/ReportPageAdapter.kt: -------------------------------------------------------------------------------- 1 | package we.zxlite.adapter 2 | 3 | import android.view.LayoutInflater.from 4 | import android.view.View 5 | import android.view.ViewGroup 6 | import android.widget.TextView 7 | import androidx.recyclerview.widget.GridLayoutManager 8 | import androidx.recyclerview.widget.RecyclerView 9 | import kotlinx.android.synthetic.main.fragment_report.view.* 10 | import kotlinx.android.synthetic.main.fragment_report.view.reportAdvice 11 | import kotlinx.android.synthetic.main.fragment_report.view.reportDetail 12 | import kotlinx.android.synthetic.main.fragment_report.view.reportProgress 13 | import kotlinx.android.synthetic.main.fragment_report.view.reportTitle 14 | import kotlinx.android.synthetic.main.fragment_report_general.view.* 15 | import we.zxlite.R 16 | import we.zxlite.bean.ReportPageBean 17 | import we.zxlite.view.ProgressBar 18 | import we.zxlite.view.ScoreChart 19 | import java.math.BigDecimal.ROUND_DOWN 20 | 21 | class ReportPageAdapter( 22 | private val pageList: ArrayList, 23 | private val callback: (ScoreChart, String) -> Unit 24 | ) : RecyclerView.Adapter() { 25 | 26 | companion object { 27 | private const val SUBJECT = 0 //学科 28 | private const val GENERAL = 1 //全科 29 | } 30 | 31 | //等级评估 32 | private val Int.examLevel 33 | get() = when { 34 | this < 60 -> "待及格" 35 | this < 70 -> "及格" 36 | this < 85 -> "良好" 37 | this != 100 -> "优秀" 38 | else -> "满分!继续努力" 39 | } 40 | //学科建议 41 | private val Int.examAdvice 42 | get() = when { 43 | this < 60 -> "务实基础,再接再厉" 44 | this < 70 -> "保持心态,查漏补缺" 45 | this < 85 -> "进行针对性巩固练习" 46 | else -> "按时复习,稳住优势" 47 | } 48 | //学科诊断 49 | private val Int.examDiagnosis 50 | get() = when { 51 | this < 60 -> "该科成绩较差" 52 | this < 70 -> "该科成绩一般" 53 | this < 85 -> "该科成绩良好" 54 | this != 100 -> "该科成绩优秀" 55 | else -> "该科成绩优异" 56 | } 57 | 58 | override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = 59 | if (viewType == SUBJECT) 60 | ViewHolder( 61 | from(parent.context).inflate(R.layout.fragment_report, parent, false) 62 | ) 63 | else 64 | ViewHolder( 65 | from(parent.context).inflate(R.layout.fragment_report_general, parent, false) 66 | ) 67 | 68 | override fun getItemCount() = pageList.size 69 | 70 | override fun onBindViewHolder(holder: ViewHolder, i: Int) { 71 | val standardScore = //标准得分 72 | pageList[i].standardScore.toBigDecimal() 73 | val userScore = //得分 74 | pageList[i].userScore.toBigDecimal() 75 | val examScale = //占比 76 | userScore.multiply(100.toBigDecimal()).divide(standardScore, 0, ROUND_DOWN).toInt() 77 | val examDeduct = //扣分 78 | standardScore.subtract(userScore).stripTrailingZeros().toPlainString() 79 | 80 | val showScore = 81 | "${userScore.stripTrailingZeros().toPlainString()} / ${standardScore.stripTrailingZeros().toPlainString()}" 82 | val showDetail = 83 | "• 我的分数: $showScore\n\n• 等级评估: ${examScale.examLevel}\n\n• 分数总扣: $examDeduct 分\n\n• 分数占比: $examScale %" 84 | val showAdvice = 85 | "• 学科诊断: ${examScale.examDiagnosis}\n\n• 学科建议: ${examScale.examAdvice}" 86 | val showChartTitle = 87 | "• 成绩变化曲线: " 88 | 89 | if (getItemViewType(i) == SUBJECT) { 90 | holder.itemView.reportChartTitle.text = showChartTitle 91 | holder.reportTitle.text = pageList[i].paperName 92 | holder.reportDetail.text = showDetail 93 | holder.reportAdvice.text = showAdvice 94 | holder.reportProgress.value = examScale 95 | 96 | if (holder.itemView.reportChart.tag != true) { 97 | callback(holder.itemView.reportChart, pageList[i].paperId) 98 | } 99 | } else { 100 | holder.reportTitle.text = pageList[i].paperName 101 | holder.reportDetail.text = showDetail 102 | holder.reportAdvice.text = showAdvice 103 | holder.reportProgress.value = examScale 104 | val subjectList = ArrayList() 105 | for (item in pageList) { 106 | subjectList.add("• ${item.title} : ${item.userScore.toBigDecimal().stripTrailingZeros().toPlainString()} / ${item.standardScore.toBigDecimal().stripTrailingZeros().toPlainString()}") 107 | } 108 | 109 | holder.itemView.reportGeneral.layoutManager = 110 | GridLayoutManager(holder.itemView.context, 2) 111 | holder.itemView.reportGeneral.adapter = 112 | ReportItemAdapter(subjectList) 113 | } 114 | } 115 | 116 | override fun getItemViewType(i: Int) = if (pageList.size > 1 && i == 0) GENERAL else SUBJECT 117 | 118 | class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { 119 | val reportTitle: TextView = itemView.reportTitle 120 | val reportDetail: TextView = itemView.reportDetail 121 | val reportAdvice: TextView = itemView.reportAdvice 122 | val reportProgress: ProgressBar = itemView.reportProgress 123 | } 124 | } -------------------------------------------------------------------------------- /app/src/main/java/we/zxlite/bean/AnalyzeListBean.kt: -------------------------------------------------------------------------------- 1 | package we.zxlite.bean 2 | 3 | data class AnalyzeListBean( 4 | var title: String, //标题 5 | var content: String //内容 6 | ) -------------------------------------------------------------------------------- /app/src/main/java/we/zxlite/bean/AnalyzePageBean.kt: -------------------------------------------------------------------------------- 1 | package we.zxlite.bean 2 | 3 | data class AnalyzePageBean( 4 | var disTitleNumber: String, //标题编号 5 | var topicNumber: Int, //主题编号 6 | var topicScoreDTOs: String, //主题分数集合 7 | var topicId: String, //主题id 8 | var topicSetId: String, //主题集id 9 | var analysisHtml: String, //解析Html 10 | var contentHtml: String, //题目Html 11 | var answerType: String, //答案类型 12 | var answerHtml: String, //答案Html 13 | var standardAnswer: String, //标准答案 14 | var standardScore: Double, //标准分数 15 | var score: Double, //得分 16 | var userAnswer: String, //用户答案 17 | var userAnswers: String, //用户答案集 18 | var imageAnswers: String, //图像答案 19 | var relatedKnowledgeGroups: String //知识点 20 | ) -------------------------------------------------------------------------------- /app/src/main/java/we/zxlite/bean/ReportListBean.kt: -------------------------------------------------------------------------------- 1 | package we.zxlite.bean 2 | 3 | data class ReportListBean( 4 | var examId: String, //报告id 5 | var examName: String, //报告名称 6 | var examCreateTime: Long //报告时间 7 | ) -------------------------------------------------------------------------------- /app/src/main/java/we/zxlite/bean/ReportPageBean.kt: -------------------------------------------------------------------------------- 1 | package we.zxlite.bean 2 | 3 | data class ReportPageBean( 4 | var title: String, //标题 5 | var paperId: String, //考卷id 6 | var paperName: String, //考卷名 7 | var standardScore: Double, //总分 8 | var userScore: Double, //用户得分 9 | var subjectCode: Int, //学科码 10 | var subjectName: String //学科名 11 | ) -------------------------------------------------------------------------------- /app/src/main/java/we/zxlite/bean/UserConfigBean.kt: -------------------------------------------------------------------------------- 1 | package we.zxlite.bean 2 | 3 | data class UserConfigBean( 4 | var logName: String? = null, //保存的用户名 5 | var logPwd: String? = null, //保存的密码 6 | var curId: String? = null, //选中id 7 | var curName: String? = null, //选中用户名 8 | var loginName: String? = null, //登录名 9 | var serviceTime: Long? = null, //服务时间 10 | var serviceToken: String? = null //验证码 11 | ) { 12 | 13 | /** 清空配置 */ 14 | fun clean() { 15 | logName = null 16 | logPwd = null 17 | curId = null 18 | curName = null 19 | loginName = null 20 | serviceTime = null 21 | serviceToken = null 22 | } 23 | } -------------------------------------------------------------------------------- /app/src/main/java/we/zxlite/dialog/AboutDialog.kt: -------------------------------------------------------------------------------- 1 | package we.zxlite.dialog 2 | 3 | import android.os.Bundle 4 | import android.view.LayoutInflater 5 | import android.view.View 6 | import android.view.ViewGroup 7 | import we.zxlite.R 8 | 9 | class AboutDialog : BaseSheetDialog() { 10 | 11 | override fun onCreateView( 12 | inflater: LayoutInflater, 13 | container: ViewGroup?, 14 | savedInstanceState: Bundle? 15 | ): View = inflater.inflate(R.layout.dialog_about, container) 16 | } -------------------------------------------------------------------------------- /app/src/main/java/we/zxlite/dialog/AccountDialog.kt: -------------------------------------------------------------------------------- 1 | package we.zxlite.dialog 2 | 3 | import android.app.Dialog 4 | import android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK 5 | import android.content.Intent.FLAG_ACTIVITY_NEW_TASK 6 | import android.os.Bundle 7 | import androidx.appcompat.app.AlertDialog 8 | import org.jetbrains.anko.db.replace 9 | import org.jetbrains.anko.db.select 10 | import org.jetbrains.anko.intentFor 11 | import we.zxlite.R 12 | import we.zxlite.activity.InitActivity 13 | import we.zxlite.utils.BaseUtils.db 14 | import we.zxlite.utils.SqlUtils.Helper.Companion.ITEM_NAME 15 | import we.zxlite.utils.SqlUtils.Helper.Companion.ITEM_VALUE 16 | import we.zxlite.utils.SqlUtils.Helper.Companion.SELECT_USER 17 | import we.zxlite.utils.SqlUtils.Helper.Companion.TABLE_CFG 18 | import we.zxlite.utils.SqlUtils.Helper.Companion.TABLE_RMB 19 | 20 | class AccountDialog : BaseAlertDialog() { 21 | 22 | override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { 23 | val users = ArrayList() 24 | context!!.db.use { 25 | select(TABLE_RMB, ITEM_NAME).exec { 26 | if (moveToFirst()) while (true) { 27 | users.add(getString(0)) 28 | if (isLast) break 29 | moveToNext() 30 | } 31 | } 32 | } 33 | return AlertDialog.Builder(context!!) 34 | .setTitle(R.string.menuSwitchAccount) 35 | .setItems(users.toTypedArray()) { _, i -> 36 | context!!.db.use { 37 | replace(TABLE_CFG, ITEM_NAME to SELECT_USER, ITEM_VALUE to users[i]) 38 | } 39 | activity!!.startActivity( 40 | activity!!.intentFor() 41 | .addFlags(FLAG_ACTIVITY_CLEAR_TASK) 42 | .addFlags(FLAG_ACTIVITY_NEW_TASK) 43 | ) 44 | }.create() 45 | } 46 | 47 | } -------------------------------------------------------------------------------- /app/src/main/java/we/zxlite/dialog/BaseAlertDialog.kt: -------------------------------------------------------------------------------- 1 | package we.zxlite.dialog 2 | 3 | import androidx.fragment.app.DialogFragment 4 | import kotlinx.coroutines.CoroutineScope 5 | import kotlinx.coroutines.MainScope 6 | import kotlinx.coroutines.cancel 7 | 8 | abstract class BaseAlertDialog :DialogFragment(), CoroutineScope by MainScope(){ 9 | 10 | override fun onDestroy() { 11 | super.onDestroy() 12 | cancel() 13 | } 14 | } -------------------------------------------------------------------------------- /app/src/main/java/we/zxlite/dialog/BaseSheetDialog.kt: -------------------------------------------------------------------------------- 1 | package we.zxlite.dialog 2 | 3 | import com.google.android.material.bottomsheet.BottomSheetDialogFragment 4 | import kotlinx.coroutines.CoroutineScope 5 | import kotlinx.coroutines.MainScope 6 | import kotlinx.coroutines.cancel 7 | 8 | abstract class BaseSheetDialog : BottomSheetDialogFragment() , CoroutineScope by MainScope() { 9 | 10 | override fun onDestroy() { 11 | super.onDestroy() 12 | cancel() 13 | } 14 | } -------------------------------------------------------------------------------- /app/src/main/java/we/zxlite/dialog/BindDialog.kt: -------------------------------------------------------------------------------- 1 | package we.zxlite.dialog 2 | 3 | import android.os.Bundle 4 | import android.view.LayoutInflater 5 | import android.view.View 6 | import android.view.ViewGroup 7 | import kotlinx.android.synthetic.main.dialog_bind.* 8 | import kotlinx.coroutines.Dispatchers.Main 9 | import kotlinx.coroutines.launch 10 | import kotlinx.coroutines.withContext 11 | import org.jetbrains.anko.toast 12 | import org.json.JSONObject 13 | import we.zxlite.R 14 | import we.zxlite.utils.HttpUtils.Type.JsonObject 15 | import we.zxlite.utils.HttpUtils.api 16 | import we.zxlite.utils.HttpUtils.Error 17 | 18 | class BindDialog : BaseSheetDialog() { 19 | 20 | companion object { 21 | private const val SMS_URL = 22 | "https://www.zhixue.com/container/app/common/user/sendSMS4Mobile" //验证码URL 23 | 24 | private const val BIND_URL = 25 | "https://www.zhixue.com/container/app/common/user/modifyMobile" //绑定手机URL 26 | } 27 | 28 | //手机号码 29 | private val bindMobileNumber get() = bindMobile.text.toString() 30 | //手机验证码 31 | private val bindMobileCode get() = bindCode.text.toString() 32 | //短信验证参数 33 | private val smsParams get() = "?mobile=$bindMobileNumber" 34 | //绑定验证参数 35 | private val bindParams get() = "?mobile=$bindMobileNumber&code=$bindMobileCode" 36 | 37 | override fun onCreateView( 38 | inflater: LayoutInflater, 39 | container: ViewGroup?, 40 | savedInstanceState: Bundle? 41 | ): View = inflater.inflate(R.layout.dialog_bind, container) 42 | 43 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 44 | super.onViewCreated(view, savedInstanceState) 45 | bindCodeBtn.setOnClickListener { 46 | if (bindMobileNumber.isNotEmpty()) launch { 47 | activity!!.api(SMS_URL + smsParams, null, true, JsonObject).let { 48 | withContext(Main) { 49 | if (it is JSONObject) context!!.toast(R.string.smsSuccess) 50 | else context!!.toast((it as Error).message) 51 | } 52 | } 53 | } else context!!.toast(R.string.valueIncorrect) 54 | } 55 | bindBtn.setOnClickListener { 56 | val mobileNumber = bindMobileNumber 57 | val mobileCode = bindMobileCode 58 | if (mobileNumber.isNotEmpty() && mobileCode.isNotEmpty()) launch { 59 | activity!!.api(BIND_URL + bindParams, null, true, JsonObject).let { 60 | withContext(Main) { 61 | if (it is JSONObject) { 62 | context!!.toast(R.string.bindSuccess) 63 | dismiss() 64 | } else context!!.toast((it as Error).message) 65 | } 66 | } 67 | } else context!!.toast(R.string.valueIncorrect) 68 | } 69 | } 70 | } -------------------------------------------------------------------------------- /app/src/main/java/we/zxlite/dialog/ModifyDialog.kt: -------------------------------------------------------------------------------- 1 | package we.zxlite.dialog 2 | 3 | import android.os.Bundle 4 | import android.view.LayoutInflater 5 | import android.view.View 6 | import android.view.ViewGroup 7 | import kotlinx.android.synthetic.main.dialog_modify.* 8 | import kotlinx.coroutines.Dispatchers.Main 9 | import kotlinx.coroutines.launch 10 | import kotlinx.coroutines.withContext 11 | import org.jetbrains.anko.db.replace 12 | import org.jetbrains.anko.toast 13 | import org.json.JSONObject 14 | import we.zxlite.R 15 | import we.zxlite.utils.HttpUtils.Type.JsonObject 16 | import we.zxlite.utils.HttpUtils.api 17 | import we.zxlite.utils.HttpUtils.Error 18 | import we.zxlite.utils.UserUtils.cfg 19 | import we.zxlite.utils.BaseUtils.db 20 | import we.zxlite.utils.BaseUtils.rc4 21 | import we.zxlite.utils.SqlUtils.Helper.Companion.ITEM_NAME 22 | import we.zxlite.utils.SqlUtils.Helper.Companion.ITEM_VALUE 23 | import we.zxlite.utils.SqlUtils.Helper.Companion.TABLE_RMB 24 | 25 | class ModifyDialog : BaseSheetDialog() { 26 | 27 | companion object { 28 | private const val MODIFY_URL = 29 | "https://www.zhixue.com/container/app/modifyOriginPWD" //修改密码URL 30 | } 31 | 32 | override fun onCreateView( 33 | inflater: LayoutInflater, 34 | container: ViewGroup?, 35 | savedInstanceState: Bundle? 36 | ): View = inflater.inflate(R.layout.dialog_modify, container) 37 | 38 | override fun onViewCreated(view: View, savedInstanceState: Bundle?) { 39 | super.onViewCreated(view, savedInstanceState) 40 | modifyBtn.setOnClickListener { 41 | val newPwd = modifyNew.text.toString() 42 | val originPwd = modifyOrigin.text.toString() 43 | if (newPwd.isNotEmpty() && originPwd.isNotEmpty()) launch { 44 | val modifyParams = 45 | "loginName=${cfg.loginName?.rc4}&newPWD=${newPwd.rc4}&originPWD=${originPwd.rc4}&description=encrypt" 46 | activity!!.api(MODIFY_URL, modifyParams, true, JsonObject).let { 47 | withContext(Main) { 48 | if (it is JSONObject) { 49 | context!!.toast(R.string.modifySuccess) 50 | cfg.logPwd = newPwd 51 | context!!.db.use { 52 | replace(TABLE_RMB, ITEM_NAME to cfg.logName, ITEM_VALUE to newPwd) 53 | } 54 | dismiss() 55 | } else context!!.toast((it as Error).message) 56 | } 57 | } 58 | } else context!!.toast(R.string.valueIncorrect) 59 | } 60 | } 61 | } -------------------------------------------------------------------------------- /app/src/main/java/we/zxlite/dialog/SelectFriendsDialog.kt: -------------------------------------------------------------------------------- 1 | package we.zxlite.dialog 2 | 3 | import android.os.Bundle 4 | import androidx.appcompat.app.AlertDialog 5 | 6 | class SelectFriendsDialog(private val callback: (Int) -> Unit) : BaseAlertDialog() { 7 | 8 | companion object { 9 | private const val NAME_LIST = "nameList" 10 | } 11 | 12 | override fun onCreateDialog(savedInstanceState: Bundle?) = 13 | AlertDialog.Builder(context!!) 14 | .setItems(arguments!!.getStringArray(NAME_LIST)) { _, which -> callback(which) } 15 | .create() 16 | } -------------------------------------------------------------------------------- /app/src/main/java/we/zxlite/utils/BaseUtils.kt: -------------------------------------------------------------------------------- 1 | package we.zxlite.utils 2 | 3 | import android.content.Context 4 | import android.graphics.Bitmap 5 | import android.graphics.BitmapFactory 6 | import android.util.Base64 7 | import androidx.core.content.ContextCompat 8 | import java.net.HttpURLConnection 9 | import java.net.URL 10 | import java.security.MessageDigest 11 | import we.zxlite.utils.SqlUtils.Helper 12 | import java.lang.Integer.toHexString 13 | import kotlin.experimental.xor 14 | 15 | object BaseUtils { 16 | /** 空字符串 */ 17 | const val EMPTY_STR = "" 18 | /** 获取数据库资源 */ 19 | val Context.db: Helper get() = Helper.getInstance(this) 20 | /** 转为RC4 */ 21 | val String.rc4: String 22 | get() { 23 | val data = this.toByteArray() //需要转换的字节 24 | val key = "iflytek_pass_edp".toByteArray() //密钥的字节 25 | 26 | val b = ByteArray(data.size) 27 | val s = ByteArray(256) 28 | var x = 0 29 | var y = 0 30 | 31 | for (i in s.indices) { 32 | s[i] = i.toByte() 33 | } 34 | 35 | for (i in s.indices) { 36 | y = y + s[i] + key[i % key.size] and 0xFF 37 | s[i] = s[i] xor s[y] 38 | s[y] = s[y] xor s[i] 39 | s[i] = s[i] xor s[y] 40 | } 41 | y = 0 42 | for (counter in data.indices) { 43 | x = x + 1 and 0xFF 44 | y = y + s[x] and 0xFF 45 | s[x] = s[x] xor s[y] 46 | s[y] = s[y] xor s[x] 47 | s[x] = s[x] xor s[y] 48 | val k = s[s[x] + s[y] and 0xFF] 49 | b[counter] = data[counter] xor k 50 | } 51 | return b.hexString 52 | } 53 | /** 转为MD5 */ 54 | val String.md5: String 55 | get() { 56 | val digest = MessageDigest.getInstance("MD5") 57 | digest.update(toByteArray()) 58 | return digest.digest().hexString 59 | } 60 | /** 转为位图 */ 61 | val String.bitmap: Bitmap 62 | get() { 63 | val decode = Base64.decode(this, Base64.DEFAULT) 64 | return BitmapFactory.decodeByteArray(decode, 0, decode.size) 65 | } 66 | /** 转为十六进制字符串 */ 67 | private val ByteArray.hexString: String 68 | get() { 69 | val builder = StringBuilder() 70 | for (byte in this) { 71 | val i: Int = byte.toInt() and 255 72 | builder.append("${if (i < 16) "0" else EMPTY_STR}${toHexString(i)}") 73 | } 74 | return builder.toString() 75 | } 76 | 77 | /** 获取颜色值 */ 78 | fun Context.color(resId: Int) = ContextCompat.getColor(this, resId) 79 | 80 | /** 转为HttpURLConnection */ 81 | fun String.conn() = URL(this).openConnection() as HttpURLConnection 82 | } -------------------------------------------------------------------------------- /app/src/main/java/we/zxlite/utils/GetterUtils.kt: -------------------------------------------------------------------------------- 1 | package we.zxlite.utils 2 | 3 | import android.content.res.Resources 4 | import android.graphics.Bitmap 5 | import android.graphics.Canvas 6 | import android.graphics.Rect 7 | import android.graphics.drawable.BitmapDrawable 8 | import android.graphics.drawable.Drawable 9 | import android.text.Html 10 | import android.widget.TextView 11 | import com.bumptech.glide.request.target.CustomTarget 12 | import com.bumptech.glide.request.transition.Transition 13 | import we.zxlite.GlideApp 14 | 15 | object GetterUtils { 16 | 17 | class ImageGetter(val htmlView: TextView) : 18 | Html.ImageGetter { 19 | override fun getDrawable(source: String): Drawable { 20 | val urlDrawable = UrlDrawable() 21 | GlideApp.with(htmlView.context).asBitmap().load(source).into(BitmapTarget(urlDrawable)) 22 | return urlDrawable 23 | } 24 | 25 | private inner class BitmapTarget(private val urlDrawable: UrlDrawable) : 26 | CustomTarget() { 27 | override fun onResourceReady(resource: Bitmap, transition: Transition?) { 28 | val drawable = BitmapDrawable(htmlView.context.resources, resource) 29 | htmlView.post { 30 | val right: Int 31 | val bottom: Int 32 | 33 | if (drawable.intrinsicWidth * 2 > htmlView.width) { //图片宽大于htmlView宽 34 | right = htmlView.width 35 | bottom = drawable.intrinsicHeight * htmlView.width / drawable.intrinsicWidth 36 | } else { 37 | right = drawable.intrinsicWidth * 2 38 | bottom = drawable.intrinsicHeight * 2 39 | } 40 | 41 | val rect = Rect(0, 0, right, bottom) 42 | drawable.bounds = rect 43 | urlDrawable.bounds = rect 44 | urlDrawable.drawable = drawable 45 | 46 | htmlView.text = htmlView.text 47 | htmlView.invalidate() 48 | } 49 | } 50 | 51 | override fun onLoadCleared(placeholder: Drawable?) {} 52 | } 53 | 54 | class UrlDrawable(resources: Resources? = null, bitmap: Bitmap? = null) : 55 | BitmapDrawable(resources, bitmap) { 56 | var drawable: Drawable? = null 57 | 58 | override fun draw(canvas: Canvas) { 59 | drawable?.draw(canvas) 60 | } 61 | } 62 | } 63 | } -------------------------------------------------------------------------------- /app/src/main/java/we/zxlite/utils/HttpUtils.kt: -------------------------------------------------------------------------------- 1 | package we.zxlite.utils 2 | 3 | import android.app.Activity 4 | import android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK 5 | import android.content.Intent.FLAG_ACTIVITY_NEW_TASK 6 | import kotlinx.coroutines.Dispatchers.Main 7 | import kotlinx.coroutines.GlobalScope 8 | import kotlinx.coroutines.async 9 | import kotlinx.coroutines.withContext 10 | import org.jetbrains.anko.intentFor 11 | import org.json.JSONArray 12 | import org.json.JSONObject 13 | import we.zxlite.R 14 | import we.zxlite.activity.LoginActivity 15 | import we.zxlite.utils.BaseUtils.EMPTY_STR 16 | import we.zxlite.utils.BaseUtils.conn 17 | import we.zxlite.utils.BaseUtils.md5 18 | import we.zxlite.utils.HttpUtils.Type.JsonArray 19 | import we.zxlite.utils.HttpUtils.Type.JsonObject 20 | import we.zxlite.utils.UserUtils.cfg 21 | import we.zxlite.utils.UserUtils.isExpired 22 | import we.zxlite.utils.UserUtils.login 23 | import we.zxlite.utils.UserUtils.updateConfig 24 | import java.io.DataOutputStream 25 | import java.lang.System.currentTimeMillis 26 | import java.net.SocketTimeoutException 27 | import java.net.UnknownHostException 28 | import java.util.UUID.randomUUID 29 | 30 | object HttpUtils { 31 | private const val AUTH_KEY = "iflytek!@#123student" //验证密钥 32 | private const val AUTH_CODE = "authbizcode" 33 | private const val AUTH_GUID = "authguid" 34 | private const val AUTH_TIME = "authtimestamp" 35 | private const val AUTH_TOKEN = "authtoken" 36 | private const val ERROR_CODE = "errorCode" 37 | private const val ERROR_INFO = "errorInfo" 38 | private const val ERROR_RESULT = "result" 39 | //验证参数 40 | private val tokenParams get() = "?token=${cfg.serviceToken}&childrenId=${cfg.curId}" 41 | 42 | /** 回调数据类型 */ 43 | enum class Type { JsonObject, JsonArray } 44 | 45 | /** 验证接口访问 46 | * @param url 接口地址 47 | * @param params 提交数据 48 | * @param add 增加验证 49 | * @param type 返回数据类型 50 | */ 51 | suspend fun Activity.api(url: String, params: String?, add: Boolean, type: Type?): Any { 52 | if (isExpired) { 53 | cfg.clean() 54 | updateConfig() 55 | if (!login()) { 56 | withContext(Main) { 57 | startActivity( 58 | intentFor() 59 | .addFlags(FLAG_ACTIVITY_CLEAR_TASK) 60 | .addFlags(FLAG_ACTIVITY_NEW_TASK) 61 | ) 62 | } 63 | return Error(Exception(getString(R.string.loginFailed))) 64 | } 65 | } 66 | return connApi(url, params, add, type) 67 | } 68 | 69 | /** 接口访问 70 | * @param url 接口地址 71 | * @param params 提交数据 72 | * @param add 增加验证 73 | * @param type 返回数据类型 74 | */ 75 | suspend fun connApi(url: String, params: String?, add: Boolean, type: Type?) = 76 | GlobalScope.async { 77 | val checkParams = if (params == null) tokenParams.replace("?", "&") else tokenParams 78 | val urlConn = ("$url${if (add) checkParams else EMPTY_STR}").conn() 79 | try { 80 | val authCode = "0001" 81 | val authGuid = randomUUID().toString() 82 | val authTime = currentTimeMillis().toString() 83 | val authToken = (authGuid + authTime + AUTH_KEY).md5 84 | val conn = urlConn.apply { 85 | if (params != null) { //如果不等于null 将设置为post提交 86 | requestMethod = "POST" 87 | doOutput = true 88 | } 89 | readTimeout = 10 * 1000 //读取超时10s 90 | connectTimeout = 10 * 1000 //连接超时10s 91 | setRequestProperty(AUTH_CODE, authCode) 92 | setRequestProperty(AUTH_GUID, authGuid) 93 | setRequestProperty(AUTH_TIME, authTime) 94 | setRequestProperty(AUTH_TOKEN, authToken) 95 | } 96 | if (params != null) { 97 | val stream = DataOutputStream(conn.outputStream) 98 | stream.writeBytes(params) 99 | stream.flush() 100 | stream.close() 101 | } 102 | val resultData = conn.inputStream.reader().readText() 103 | return@async when (type) { 104 | JsonObject -> resultData.jsonObject 105 | JsonArray -> resultData.jsonArray 106 | else -> resultData 107 | } 108 | } catch (e: Exception) { 109 | return@async Error(e) 110 | } finally { 111 | urlConn.disconnect() 112 | } 113 | }.await() 114 | 115 | /** 转为JSON */ 116 | private fun String.json(): String = JSONObject(this).run { 117 | if (optInt(ERROR_CODE) == 0) optString(ERROR_RESULT) 118 | else throw Exception(optString(ERROR_INFO)) 119 | } 120 | 121 | /** 转为JSONObject */ 122 | private val String.jsonObject: Any 123 | get() { 124 | val json = json() 125 | return if (json.isNotEmpty()) JSONObject(json) else JSONObject() 126 | } 127 | 128 | /** 转为JSONArray */ 129 | private val String.jsonArray: Any 130 | get() { 131 | val json = json() 132 | return if (json.isNotEmpty()) JSONArray(json) else JSONArray() 133 | } 134 | 135 | /** 返回错误信息 */ 136 | class Error(private val error: Exception) { 137 | val message: String 138 | get() = when (error) { 139 | is UnknownHostException -> "网络连接错误" 140 | is SocketTimeoutException -> "网络连接超时" 141 | else -> error.message.toString() 142 | } 143 | } 144 | } -------------------------------------------------------------------------------- /app/src/main/java/we/zxlite/utils/SqlUtils.kt: -------------------------------------------------------------------------------- 1 | package we.zxlite.utils 2 | 3 | import android.content.Context 4 | import android.database.sqlite.SQLiteDatabase 5 | import org.jetbrains.anko.db.* 6 | 7 | object SqlUtils { 8 | 9 | private const val DB_NAME = "Zxlite" //数据库名 10 | 11 | class Helper private constructor(ctx: Context) : 12 | ManagedSQLiteOpenHelper(ctx, DB_NAME, null, 1) { 13 | init { 14 | instance = this 15 | } 16 | 17 | companion object { 18 | const val TABLE_RMB = "TABLE_RMB" //记住密码 19 | const val TABLE_CFG = "TABLE_CFG" //用户配置 20 | const val ITEM_NAME = "ITEM_NAME" //项名 21 | const val ITEM_VALUE = "ITEM_VALUE" //项值 22 | const val SELECT_USER = "SELECT_USER" //选中用户 23 | const val REPORT_TYPE = "REPORT_TYPE" //报告类型 24 | 25 | private var instance: Helper? = null 26 | 27 | @Synchronized 28 | fun getInstance(ctx: Context) = instance ?: Helper(ctx.applicationContext) 29 | } 30 | 31 | override fun onCreate(db: SQLiteDatabase) { 32 | db.createTable(TABLE_RMB, true, ITEM_NAME to TEXT + UNIQUE, ITEM_VALUE to TEXT) //创建记住密码表 33 | db.createTable(TABLE_CFG, true, ITEM_NAME to TEXT + UNIQUE, ITEM_VALUE to TEXT) //创建用户配置表 34 | } 35 | 36 | override fun onUpgrade(db: SQLiteDatabase, oldVersion: Int, newVersion: Int) { 37 | db.dropTable(TABLE_RMB) 38 | db.dropTable(TABLE_CFG) 39 | } 40 | } 41 | 42 | } -------------------------------------------------------------------------------- /app/src/main/java/we/zxlite/utils/UserUtils.kt: -------------------------------------------------------------------------------- 1 | package we.zxlite.utils 2 | 3 | import android.content.Context 4 | import kotlinx.coroutines.GlobalScope 5 | import kotlinx.coroutines.async 6 | import org.jetbrains.anko.db.select 7 | import org.json.JSONObject 8 | import we.zxlite.bean.UserConfigBean 9 | import we.zxlite.utils.BaseUtils.EMPTY_STR 10 | import we.zxlite.utils.BaseUtils.db 11 | import we.zxlite.utils.BaseUtils.rc4 12 | import we.zxlite.utils.HttpUtils.connApi 13 | import we.zxlite.utils.HttpUtils.Type.JsonObject 14 | import we.zxlite.utils.SqlUtils.Helper.Companion.ITEM_NAME 15 | import we.zxlite.utils.SqlUtils.Helper.Companion.ITEM_VALUE 16 | import we.zxlite.utils.SqlUtils.Helper.Companion.SELECT_USER 17 | import we.zxlite.utils.SqlUtils.Helper.Companion.TABLE_CFG 18 | import we.zxlite.utils.SqlUtils.Helper.Companion.TABLE_RMB 19 | import java.lang.System.currentTimeMillis 20 | 21 | object UserUtils { 22 | 23 | //用户配置 24 | val cfg = UserConfigBean() 25 | 26 | //检测登录是否过期 27 | val isExpired get() = (cfg.serviceTime ?: 0) < currentTimeMillis() - 1800000L 28 | 29 | private const val LOG_URL = "https://www.zhixue.com/container/app/login" //登录账号URL 30 | private const val INFO_URL = 31 | "https://www.zhixue.com/zhixuebao/base/common/getUserInfo" //用户信息URL 32 | 33 | private const val USER_INFO = "userInfo" //用户信息 34 | private const val SERVER_INFO = "serverInfo" //服务信息 35 | private const val CUR_SERVER_TIME = "curServerTime" //服务时间 36 | private const val CUR_CHILD_ID = "curChildId" //选定Id 37 | private const val LOGIN_NAME = "loginName" //登录名 38 | private const val TOKEN = "token" //验证码 39 | private const val NAME = "name" //名字 40 | //登录参数 41 | private val logParams get() = "loginName=${cfg.logName}&password=${cfg.logPwd?.rc4}&description={'encrypt':['password']}" 42 | 43 | /** 登录 44 | * @param userName 用户名 45 | * @param userPwd 用户密码 46 | */ 47 | suspend fun login( 48 | userName: String? = cfg.logName, 49 | userPwd: String? = cfg.logPwd 50 | ) = GlobalScope.async { 51 | cfg.logName = userName 52 | cfg.logPwd = userPwd 53 | connApi(LOG_URL, logParams, false, JsonObject).run { 54 | if (this is JSONObject) { 55 | cfg.loginName = optJSONObject(USER_INFO)!!.optString(LOGIN_NAME) 56 | cfg.curName = optJSONObject(USER_INFO)!!.optString(NAME) 57 | cfg.serviceTime = optJSONObject(SERVER_INFO)!!.optLong(CUR_SERVER_TIME) 58 | cfg.serviceToken = optString(TOKEN) 59 | 60 | connApi(INFO_URL, EMPTY_STR, true, JsonObject).run { 61 | if (this is JSONObject) cfg.curId = optString(CUR_CHILD_ID) 62 | } 63 | } 64 | } 65 | return@async cfg.curId != null 66 | }.await() 67 | 68 | /** 更新信息 */ 69 | fun Context.updateConfig() = db.use { 70 | select(TABLE_CFG, ITEM_VALUE) 71 | .whereSimple("$ITEM_NAME = '$SELECT_USER'") 72 | .exec { if (moveToFirst()) getString(0) else null } 73 | ?.let { userName -> 74 | select(TABLE_RMB, ITEM_VALUE) 75 | .whereSimple("$ITEM_NAME = '$userName'") 76 | .exec { if (moveToFirst()) getString(0) else null } 77 | ?.let { userPwd -> 78 | cfg.logName = userName 79 | cfg.logPwd = userPwd 80 | } 81 | } 82 | } 83 | } -------------------------------------------------------------------------------- /app/src/main/java/we/zxlite/view/ProgressBar.kt: -------------------------------------------------------------------------------- 1 | package we.zxlite.view 2 | 3 | import android.content.Context 4 | import android.graphics.Canvas 5 | import android.graphics.Paint 6 | import android.util.AttributeSet 7 | import android.view.View 8 | import we.zxlite.R 9 | import we.zxlite.utils.BaseUtils.color 10 | 11 | class ProgressBar(ctx: Context, attrs: AttributeSet) : View(ctx, attrs) { 12 | 13 | /* 进度值 */ 14 | var value: Int = 0 15 | set(value) { 16 | field = value 17 | invalidate() //刷新 18 | } 19 | 20 | //画笔 21 | private val mPaint: Paint = Paint() 22 | 23 | override fun onDraw(canvas: Canvas) { 24 | super.onDraw(canvas) 25 | 26 | val progressWidth = value * measuredWidth / 100F //计算进度宽度 27 | 28 | mPaint.color = context!!.color(R.color.colorLine) 29 | canvas.drawRect(0f, 0f, measuredWidth.toFloat(), measuredHeight.toFloat(), mPaint) //画底层 30 | 31 | mPaint.color = context!!.color(R.color.colorAccent) 32 | canvas.drawRect(0f, 0f, progressWidth, measuredHeight.toFloat(), mPaint) //画进度 33 | } 34 | } -------------------------------------------------------------------------------- /app/src/main/java/we/zxlite/view/ScoreChart.kt: -------------------------------------------------------------------------------- 1 | package we.zxlite.view 2 | 3 | import android.content.Context 4 | import android.graphics.Color 5 | import android.graphics.Color.TRANSPARENT 6 | import android.graphics.DashPathEffect 7 | import android.graphics.Typeface.DEFAULT_BOLD 8 | import android.util.AttributeSet 9 | import android.view.MotionEvent 10 | import com.github.mikephil.charting.charts.LineChart 11 | import com.github.mikephil.charting.components.AxisBase 12 | import com.github.mikephil.charting.components.Legend.LegendVerticalAlignment.TOP 13 | import com.github.mikephil.charting.components.Legend.LegendHorizontalAlignment.RIGHT 14 | import com.github.mikephil.charting.components.Legend.LegendOrientation.HORIZONTAL 15 | import com.github.mikephil.charting.components.Legend.LegendForm.LINE 16 | import com.github.mikephil.charting.components.LegendEntry 17 | import com.github.mikephil.charting.data.Entry 18 | import com.github.mikephil.charting.data.LineData 19 | import com.github.mikephil.charting.data.LineDataSet 20 | import com.github.mikephil.charting.data.LineDataSet.Mode.CUBIC_BEZIER 21 | import com.github.mikephil.charting.formatter.ValueFormatter 22 | import com.github.mikephil.charting.interfaces.datasets.ILineDataSet 23 | import we.zxlite.R 24 | import we.zxlite.utils.BaseUtils.EMPTY_STR 25 | import we.zxlite.utils.BaseUtils.color 26 | 27 | class ScoreChart(ctx: Context, attr: AttributeSet) : LineChart(ctx, attr) { 28 | //图例条目 29 | var legendEntries = ArrayList() 30 | //数据集 31 | private var dataSets = ArrayList() 32 | //分割线颜色 33 | private val diverColor get() = context!!.color(R.color.colorChartDiver) 34 | //线的颜色 35 | private val lineColor get() = context!!.color(R.color.colorAccent) 36 | 37 | init { 38 | dataSets.add(initDefaultLine()) 39 | description.isEnabled = false 40 | isDoubleTapToZoomEnabled = false 41 | isDragEnabled = false 42 | legend.verticalAlignment = TOP 43 | legend.horizontalAlignment = RIGHT 44 | legend.orientation = HORIZONTAL 45 | data = LineData(dataSets) 46 | setTouchEnabled(false) 47 | setScaleEnabled(false) 48 | setAxis() 49 | } 50 | 51 | override fun dispatchTouchEvent(ev: MotionEvent): Boolean { 52 | parent.requestDisallowInterceptTouchEvent(false) 53 | return super.dispatchTouchEvent(ev) 54 | } 55 | 56 | fun addLine(name: String, entries: ArrayList, length: Float) { 57 | val effect = DashPathEffect(floatArrayOf(length, length), 0f) 58 | legendEntries.add(LegendEntry(name, LINE, 10f, 2f, effect, lineColor)) 59 | dataSets.add(LineDataSet(entries, null).apply { 60 | lineWidth = 2f 61 | circleRadius = 3f 62 | color = lineColor 63 | mode = CUBIC_BEZIER 64 | setDrawCircles(true) 65 | setDrawFilled(false) 66 | setDrawValues(false) 67 | setCircleColor(lineColor) 68 | enableDashedLine(length, length, 0f) 69 | }) 70 | } 71 | 72 | private fun initDefaultLine(): LineDataSet { 73 | val pointValues = ArrayList() 74 | for (i in 0..4) { 75 | pointValues.add(Entry((i * 2).toFloat(), (i * 2).toFloat())) 76 | } 77 | return LineDataSet(pointValues, null).apply { 78 | setDrawCircles(false) 79 | setDrawFilled(false) 80 | setDrawValues(false) 81 | color = TRANSPARENT 82 | } 83 | } 84 | 85 | private fun setAxis() { 86 | xAxis.isEnabled = false 87 | axisLeft.isEnabled = true 88 | axisRight.isEnabled = false 89 | axisLeft.axisMinimum = 0f 90 | axisLeft.axisMaximum = 9f 91 | axisLeft.xOffset = 10f 92 | axisLeft.yOffset = -8f 93 | axisLeft.typeface = DEFAULT_BOLD 94 | axisLeft.textColor = Color.GRAY 95 | axisLeft.gridColor = diverColor 96 | axisLeft.axisLineColor = diverColor 97 | axisLeft.axisLineWidth = 1.5f 98 | axisLeft.gridLineWidth = 1.5f 99 | axisLeft.setLabelCount(6, false) 100 | axisLeft.valueFormatter = LevelValueFormatter() 101 | } 102 | 103 | class LevelValueFormatter : ValueFormatter() { 104 | override fun getAxisLabel(value: Float, axis: AxisBase?): String { 105 | return when (value.toInt()) { 106 | 0 -> "E" 107 | 2 -> "D" 108 | 4 -> "C" 109 | 6 -> "B" 110 | 8 -> "A" 111 | else -> EMPTY_STR 112 | } 113 | } 114 | } 115 | 116 | } -------------------------------------------------------------------------------- /app/src/main/java/we/zxlite/view/ShadowView.kt: -------------------------------------------------------------------------------- 1 | package we.zxlite.view 2 | 3 | import android.content.Context 4 | import android.util.AttributeSet 5 | import android.view.View 6 | import we.zxlite.R 7 | 8 | /** 阴影控件 9 | * isTop 是否是顶部阴影 10 | */ 11 | class ShadowView(ctx: Context, attrs: AttributeSet) : View(ctx, attrs) { 12 | init { 13 | val styleAttrs = ctx.obtainStyledAttributes(attrs, R.styleable.ShadowView) 14 | 15 | if (styleAttrs.getBoolean(R.styleable.ShadowView_isTop, true)) { 16 | setBackgroundResource(R.drawable.shadow_top) //设置顶部阴影 17 | } else { 18 | setBackgroundResource(R.drawable.shadow_btm) //设置底部阴影 19 | } 20 | 21 | styleAttrs.recycle() 22 | } 23 | } -------------------------------------------------------------------------------- /app/src/main/res/drawable/edit_line.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_arrow.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_arrow_back.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 12 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/nav_text_color.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/shadow_btm.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/shadow_top.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_analyze.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 18 | 19 | 25 | 26 | 27 | 35 | 36 | 42 | 43 | 50 | 51 | 63 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_guess.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 18 | 19 | 25 | 26 | 27 | 41 | 42 | 57 | 58 | 72 | 73 | 85 | 86 | 92 | 93 | 100 | 101 | 114 | 115 | 124 | 125 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_init.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 26 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_login.xml: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | 21 | 22 | 35 | 36 | 46 | 47 | 67 | 68 | 87 | 88 | 99 | 100 | 112 | 113 | 126 | 127 | 139 | 140 | 141 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 14 | 15 | 23 | 24 | 28 | 29 | 30 | 36 | 37 | 45 | 46 | 53 | 54 | 55 | 56 | 69 | 70 | 71 | 80 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_paper.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 18 | 19 | 25 | 26 | 27 | 36 | 37 | 43 | 44 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_register.xml: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | 21 | 22 | 35 | 36 | 46 | 47 | 67 | 68 | 87 | 88 | 109 | 110 | 122 | 123 | 133 | 134 | 155 | 156 | 165 | 166 | 177 | 178 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_report.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 17 | 18 | 24 | 25 | 26 | 34 | 35 | 41 | 42 | 49 | 50 | 62 | -------------------------------------------------------------------------------- /app/src/main/res/layout/dialog_about.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 18 | 19 | 30 | -------------------------------------------------------------------------------- /app/src/main/res/layout/dialog_bind.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 19 | 20 | 31 | 32 | 49 | 50 | 61 | 62 | 81 | 82 | 91 | 92 | 103 | -------------------------------------------------------------------------------- /app/src/main/res/layout/dialog_modify.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 19 | 20 | 31 | 32 | 49 | 50 | 61 | 62 | 81 | 82 | 93 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_analyze.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_report.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 16 | 17 | 32 | 33 | 41 | 42 | 53 | 54 | 62 | 63 | 71 | 72 | 83 | 84 | 92 | 93 | 103 | 104 | 112 | 113 | 114 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_report_general.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | 16 | 17 | 32 | 33 | 41 | 42 | 53 | 54 | 62 | 63 | 71 | 72 | 83 | 84 | 92 | 93 | 102 | 103 | 104 | -------------------------------------------------------------------------------- /app/src/main/res/layout/header_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 22 | 23 | 30 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_analyze.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 14 | 15 | 22 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_general.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_guess.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 12 | 13 | 20 | 21 | 31 | 32 | 39 | 40 | 41 | 47 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_report.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 15 | 16 | 29 | 30 | 43 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_tab.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 9 | 12 | 13 | 14 | 15 | 16 | 17 | 20 | 23 | 24 | 25 | 26 | 29 | 32 | 33 | 34 | 35 | 38 | 41 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_report.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 9 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Git-WeStudio/Zxlite/a737f0bdac52346e754f208129e8f64988116b1d/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Git-WeStudio/Zxlite/a737f0bdac52346e754f208129e8f64988116b1d/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Git-WeStudio/Zxlite/a737f0bdac52346e754f208129e8f64988116b1d/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Git-WeStudio/Zxlite/a737f0bdac52346e754f208129e8f64988116b1d/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Git-WeStudio/Zxlite/a737f0bdac52346e754f208129e8f64988116b1d/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Git-WeStudio/Zxlite/a737f0bdac52346e754f208129e8f64988116b1d/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Git-WeStudio/Zxlite/a737f0bdac52346e754f208129e8f64988116b1d/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Git-WeStudio/Zxlite/a737f0bdac52346e754f208129e8f64988116b1d/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Git-WeStudio/Zxlite/a737f0bdac52346e754f208129e8f64988116b1d/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Git-WeStudio/Zxlite/a737f0bdac52346e754f208129e8f64988116b1d/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/values/attrs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #FFFFFF 4 | #FFFFFF 5 | #32C2B3 6 | #FFC107 7 | #80888888 8 | #3C4245 9 | #A5A9AF 10 | #ECEFF1 11 | #EEEEEE 12 | #262626 13 | #F5F5F5 14 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 智学网 3 |   报告类型 4 |   账号安全 5 |   其他相关 6 | 考试报告 7 | 作业报告 8 | 绑定手机 9 | 修改密码 10 | 检测更新 11 | 意见反馈 12 | 关于我们 13 | 注销登录 14 | 切换账号 15 | 原卷查看 16 | 题目解析 17 | 好友伴学 18 | 欢迎登录 19 | 智学,让学习更简单! 20 | 输入手机号或用户名 21 | 输入密码 22 | 登录 23 | 注册账号 24 | 忘记密码 25 | 登录失败 26 | 欢迎注册 27 | 智学,让学习更简单 28 | 输入手机号码 29 | 输入密码(不少于6位) 30 | 输入图像验证码 31 | 获取验证码 32 | 输入手机验证码 33 | 注册 34 | 注册成功 35 | 发送成功 36 | 参数填写不正确 37 | 确定 38 | 返回 39 | 加Q群获取最新版 40 | 注销登录? 41 | 通过邮箱反馈 42 | 请输入手机号码 43 | 请输入验证码 44 | 绑定 45 | 获取验证码 46 | 绑定成功 47 | 修改成功 48 | 请输入旧密码 49 | 请输入新密码 50 | 绑定 51 | 我的分数 52 | 学科 53 | TA的分数 54 | 选择 55 | 请选择伴学对象 56 | 未安装手Q或安装的版本不支持 57 | 未安装邮箱软件 58 | 本软件为免费软件,由个人独立开发完成。\n此软件仅供学习交流,勿于商业用途。\n在软件中难免存在一些未修复的漏洞,我深感歉意。\n希望你能尽快联系我修复问题。 59 | 学情报告 60 | 原卷查看 61 | 题目解析 62 | 好友伴学 63 | 没有好友 64 | 全科无法查看 65 | 已将全班添加至列表 66 | 请稍等 67 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 10 | 11 | 14 | 15 | 21 | -------------------------------------------------------------------------------- /app/src/test/java/we/zxlite/ExampleUnitTest.kt: -------------------------------------------------------------------------------- 1 | package we.zxlite 2 | 3 | import org.junit.Test 4 | 5 | import org.junit.Assert.* 6 | 7 | /** 8 | * Example local unit test, which will execute on the development machine (host). 9 | * 10 | * See [testing documentation](http://d.android.com/tools/testing). 11 | */ 12 | class ExampleUnitTest { 13 | @Test 14 | fun addition_isCorrect() { 15 | assertEquals(4, 2 + 2) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | ext.anko_version = '0.10.8' 5 | ext.kotlin_version = '1.3.50' 6 | ext.kotlinx_version = '1.3.2' 7 | repositories { 8 | google() 9 | jcenter() 10 | 11 | } 12 | dependencies { 13 | classpath 'com.android.tools.build:gradle:3.5.2' 14 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" 15 | // NOTE: Do not place your application dependencies here; they belong 16 | // in the individual module build.gradle files 17 | } 18 | } 19 | 20 | allprojects { 21 | repositories { 22 | google() 23 | jcenter() 24 | 25 | } 26 | } 27 | 28 | task clean(type: Delete) { 29 | delete rootProject.buildDir 30 | } 31 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | # IDE (e.g. Android Studio) users: 3 | # Gradle settings configured through the IDE *will override* 4 | # any settings specified in this file. 5 | # For more details on how to configure your build environment visit 6 | # http://www.gradle.org/docs/current/userguide/build_environment.html 7 | # Specifies the JVM arguments used for the daemon process. 8 | # The setting is particularly useful for tweaking memory settings. 9 | org.gradle.jvmargs=-Xmx1536m 10 | # When configured, Gradle will run in incubating parallel mode. 11 | # This option should only be used with decoupled projects. More details, visit 12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 13 | # org.gradle.parallel=true 14 | # AndroidX package structure to make it clearer which packages are bundled with the 15 | # Android operating system, and which are packaged with your app's APK 16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn 17 | android.useAndroidX=true 18 | # Automatically convert third-party libraries to use AndroidX 19 | android.enableJetifier=true 20 | # Kotlin code style for this project: "official" or "obsolete": 21 | kotlin.code.style=official 22 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Git-WeStudio/Zxlite/a737f0bdac52346e754f208129e8f64988116b1d/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Sat Nov 02 11:24:55 CST 2019 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | rootProject.name='智学网' 3 | --------------------------------------------------------------------------------