| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/activity_course_main.xml" value="0.33" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/activity_course_main.xml" value="0.33" /> | ||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/activity_course_statistics_detail.xml" value="0.33" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/activity_course_statistics_detail.xml" value="0.33" /> | ||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/activity_course_test.xml" value="0.31567028985507245" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/activity_course_test.xml" value="0.31567028985507245" /> | ||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/activity_dictionary.xml" value="0.5" /> | |||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/activity_exam_learn_spell.xml" value="0.47690217391304346" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/activity_exam_learn_spell.xml" value="0.47690217391304346" /> | ||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/activity_learn_base.xml" value="0.4979166666666667" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/activity_learn_base.xml" value="0.4979166666666667" /> | ||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/activity_learn_creading.xml" value="0.4304093567251462" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/activity_learn_creading.xml" value="0.4304093567251462" /> | ||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/dialog_common.xml" value="0.30978260869565216" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/dialog_common.xml" value="0.30978260869565216" /> | ||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/dialog_item_select_repeat.xml" value="0.4979166666666667" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/dialog_item_select_repeat.xml" value="0.4979166666666667" /> | ||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/dialog_lesson_learn.xml" value="0.4144927536231884" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/dialog_lesson_learn.xml" value="0.4144927536231884" /> | ||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/dialog_vocabulary.xml" value="0.370018115942029" /> | |||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/fragment_course_lesson.xml" value="0.33" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/fragment_course_lesson.xml" value="0.33" /> | ||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/fragment_course_main.xml" value="0.4979166666666667" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/fragment_course_main.xml" value="0.4979166666666667" /> | ||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/fragment_course_pack.xml" value="0.34427083333333336" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/fragment_course_pack.xml" value="0.34427083333333336" /> | ||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/include_title_bar.xml" value="0.25052083333333336" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/include_title_bar.xml" value="0.25052083333333336" /> | ||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/item_checkbox.xml" value="1.0" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/item_checkbox.xml" value="1.0" /> | ||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/item_course_lesson.xml" value="0.4785615491009682" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/item_course_lesson.xml" value="0.4785615491009682" /> | ||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/item_dic_detail_chinese.xml" value="0.33242753623188404" /> | |||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/item_dic_detail_chinese_for_english_item.xml" value="0.75" /> | |||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/item_dic_detail_english.xml" value="0.5" /> | |||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/item_dic_history_chinese.xml" value="0.23632218844984804" /> | |||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/item_dic_history_english.xml" value="0.23632218844984804" /> | |||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/item_dic_search.xml" value="0.75" /> | |||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/item_empty.xml" value="0.4979166666666667" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/item_empty.xml" value="0.4979166666666667" /> | ||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/item_historical_route.xml" value="0.4859375" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/item_historical_route.xml" value="0.4859375" /> | ||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/item_memo.xml" value="0.67" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/item_memo.xml" value="0.67" /> | ||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/item_memo_detail_list_for_literacy.xml" value="0.67" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/item_memo_detail_list_for_literacy.xml" value="0.67" /> | ||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/item_memo_detail_list_literacy.xml" value="0.5" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/item_memo_detail_list_literacy.xml" value="0.5" /> | ||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/item_memo_detail_list_pinyin.xml" value="0.67" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/item_memo_detail_list_pinyin.xml" value="0.67" /> | ||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/item_service_center_item.xml" value="0.717816683831102" /> | |||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/item_service_center_item.xml" value="0.6604774535809018" /> | |||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/item_spell_single_word.xml" value="0.23632218844984804" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/item_spell_single_word.xml" value="0.23632218844984804" /> | ||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/item_statics_for_time.xml" value="0.27717391304347827" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/item_statics_for_time.xml" value="0.27717391304347827" /> | ||||
| <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/item_statistics_bottom_course_change.xml" value="0.30842391304347827" /> | <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/item_statistics_bottom_course_change.xml" value="0.30842391304347827" /> |
| android:supportsRtl="true" | android:supportsRtl="true" | ||||
| android:theme="@style/Theme.XklLocal" | android:theme="@style/Theme.XklLocal" | ||||
| tools:ignore="LockedOrientationActivity"> | tools:ignore="LockedOrientationActivity"> | ||||
| <activity | |||||
| android:name=".module.m_service_center.DictionaryActivity" | |||||
| android:exported="true" /> | |||||
| <activity | <activity | ||||
| android:name=".module.m_service_center.TestVocabularyActivity" | android:name=".module.m_service_center.TestVocabularyActivity" | ||||
| android:exported="true" /> | android:exported="true" /> |
| override fun coverViewHolder(parent : ViewGroup, viewType : Int) : BaseAdapterViewHolder { | override fun coverViewHolder(parent : ViewGroup, viewType : Int) : BaseAdapterViewHolder { | ||||
| return BaseAdapterViewHolder(DataBindingUtil.inflate(LayoutInflater.from(parent.context), R.layout.item_test_score,parent,false)) | |||||
| return BaseAdapterViewHolder(inflateBinding(parent,R.layout.item_test_score)) | |||||
| } | } | ||||
| @SuppressLint("SetTextI18n") | @SuppressLint("SetTextI18n") |
| package com.xkl.cdl.adapter | |||||
| import android.view.ViewGroup | |||||
| import com.suliang.common.base.adapter.BaseAdapterViewHolder | |||||
| import com.suliang.common.base.adapter.BaseRVAdapterVM | |||||
| import com.suliang.common.databinding.ItemEmptyBinding | |||||
| import com.xkl.cdl.R | |||||
| import com.xkl.cdl.data.bean.DictionaryItem | |||||
| import com.xkl.cdl.module.m_service_center.DictionaryViewModel | |||||
| /** | |||||
| * author suliang | |||||
| * create 2022/8/4 10:41 | |||||
| * Describe: | |||||
| */ | |||||
| class DictionaryAdapter(vm:DictionaryViewModel) : BaseRVAdapterVM<DictionaryItem,DictionaryViewModel>(vm) { | |||||
| override fun getItemCount() : Int { | |||||
| //历史记录,不显示空状态 | |||||
| return if (vm.detailState == 1) { | |||||
| //大于页数显示的总数量,则显示指定数量,否则显示全部 | |||||
| val showCount = vm.histroyShowPage * vm.historyPageSize | |||||
| if (getData().size >= showCount){ | |||||
| showCount | |||||
| }else{ | |||||
| getData().size | |||||
| } | |||||
| }else if (needShowEmptyView && getData().isEmpty()) 1 else getData().size | |||||
| } | |||||
| override fun onBindEmptyViewHolder(holder : BaseAdapterViewHolder) { | |||||
| (holder.binding as ItemEmptyBinding).run { | |||||
| //根据监听,显示具体的内容 | |||||
| vm.etSearchLiveData.value?.let { | |||||
| if (it.isNotEmpty()) { | |||||
| imgEmpty.setImageResource(R.mipmap.empty_nothing_search) | |||||
| tvContent.text = "没有搜索到任何内容" | |||||
| } else { | |||||
| imgEmpty.setImageResource(R.mipmap.empty_nothing) | |||||
| tvContent.text = "没有数据" | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| override fun getItemViewType(position : Int) : Int { | |||||
| return when{ | |||||
| enableEmptyPosition(position) -> TYPE_EMPTY | |||||
| //单条详情 | |||||
| vm.searchItemDetailAble -> { | |||||
| val item = getItem(position) | |||||
| item.form //1英文 2 中文 | |||||
| } | |||||
| //多条记录 | |||||
| else -> 3 | |||||
| } | |||||
| } | |||||
| override fun coverViewHolder(parent : ViewGroup, viewType : Int) : BaseAdapterViewHolder { | |||||
| return when(viewType){ | |||||
| 1 -> BaseAdapterViewHolder(inflateBinding(parent,R.layout.item_dic_detail_english)) //英文搜索结果详情 | |||||
| 2 -> BaseAdapterViewHolder(inflateBinding(parent,R.layout.item_dic_detail_chinese)) //中文搜索结果详情 | |||||
| else -> BaseAdapterViewHolder(inflateBinding(parent,R.layout.item_dic_search)) //记录列表 历史和搜索记录列表 | |||||
| } | |||||
| } | |||||
| override fun onBindVH(holder : BaseAdapterViewHolder, position : Int) { | |||||
| val itemViewType = getItemViewType(position) | |||||
| when(itemViewType){ | |||||
| 1 -> { | |||||
| } | |||||
| 2 -> { | |||||
| } | |||||
| 3 -> { | |||||
| } | |||||
| } | |||||
| } | |||||
| } |
| package com.xkl.cdl.data.bean | |||||
| /** | |||||
| * author suliang | |||||
| * create 2022/8/4 10:47 | |||||
| * Describe: | |||||
| */ | |||||
| open class DictionaryBean() { | |||||
| var id : Long = 0 | |||||
| var word : String? = null | |||||
| var form : Int = 0 // 1 英文 2中文 | |||||
| var pre_index : String? = null //前缀 | |||||
| var phonetic_uk : String? = null | |||||
| var phonectic_us : String? = null | |||||
| var phonectic_cn : String? = null | |||||
| var basic_explaination : String? = null | |||||
| var all_explaination : String? = null | |||||
| var phrase : String? = null | |||||
| var example : String? = null | |||||
| var reference : String? = null | |||||
| } |
| package com.xkl.cdl.data.bean | |||||
| import androidx.room.Entity | |||||
| import androidx.room.Ignore | |||||
| import androidx.room.PrimaryKey | |||||
| /** | |||||
| * author suliang | |||||
| * create 2022/8/4 10:42 | |||||
| * Describe: | |||||
| */ | |||||
| @Entity(tableName = "dic_history",primaryKeys = ["word"]) | |||||
| class DictionaryItem : DictionaryBean() { | |||||
| //课程查询时的课程id | |||||
| var courseId : Long = 0 | |||||
| //查询时间 | |||||
| var queryTime: Long = 0 | |||||
| //词典联想结果判断其是否在历史记录中,如果在历史记录中,则进行时间重排序 | |||||
| @Ignore | |||||
| var inHistory : Boolean = false | |||||
| } |
| * create 2022/7/13 10:48 | * create 2022/7/13 10:48 | ||||
| * Describe: | * Describe: | ||||
| */ | */ | ||||
| class VocabularyItem(val icon: Int, val level: String,val level_e: String) | |||||
| class VocabularyItem(val icon: Int, val level: String,val level_e: String,val stage : Int,val size:Int) |
| package com.xkl.cdl.data.bean.intentdata | package com.xkl.cdl.data.bean.intentdata | ||||
| import com.xkl.cdl.data.bean.VocabularyItem | |||||
| import com.xkl.cdl.data.bean.course.ExamBean | import com.xkl.cdl.data.bean.course.ExamBean | ||||
| import com.xkl.cdl.data.bean.course.Lesson | import com.xkl.cdl.data.bean.course.Lesson | ||||
| * | * | ||||
| * 课时学后测: coursePackType, courseType, testData ,lesson. | * 课时学后测: coursePackType, courseType, testData ,lesson. | ||||
| * | * | ||||
| * 词汇量测试: testData, vocabularyItem | |||||
| */ | */ | ||||
| data class ExamData( | data class ExamData( | ||||
| val subjectId : Int, //项目类型 | val subjectId : Int, //项目类型 | ||||
| // 课程/课时学前测试正确错误列表 key=> {chapter_id}_{lesson_id}_{entity_id} value=>正确 true;错误 false | // 课程/课时学前测试正确错误列表 key=> {chapter_id}_{lesson_id}_{entity_id} value=>正确 true;错误 false | ||||
| var mExamWRMap : HashMap<String, Boolean>? = null | var mExamWRMap : HashMap<String, Boolean>? = null | ||||
| //测词汇量item | |||||
| var vocabularyItem : VocabularyItem? = null | |||||
| } | } |
| abstract fun examDao() : ExamDao | abstract fun examDao() : ExamDao | ||||
| abstract fun examItemDao(): ExamItemDao | abstract fun examItemDao(): ExamItemDao | ||||
| abstract fun examMiddleDao(): ExamMiddleDao | abstract fun examMiddleDao(): ExamMiddleDao | ||||
| abstract fun dictionaryDao(): DictionaryDao | |||||
| companion object{ | companion object{ | ||||
| private var DATABASE_NAME :String = "${FileUtil.getSaveDirPath("db")}${File.separator}app.db" | private var DATABASE_NAME :String = "${FileUtil.getSaveDirPath("db")}${File.separator}app.db" |
| package com.xkl.cdl.data.exam_record | |||||
| import androidx.room.Dao | |||||
| import androidx.room.Insert | |||||
| import androidx.room.OnConflictStrategy | |||||
| import androidx.room.Query | |||||
| import com.xkl.cdl.data.bean.DictionaryItem | |||||
| @Dao | |||||
| interface DictionaryDao { | |||||
| @Insert(onConflict = OnConflictStrategy.REPLACE) | |||||
| fun insert(item:DictionaryItem) | |||||
| @Query("SELECT * FROM dic_history WHERE courseId = :courseId ORDER BY queryTime DESC LIMIT 30") | |||||
| fun query(courseId : Long): MutableList<DictionaryItem> | |||||
| @Query("DELETE FROM dic_history WHERE courseId = :courseId") | |||||
| fun clear(courseId: Long) | |||||
| } |
| package com.xkl.cdl.data.manager.db | |||||
| import android.widget.Toast | |||||
| import com.google.common.base.Joiner | |||||
| import com.suliang.common.util.AppGlobals | |||||
| import com.suliang.common.util.LogUtil | |||||
| import com.suliang.common.util.thread.AppExecutors | |||||
| import com.xkl.cdl.data.bean.DictionaryItem | |||||
| import com.xkl.cdl.data.manager.FilePathManager | |||||
| import net.sqlcipher.database.SQLiteDatabase | |||||
| import java.lang.StringBuilder | |||||
| import java.util.* | |||||
| /** | |||||
| * author suliang | |||||
| * create 2022/7/14 17:28 | |||||
| * Describe: | |||||
| */ | |||||
| object DictionaryManager { | |||||
| private var mDataBase : SQLiteDatabase? = null | |||||
| private var pwd : String = "XKL_XECD_DICT_DATA_KEY" | |||||
| private const val DATA_DICT = "dict" | |||||
| private const val MAX_COUNT = 50 | |||||
| private fun open() { | |||||
| synchronized(DictionaryManager) { | |||||
| if (mDataBase == null) { | |||||
| mDataBase = SQLiteDatabase.openDatabase(FilePathManager.getDictionaryDbPath().path, pwd, null, SQLiteDatabase.OPEN_READONLY) | |||||
| } | |||||
| if (mDataBase == null) { | |||||
| AppExecutors.mainThread.run { | |||||
| Toast.makeText(AppGlobals.application, "词典数据获取失败,请重启应用或联系业务员", Toast.LENGTH_LONG) | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| //避免进行多次的查询 | |||||
| private var count: Int = 0 | |||||
| /** | |||||
| * 简单版词典联想查询 | |||||
| * @param keyWord 关键字 | |||||
| * @param courseId 课程id,用于课程查询时用以记录历史记录的的courseId | |||||
| * @return 查询结果 | |||||
| */ | |||||
| fun queryKeyWordLikeMatchSimple(keyWord : String, courseId : Long = 0) : MutableList<DictionaryItem> { | |||||
| //打开数据库 | |||||
| open() | |||||
| val currentCount : Int = count | |||||
| LogUtil.e("开始查询 $count") | |||||
| count++ | |||||
| //1、完全匹配 | |||||
| //2 、完全包含步变形匹配 | |||||
| //3 、完全包含的变形完整匹配 | |||||
| //4 、非完全包含的匹配 | |||||
| val result : MutableList<DictionaryItem> = mutableListOf() | |||||
| val titleMap : MutableMap<String, Int> = mutableMapOf() | |||||
| var sql = "" | |||||
| //1: wor | |||||
| sql = "SELECT word FROM $DATA_DICT WHERE word = $keyWord" | |||||
| query(sql, titleMap) | |||||
| //2: wor% %wor% | |||||
| sql = "SELECT word FROM $DATA_DICT WHERE word LIKE $keyWord || '%' LIMIT $MAX_COUNT" //完全匹配搜索:以关键字开头的搜索 | |||||
| query(sql, titleMap) | |||||
| if (titleMap.size < MAX_COUNT) { | |||||
| sql = "SELECT word FROM $DATA_DICT WHERE word LIKE '%' || $keyWord || '%' LIMIT $MAX_COUNT" //查找任意位置包含keyword的值 | |||||
| query(sql, titleMap) | |||||
| if (titleMap.size < MAX_COUNT) { | |||||
| //3:% w % o % r % | |||||
| var newKeyWord : String = insertPercent(keyWord) | |||||
| val length = keyWord.length | |||||
| for (i in 0 until length - 1) { | |||||
| val max : Int = MAX_COUNT - titleMap.size | |||||
| newKeyWord = substringEnd(newKeyWord) | |||||
| sql = "SELECT word FROM $DATA_DICT WHERE word LIKE \"$newKeyWord\" LIMIT $max" | |||||
| query(sql, titleMap) | |||||
| if (titleMap.size >= MAX_COUNT) break | |||||
| } | |||||
| } | |||||
| } | |||||
| //查询最终结果 | |||||
| val list = ArrayList(titleMap.entries) | |||||
| list.sortedWith{ o1, o2 -> o1.value.compareTo(o2.value) } | |||||
| for (i in list.indices) { | |||||
| if (count - currentCount != 1) break | |||||
| query(list[i].key,courseId)?.let { | |||||
| result.add(it) | |||||
| } | |||||
| } | |||||
| LogUtil.e("结束查询 $count") | |||||
| return result | |||||
| } | |||||
| /** | |||||
| * 联想查询,仅查询title,并将title放入hashmap中 | |||||
| * @param sql 查询数据 | |||||
| * @param hashMap | |||||
| */ | |||||
| private fun query(sql : String, hashMap : MutableMap<String, Int>) { | |||||
| mDataBase?.rawQuery(sql, null)?.let { | |||||
| while (it.moveToNext()) { | |||||
| if (hashMap.size == MAX_COUNT) break //数量15则打断 | |||||
| val title = it.getString(0) | |||||
| if (hashMap[title] == null) { | |||||
| hashMap[title] = hashMap.size + 1 | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| private val builder = StringBuilder() | |||||
| /** | |||||
| * 字符串添加% | |||||
| * @param value 字符串 | |||||
| * @return | |||||
| */ | |||||
| private fun insertPercent(value : String) : String { | |||||
| val length = value.length | |||||
| if (length == 0) { | |||||
| return "" | |||||
| } | |||||
| builder.setLength(0) | |||||
| builder.append("%") | |||||
| for (i in 0 until length) { | |||||
| builder.append(value[i]).append("%") | |||||
| } | |||||
| return builder.toString() | |||||
| } | |||||
| /** | |||||
| * 去掉字符串最后一位 | |||||
| * @param value 字符串 | |||||
| * @return | |||||
| */ | |||||
| private fun substringEnd(value : String) : String { | |||||
| val length = value.length | |||||
| return if (length == 0) { | |||||
| "" | |||||
| } else value.substring(0, length - 1) | |||||
| } | |||||
| /** | |||||
| * 查询返回数据 精准匹配 | |||||
| * @param word | |||||
| * @return | |||||
| */ | |||||
| fun query(keyWord : String,courseId : Long) : DictionaryItem?{ | |||||
| var mDictionaryItem : DictionaryItem? = null | |||||
| val sql = "SELECT * FROM $DATA_DICT WHERE word = \"$keyWord\"" | |||||
| open() | |||||
| mDataBase?.rawQuery(sql,null)?.let { | |||||
| if (it.count > 0) { | |||||
| it.moveToNext() | |||||
| mDictionaryItem = DictionaryItem().apply { | |||||
| this.courseId = courseId | |||||
| id = it.getLong(0) //id | |||||
| word = it.getString(1) //单词 | |||||
| form = it.getInt(2) | |||||
| pre_index = it.getString(3) | |||||
| phonetic_uk = it.getString(4) | |||||
| phonectic_us = it.getString(5) | |||||
| phonectic_cn = it.getString(6) | |||||
| // setPhoto(it.getString(7)) | |||||
| // setAudio(it.getString(8)) | |||||
| // setDifficulty(it.getInt(9)) | |||||
| basic_explaination = it.getString(10) | |||||
| all_explaination = it.getString(11) | |||||
| phrase = it.getString(12) | |||||
| example = it.getString(13) | |||||
| reference = it.getString(14) | |||||
| // setVersion(it.getInt(15)) //version版本 | |||||
| } | |||||
| } | |||||
| it.close() | |||||
| } | |||||
| return mDictionaryItem | |||||
| } | |||||
| /** | |||||
| * 查询返回数据 批量精准匹配 | |||||
| * @param words | |||||
| * @param courseId 课程查询的courseId | |||||
| * @return | |||||
| */ | |||||
| fun querys(words : List<String>,courseId : Long = 0 ) : List<DictionaryItem> { | |||||
| val list : MutableList<DictionaryItem> = ArrayList<DictionaryItem>() | |||||
| val sql = "SELECT * FROM " + DATA_DICT + " WHERE word IN (" + Joiner.on(",").join(words) + ")" | |||||
| open() | |||||
| mDataBase?.rawQuery(sql, null)?.let { | |||||
| while (it.moveToNext()) { | |||||
| val mDictionaryItem = DictionaryItem().apply { | |||||
| this.courseId = courseId | |||||
| id = it.getLong(0) //id | |||||
| word = it.getString(1) //单词 | |||||
| form = it.getInt(2) | |||||
| pre_index = it.getString(3) | |||||
| phonetic_uk = it.getString(4) | |||||
| phonectic_us = it.getString(5) | |||||
| phonectic_cn = it.getString(6) | |||||
| // setPhoto(it.getString(7)) | |||||
| // setAudio(it.getString(8)) | |||||
| // setDifficulty(it.getInt(9)) | |||||
| basic_explaination = it.getString(10) | |||||
| all_explaination = it.getString(11) | |||||
| phrase = it.getString(12) | |||||
| example = it.getString(13) | |||||
| reference = it.getString(14) | |||||
| } | |||||
| list.add(mDictionaryItem) | |||||
| } | |||||
| it.close() | |||||
| } | |||||
| //去重 排序 | |||||
| return list.distinctBy { it.word }.sortedBy { | |||||
| words.indexOf(it.word) | |||||
| } | |||||
| } | |||||
| } |
| package com.xkl.cdl.data.manager.db | package com.xkl.cdl.data.manager.db | ||||
| import android.widget.Toast | import android.widget.Toast | ||||
| import androidx.core.database.getBlobOrNull | |||||
| import appApi.AppApi | import appApi.AppApi | ||||
| import com.suliang.common.AppConfig | |||||
| import com.suliang.common.util.AppGlobals | import com.suliang.common.util.AppGlobals | ||||
| import com.suliang.common.util.file.FileUtil | |||||
| import com.suliang.common.util.thread.AppExecutors | import com.suliang.common.util.thread.AppExecutors | ||||
| import com.xkl.cdl.data.AppConstants | import com.xkl.cdl.data.AppConstants | ||||
| import com.xkl.cdl.data.bean.VocabularyItem | import com.xkl.cdl.data.bean.VocabularyItem | ||||
| import com.xkl.cdl.data.bean.course.ExamBean | import com.xkl.cdl.data.bean.course.ExamBean | ||||
| import com.xkl.cdl.data.manager.FilePathManager | import com.xkl.cdl.data.manager.FilePathManager | ||||
| import net.sqlcipher.database.SQLiteDatabase | import net.sqlcipher.database.SQLiteDatabase | ||||
| import java.io.File | |||||
| /** | /** | ||||
| * author suliang | * author suliang | ||||
| */ | */ | ||||
| object VocabularyManager { | object VocabularyManager { | ||||
| private var mDataBase : SQLiteDatabase? = null | |||||
| private var mDataBase : SQLiteDatabase? = null | |||||
| private var pwd : String = "XKL_VOCABULARY_DATA_KEY" //https://cdn.xuekaole.com/dict/vocabulary.db | |||||
| // XKL_XECD_DICT_DATA_KEY https://cdn.xuekaole.com/dict/xecd_dict.db | |||||
| private fun open() { | private fun open() { | ||||
| synchronized(VocabularyManager) { | synchronized(VocabularyManager) { | ||||
| if (mDataBase == null) { | if (mDataBase == null) { | ||||
| mDataBase = SQLiteDatabase.openDatabase(FilePathManager.getVocabularyDbPath().path, "", null, SQLiteDatabase.OPEN_READONLY) | |||||
| mDataBase = SQLiteDatabase.openDatabase(FilePathManager.getVocabularyDbPath().path, pwd, null, | |||||
| SQLiteDatabase.OPEN_READONLY) | |||||
| } | } | ||||
| if (mDataBase == null) { | if (mDataBase == null) { | ||||
| AppExecutors.mainThread.run { | AppExecutors.mainThread.run { | ||||
| * @param level VocabularyItem | * @param level VocabularyItem | ||||
| * @return List<ExamBean> | * @return List<ExamBean> | ||||
| */ | */ | ||||
| fun queryVocabularyTestData(level : VocabularyItem) : List<ExamBean>{ | |||||
| fun queryVocabularyTestData(level : VocabularyItem) : List<ExamBean> { | |||||
| open() | open() | ||||
| val result = mutableListOf<ExamBean>() | val result = mutableListOf<ExamBean>() | ||||
| val sql = "SELECT * FROM " | |||||
| val sql = "SELECT * FROM exam WHERE stage <= ${level.stage} ORDER BY random() LIMIT 100" | |||||
| mDataBase?.rawQuery(sql, null)?.let { | |||||
| while (it.moveToNext()) { | |||||
| result.add(ExamBean().apply { | |||||
| id = it.getLong(0) | |||||
| word_id = it.getLong(1) | |||||
| word = it.getString(2) | |||||
| correct = it.getString(3) | |||||
| error1 = it.getString(4) | |||||
| error2 = it.getString(5) | |||||
| error3 = it.getString(6) | |||||
| }) | |||||
| } | |||||
| it.close() | |||||
| } | |||||
| return result; | |||||
| } | } | ||||
| /** | |||||
| * 查询单词的发音音频 | |||||
| * @param base DbControlBase | |||||
| * @param wordId Long 查询单词 | |||||
| * @param soundWay Int 发音方式 | |||||
| * @return String 发音保存的文件名称 要不为空,要不为文件地址, 为空,则表明没有发音文件,如果是英美发音方式,则表示英美都没有发音内容 | |||||
| */ | |||||
| fun queryAudio(wordId : Long, soundWay : Int) : String? { | |||||
| val sql = "SELECT audio_us,audio_uk FROM exam WHERE word_id = $wordId" | |||||
| var audio_us : ByteArray? = null | |||||
| var audio_uk : ByteArray? = null | |||||
| open() | |||||
| mDataBase?.rawQuery(sql, null)?.let { | |||||
| while (it.moveToNext()) { | |||||
| //写入文件 | |||||
| audio_us = it.getBlobOrNull(0) | |||||
| audio_uk = it.getBlobOrNull(1) | |||||
| } | |||||
| it.close() | |||||
| } | |||||
| //不为空,写入本身,如果为空,用另外的发音方式写入 | |||||
| val parentPath = FileUtil.getSaveDirPath(AppConfig.VOICE) | |||||
| val audio_us_file_path = audio_us?.let { | |||||
| val audioFileNameUS = "${wordId}_${AppConstants.SOUND_TYPE_US}" | |||||
| val file = File(parentPath, audioFileNameUS) | |||||
| FileUtil.writeBytesToFile(file, it) | |||||
| file.path | |||||
| } ?: audio_uk?.let { | |||||
| val audioFileNameUS = "${wordId}_${AppConstants.SOUND_TYPE_US}" | |||||
| val file = File(parentPath, audioFileNameUS) | |||||
| FileUtil.writeBytesToFile(file, it) | |||||
| file.path | |||||
| } | |||||
| //不为空,写入本身,如果为空,用另外的发音方式写入 | |||||
| val audio_uk_file_path = audio_uk?.let { | |||||
| val audioFileNameUk = "${wordId}_${AppConstants.SOUND_TYPE_UK}" | |||||
| val file = File(parentPath, audioFileNameUk) | |||||
| FileUtil.writeBytesToFile(file, it) | |||||
| file.path | |||||
| } ?: audio_us?.let { | |||||
| val audioFileNameUk = "${wordId}_${AppConstants.SOUND_TYPE_UK}" | |||||
| val file = File(parentPath, audioFileNameUk) | |||||
| FileUtil.writeBytesToFile(file, it) | |||||
| file.path | |||||
| } | |||||
| return if (soundWay == AppConstants.SOUND_TYPE_UK) audio_uk_file_path else audio_us_file_path | |||||
| } | |||||
| } | } |
| import com.xkl.cdl.data.AppConstants | import com.xkl.cdl.data.AppConstants | ||||
| import com.xkl.cdl.data.manager.db.DBCourseManager | import com.xkl.cdl.data.manager.db.DBCourseManager | ||||
| import com.xkl.cdl.data.manager.db.DbControlBase | import com.xkl.cdl.data.manager.db.DbControlBase | ||||
| import com.xkl.cdl.data.manager.db.VocabularyManager | |||||
| import io.reactivex.rxjava3.core.Observable | import io.reactivex.rxjava3.core.Observable | ||||
| import java.io.File | import java.io.File | ||||
| import java.util.* | import java.util.* | ||||
| } | } | ||||
| return lruCache[fileName] | return lruCache[fileName] | ||||
| } | } | ||||
| fun getVocabulary(wordId : Long,soundWay : Int){ | |||||
| //父文件路劲 | |||||
| val parentPath = FileUtil.getSaveDirPath(AppConfig.VOICE) | |||||
| //先查对应的文件路径 : 项目id_课程包id_课程id_单词id_发音方式 | |||||
| val defaultKey = "${wordId}_$soundWay" | |||||
| Observable.fromCallable { | |||||
| //不为空,直接取值 | |||||
| if (lruCache.get(defaultKey) == null){ | |||||
| //为空 查文件 | |||||
| val file = File(parentPath, defaultKey) | |||||
| when { | |||||
| file.exists() -> lruCache.put(defaultKey, file.path) //文件存在,则表示以前进行过数据库查询,且进行了保存文件,英美发音本地都有文件 | |||||
| else -> { //文件不存在,则查询数据库进行查询,返回的为保存的文件地址 | |||||
| val filePath = VocabularyManager.queryAudio(wordId, soundWay) | |||||
| filePath?.also { | |||||
| when(soundWay){ | |||||
| AppConstants.SOUND_TYPE_UK -> { | |||||
| lruCache.put(defaultKey, it) //保存路径 | |||||
| val audioFileNameUS = "${wordId}_${AppConstants.SOUND_TYPE_US}" | |||||
| lruCache.put(audioFileNameUS, File(parentPath,audioFileNameUS).path) //保存路径 | |||||
| } | |||||
| AppConstants.SOUND_TYPE_US -> { | |||||
| lruCache.put(defaultKey, it) //保存路径 | |||||
| val audioFileNameUS = "${wordId}_${AppConstants.SOUND_TYPE_UK}" | |||||
| lruCache.put(audioFileNameUS, File(parentPath,audioFileNameUS).path) //保存路径 | |||||
| } | |||||
| else -> lruCache.put(defaultKey, it) //保存路径 | |||||
| } | |||||
| } //如果查询返回路径为空,则说明,没有发音内容 | |||||
| } | |||||
| } | |||||
| } | |||||
| return@fromCallable lruCache.get(defaultKey) ?: "" | |||||
| }.compose(diskIo2Main()).subscribe { | |||||
| if (this::audioLiveData.isInitialized) | |||||
| audioLiveData.value = it | |||||
| } | |||||
| } | |||||
| } | } |
| } | } | ||||
| override fun resizeDialog(){} | |||||
| } | } |
| //备忘本测试 课程测试 | //备忘本测试 课程测试 | ||||
| AppConstants.TEST_TYPE_SERVICE_CENTER, | AppConstants.TEST_TYPE_SERVICE_CENTER, | ||||
| AppConstants.TEST_TYPE_MEMO -> initMemoTestOver() | AppConstants.TEST_TYPE_MEMO -> initMemoTestOver() | ||||
| //词汇量测试结束 | |||||
| } | } | ||||
| //学习结束弹窗 | //学习结束弹窗 | ||||
| AppConstants.DIALOG_TYPE_LEARNING_OVER -> initLessonLearningOver(false) | AppConstants.DIALOG_TYPE_LEARNING_OVER -> initLessonLearningOver(false) | ||||
| } | } | ||||
| } | } | ||||
| override fun onStart() { | |||||
| super.onStart() | |||||
| //设置dialog位置 | |||||
| requireDialog().window?.let { | |||||
| it.attributes.run { | |||||
| y = ScreenUtil.getScreenHeight() / 5 | |||||
| it.attributes = this | |||||
| } | |||||
| it.setGravity(Gravity.TOP) | |||||
| } | |||||
| } | |||||
| /** 初始化分数 */ | /** 初始化分数 */ | ||||
| private fun initScore() { | private fun initScore() { | ||||
| //插画 | //插画 |
| package com.xkl.cdl.dialog | |||||
| import android.annotation.SuppressLint | |||||
| import android.os.Bundle | |||||
| import android.view.Gravity | |||||
| import android.view.View | |||||
| import com.suliang.common.AppConfig | |||||
| import com.suliang.common.base.BaseDialogFragment | |||||
| import com.suliang.common.extension.click | |||||
| import com.suliang.common.extension.setHtml | |||||
| import com.suliang.common.util.os.ScreenUtil | |||||
| import com.xkl.cdl.R | |||||
| import com.xkl.cdl.data.AppConstants | |||||
| import com.xkl.cdl.databinding.DialogVocabularyBinding | |||||
| /** | |||||
| * author suliang | |||||
| * create 2022/4/2 15:47 | |||||
| * Describe: 词汇量测试结束弹窗 | |||||
| */ | |||||
| class VocabularyDialog private constructor() : BaseDialogFragment<DialogVocabularyBinding>() { | |||||
| companion object { | |||||
| /** | |||||
| * @param levelName String 测试级别 | |||||
| * @param testTime String 测试时间 | |||||
| * @param testCount Int 词汇量 | |||||
| * @param coverRange Int 覆盖率 | |||||
| * @return VocabularyDialog | |||||
| */ | |||||
| fun newInstance( levelName:String, testTime : String, testCount: Int, coverRange:Int) : VocabularyDialog { | |||||
| val args = Bundle() | |||||
| args.putString(AppConfig.INTENT_1, levelName) | |||||
| args.putString(AppConfig.INTENT_2, testTime) | |||||
| args.putInt(AppConfig.INTENT_3, testCount) | |||||
| args.putInt(AppConfig.INTENT_4, coverRange) | |||||
| val fragment = VocabularyDialog() | |||||
| fragment.arguments = args | |||||
| return fragment | |||||
| } | |||||
| } | |||||
| /** 事件动作 */ | |||||
| lateinit var onDialogListener : (action : Int, dialog : VocabularyDialog) -> Unit | |||||
| @SuppressLint("SetTextI18n") | |||||
| override fun initFragment() { | |||||
| val levelName = requireArguments().getString(AppConfig.INTENT_1) | |||||
| val testTime = requireArguments().getString(AppConfig.INTENT_2) | |||||
| val testCount = requireArguments().getInt(AppConfig.INTENT_3) | |||||
| val coverRange = requireArguments().getInt(AppConfig.INTENT_4) | |||||
| binding.tvVocabulary.text = "学考乐词汇量测试:$levelName" | |||||
| binding.tvVocabularyTestTime.text = testTime | |||||
| when(testCount){ | |||||
| 0 -> { | |||||
| binding.groupVocabularyNormal.visibility = View.GONE | |||||
| binding.tvVocabularyLittle.visibility = View.VISIBLE | |||||
| binding.tvLeft.apply { | |||||
| text = getString(R.string.done) | |||||
| click { | |||||
| onDialogListener(AppConstants.DIALOG_OVER,this@VocabularyDialog) | |||||
| } | |||||
| } | |||||
| binding.tvRight.apply { | |||||
| text = getString(R.string.test_again) | |||||
| click { | |||||
| onDialogListener(AppConstants.DIALOG_START_TEST,this@VocabularyDialog) | |||||
| } | |||||
| } | |||||
| } | |||||
| else -> { | |||||
| binding.groupVocabularyNormal.visibility = View.VISIBLE | |||||
| binding.tvVocabularyLittle.visibility = View.GONE | |||||
| binding.tvVocabularyCount.text = "$testCount" | |||||
| binding.ratingBar.setStar(coverRange / 20f) | |||||
| binding.tvVocabularyCoverRateStage.setHtml("覆盖率<font color = \'#F7874F\'>${coverRange}%</font>($levelName)") | |||||
| binding.tvLeft.apply { | |||||
| text = getString(R.string.test_again) | |||||
| click { | |||||
| onDialogListener(AppConstants.DIALOG_START_TEST,this@VocabularyDialog) | |||||
| } | |||||
| } | |||||
| binding.tvRight.apply { | |||||
| text = getString(R.string.done) | |||||
| click { | |||||
| onDialogListener(AppConstants.DIALOG_OVER,this@VocabularyDialog) | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| } |
| import com.xkl.cdl.data.AppConstants | import com.xkl.cdl.data.AppConstants | ||||
| import com.xkl.cdl.data.DataTransferHolder | import com.xkl.cdl.data.DataTransferHolder | ||||
| import com.xkl.cdl.data.bean.LearnDialogBean | import com.xkl.cdl.data.bean.LearnDialogBean | ||||
| import com.xkl.cdl.data.bean.VocabularyItem | |||||
| import com.xkl.cdl.data.bean.course.ExamBean | import com.xkl.cdl.data.bean.course.ExamBean | ||||
| import com.xkl.cdl.data.event.LearnEventData | import com.xkl.cdl.data.event.LearnEventData | ||||
| import com.xkl.cdl.data.manager.CourseManager | import com.xkl.cdl.data.manager.CourseManager | ||||
| import com.xkl.cdl.dialog.CommonDialog | import com.xkl.cdl.dialog.CommonDialog | ||||
| import com.xkl.cdl.dialog.CommonDialogBean | import com.xkl.cdl.dialog.CommonDialogBean | ||||
| import com.xkl.cdl.dialog.LearnDialog | import com.xkl.cdl.dialog.LearnDialog | ||||
| import com.xkl.cdl.dialog.VocabularyDialog | |||||
| import com.xkl.cdl.module.m_service_center.TestDetailActivity | import com.xkl.cdl.module.m_service_center.TestDetailActivity | ||||
| /** | /** | ||||
| /** 新单词来了的发音事件 */ | /** 新单词来了的发音事件 */ | ||||
| private fun initNewWordRead(it : ExamBean) { | private fun initNewWordRead(it : ExamBean) { | ||||
| //词汇量测试,新单词发音 | |||||
| if (vm.intentData.examType == AppConstants.TEST_TYPE_NORMAL){ | |||||
| wordChooseBinding.ivVoice.performClick() | |||||
| return | |||||
| } | |||||
| when (vm.intentData.courseType) { | when (vm.intentData.courseType) { | ||||
| //拼写初始不发音,作文不发音, 音标课程测试不发音 | //拼写初始不发音,作文不发音, 音标课程测试不发音 | ||||
| AppConstants.COURSE_TYPE_ENGLISH_SOUNDMARK, AppConstants.COURSE_TYPE_ENGLISH_SPELL, AppConstants.COURSE_TYPE_CHINESE_COMPOSITION -> { | AppConstants.COURSE_TYPE_ENGLISH_SOUNDMARK, AppConstants.COURSE_TYPE_ENGLISH_SPELL, AppConstants.COURSE_TYPE_CHINESE_COMPOSITION -> { | ||||
| AppConstants.COURSE_TYPE_ENGLISH_VOICE -> { | AppConstants.COURSE_TYPE_ENGLISH_VOICE -> { | ||||
| wordChooseBinding.ivVoice.performClick() | wordChooseBinding.ivVoice.performClick() | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| private fun initStatistics() { | private fun initStatistics() { | ||||
| binding.incStatistics.run { | binding.incStatistics.run { | ||||
| progressTestNumber.max = vm.testData.size | progressTestNumber.max = vm.testData.size | ||||
| tvTestTypeName.text = CourseManager.getExamTypeName(vm.intentData.examType) | |||||
| //测试类型 | |||||
| tvTestTypeName.text = when (vm.intentData.examType) { | |||||
| AppConstants.TEST_TYPE_NORMAL -> vm.intentData.vocabularyItem?.level | |||||
| else -> CourseManager.getExamTypeName(vm.intentData.examType) | |||||
| } | |||||
| //监听总时间的改变 | //监听总时间的改变 | ||||
| vm.totalUseTime.observe(this@LearnExamActivity) { | vm.totalUseTime.observe(this@LearnExamActivity) { | ||||
| tvTestTime.text = DateUtil.formatGMT(it, DateUtil.FORMAT_2) | tvTestTime.text = DateUtil.formatGMT(it, DateUtil.FORMAT_2) | ||||
| vm.errorLiveData.observe(this@LearnExamActivity) { | vm.errorLiveData.observe(this@LearnExamActivity) { | ||||
| tvErrorNumber.text = "错误: $it" | tvErrorNumber.text = "错误: $it" | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } ?: let { //取消事件 | |||||
| } ?: let { //取消选项答案选择事件,设置选项发音事件 | |||||
| vm.optionList.forEachIndexed { index, optionItemBinding -> | vm.optionList.forEachIndexed { index, optionItemBinding -> | ||||
| optionItemBinding.root.click(null) | optionItemBinding.root.click(null) | ||||
| optionItemBinding.tvOption.click { optionItemBinding.ivOption.performClick() } | optionItemBinding.tvOption.click { optionItemBinding.ivOption.performClick() } | ||||
| //口语的音频,有问题,与选项 直接获取其tag获取音频 | //口语的音频,有问题,与选项 直接获取其tag获取音频 | ||||
| currentPlayView?.cancelAnimation() | currentPlayView?.cancelAnimation() | ||||
| if (view is LottieAnimationView && view.visibility == View.VISIBLE) currentPlayView = view | if (view is LottieAnimationView && view.visibility == View.VISIBLE) currentPlayView = view | ||||
| if (isSpokenTotalTest()) { | |||||
| //口语课程学前学后总的点击事件取tag | |||||
| AudioCache.get(view.tag as String) | |||||
| } else { | |||||
| AudioCache.get(vm.dbBaseControl, it.word_id, vm.defaultSoundWay) | |||||
| when{ | |||||
| //词汇量测试 | |||||
| vm.intentData.examType == AppConstants.TEST_TYPE_NORMAL -> AudioCache.getVocabulary(it.word_id,vm.defaultSoundWay) | |||||
| //口语 | |||||
| isSpokenTotalTest() -> AudioCache.get(view.tag as String) | |||||
| //测试 | |||||
| else -> AudioCache.get(vm.dbBaseControl, it.word_id, vm.defaultSoundWay) | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /** 测试完成 : 弹窗显示 */ | /** 测试完成 : 弹窗显示 */ | ||||
| private fun testOver() { | private fun testOver() { | ||||
| if (vm.intentData.examType == AppConstants.TEST_TYPE_NORMAL){ | |||||
| vm.intentData.vocabularyItem?.let { | |||||
| val createTime = DateUtil.format(System.currentTimeMillis(), DateUtil.FORMAT_1) | |||||
| VocabularyDialog.newInstance(it.level,createTime,vm.scoreValue,vm.vocabularyCoverange).apply { | |||||
| onDialogListener = { action, dialog -> | |||||
| when(action){ | |||||
| //完成 | |||||
| AppConstants.DIALOG_OVER -> { | |||||
| dialog.dismissAllowingStateLoss() | |||||
| finish() | |||||
| } | |||||
| //再测一次 | |||||
| AppConstants.DIALOG_START_TEST -> { | |||||
| dialog.dismissAllowingStateLoss() | |||||
| finish() | |||||
| LiveEventBus.get<VocabularyItem>("vocabulary_test").post(vm.intentData.vocabularyItem) | |||||
| } | |||||
| } | |||||
| } | |||||
| }.show(supportFragmentManager,"vocabulary") | |||||
| } | |||||
| return | |||||
| } | |||||
| //对话框信息实体 | //对话框信息实体 | ||||
| val learnDialogBean = LearnDialogBean(AppConstants.DIALOG_TYPE_EXAM_OVER).apply { | val learnDialogBean = LearnDialogBean(AppConstants.DIALOG_TYPE_EXAM_OVER).apply { | ||||
| examType = vm.intentData.examType | examType = vm.intentData.examType | ||||
| score = vm.scoreValue | score = vm.scoreValue | ||||
| correctNumber = vm.correctLiveData.value!! | correctNumber = vm.correctLiveData.value!! | ||||
| errorNumber = vm.errorLiveData.value!! | errorNumber = vm.errorLiveData.value!! | ||||
| //备忘本需要显示课程名称 | |||||
| if (examType == AppConstants.TEST_TYPE_MEMO || examType == AppConstants.TEST_TYPE_SERVICE_CENTER){ | |||||
| //备忘本、课程测试需要显示课程名称 | |||||
| if (examType == AppConstants.TEST_TYPE_MEMO || examType == AppConstants.TEST_TYPE_SERVICE_CENTER) { | |||||
| showTimeCount = vm.intentData.showTitle | showTimeCount = vm.intentData.showTitle | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| //备忘本测试 | //备忘本测试 | ||||
| AppConstants.TEST_TYPE_SERVICE_CENTER, | |||||
| AppConstants.TEST_TYPE_MEMO -> when(action){ | |||||
| AppConstants.TEST_TYPE_SERVICE_CENTER, AppConstants.TEST_TYPE_MEMO -> when (action) { | |||||
| //完成 | //完成 | ||||
| AppConstants.DIALOG_OVER -> { | AppConstants.DIALOG_OVER -> { | ||||
| dialog.dismissAllowingStateLoss() | dialog.dismissAllowingStateLoss() |
| createErrorRecord() | createErrorRecord() | ||||
| } | } | ||||
| } | } | ||||
| //添加到记录集合 | |||||
| mExamRecordList.add(currentExamRecord!!.build()) | |||||
| //添加到记录集合 词汇量测试不添加记录 | |||||
| if (intentData.examType != AppConstants.TEST_TYPE_NORMAL) { | |||||
| mExamRecordList.add(currentExamRecord!!.build()) | |||||
| } | |||||
| currentChooseResultLiveData.value = chooseResult | currentChooseResultLiveData.value = chooseResult | ||||
| } | } | ||||
| //分数 与 覆盖率 只有测试成功才进行计算 | //分数 与 覆盖率 只有测试成功才进行计算 | ||||
| if (isVocablularySuccess) { | if (isVocablularySuccess) { | ||||
| val converange = (calculateCorrectNumber - 25) / 75 //被测试题的占比重 | val converange = (calculateCorrectNumber - 25) / 75 //被测试题的占比重 | ||||
| // TODO: 2022/4/14 16000应该为该词汇量测试对应的词汇数 | |||||
| scoreValue = (16000 * converange).toInt() | |||||
| // 用了了100只是预防取值错误时不好看 | |||||
| scoreValue = ( intentData.vocabularyItem?.size ?: 100 * converange).toInt() | |||||
| vocabularyCoverange = (converange * 100).toInt() //测试类型的覆盖率 | vocabularyCoverange = (converange * 100).toInt() //测试类型的覆盖率 | ||||
| } | } | ||||
| } | } | ||||
| stage = "小学" | stage = "小学" | ||||
| coverRate = vocabularyCoverange.toFloat() | coverRate = vocabularyCoverange.toFloat() | ||||
| } | } | ||||
| //添加测试题 | |||||
| addAllRecord(mExamRecordList) | |||||
| //添加测试题 词汇量测试不添加测试题 | |||||
| if (intentData.examType != AppConstants.TEST_TYPE_NORMAL) { | |||||
| addAllRecord(mExamRecordList) | |||||
| } | |||||
| } | } | ||||
| // //是否完成 | |||||
| // if (examType == SyncStateContract.Constants.TEST_TYPE_AFTER_TOTAL && mData.getScore() >= SyncStateContract.Constants.SCORE_1 && !mData.isCourseFinished()) { | |||||
| // learnExam.setIsFinished(true) | |||||
| // } | |||||
| //最终上传数据 | //最终上传数据 | ||||
| record.addExam(learnExam) //测试试卷 | record.addExam(learnExam) //测试试卷 | ||||
| //时间 学习中心的测试需要添加为学习时间 | //时间 学习中心的测试需要添加为学习时间 |
| package com.xkl.cdl.module.m_service_center | |||||
| import android.annotation.SuppressLint | |||||
| import android.content.Context | |||||
| import android.content.Intent | |||||
| import android.os.Bundle | |||||
| import android.view.View | |||||
| import androidx.lifecycle.ViewModelProvider | |||||
| import androidx.recyclerview.widget.LinearLayoutManager | |||||
| import com.suliang.common.AppConfig | |||||
| import com.suliang.common.base.activity.BaseActivityVM | |||||
| import com.suliang.common.extension.click | |||||
| import com.xkl.cdl.R | |||||
| import com.xkl.cdl.databinding.ActivityDictionaryBinding | |||||
| import com.xkl.cdl.dialog.CommonDialog | |||||
| import com.xkl.cdl.dialog.CommonDialogBean | |||||
| import com.xkl.cdl.module.m_service_center.DictionaryViewModel.Companion.STATE_HISTROY | |||||
| import com.xkl.cdl.module.m_service_center.DictionaryViewModel.Companion.STATE_SEARCH | |||||
| class DictionaryActivity : BaseActivityVM<ActivityDictionaryBinding, DictionaryViewModel>() { | |||||
| companion object { | |||||
| fun newInstance(context : Context, courseId : Long = 0) { | |||||
| val intent = Intent(context, DictionaryActivity::class.java) | |||||
| intent.putExtra(AppConfig.INTENT_1, courseId) | |||||
| context.startActivity(intent) | |||||
| } | |||||
| } | |||||
| override fun initViewModel() : DictionaryViewModel { | |||||
| return ViewModelProvider(this)[DictionaryViewModel::class.java] | |||||
| } | |||||
| @SuppressLint("NotifyDataSetChanged") | |||||
| override fun initActivity(savedInstanceState : Bundle?) { | |||||
| vm.courseId = intent.getLongExtra(AppConfig.INTENT_1, 0) | |||||
| initHistoryRecyclerView() | |||||
| //点击 查看更多 | |||||
| binding.tvSeeMore.click { | |||||
| when (vm.detailState) { | |||||
| STATE_HISTROY -> { | |||||
| //显示页面加1, 列表更新 | |||||
| vm.histroyShowPage++ | |||||
| vm.adapter.notifyDataSetChanged() | |||||
| //根据数量判断,是否还要显示 | |||||
| binding.tvSeeMore.visibility = if (vm.historyList.size > vm.histroyShowPage * vm.historyPageSize) View.VISIBLE else View.GONE | |||||
| } | |||||
| STATE_SEARCH -> { | |||||
| //显示页面加1, 列表更新 | |||||
| vm.searchShowPage++ | |||||
| vm.adapter.notifyDataSetChanged() | |||||
| //根据数量判断,是否还要显示 | |||||
| binding.tvSeeMore.visibility = if (vm.searchDetailList.size > vm.searchShowPage * vm.historyPageSize) View.VISIBLE else View.GONE | |||||
| } | |||||
| } | |||||
| } | |||||
| //删除历史记录,弹窗提示 | |||||
| binding.ivDelete.click { | |||||
| val commonDialogBean = CommonDialogBean(titleText = R.string.dialog_delete_history, leftText = R.string.delete, | |||||
| rightText = R.string.cancel) | |||||
| CommonDialog.newInstance(commonDialogBean).apply { | |||||
| onCommonDialogButtonClickListener = { dialog : CommonDialog, isRightClick : Boolean -> | |||||
| if (!isRightClick) { //删除 | |||||
| vm.clearHistory() | |||||
| } | |||||
| dialog.dismissAllowingStateLoss() | |||||
| } | |||||
| }.show(supportFragmentManager, javaClass.name) | |||||
| } | |||||
| } | |||||
| private fun initHistoryRecyclerView() { | |||||
| binding.rv.apply { | |||||
| layoutManager = LinearLayoutManager(this@DictionaryActivity, LinearLayoutManager.VERTICAL, false) | |||||
| adapter = vm.adapter | |||||
| } | |||||
| } | |||||
| @SuppressLint("NotifyDataSetChanged") | |||||
| override fun loadData() { | |||||
| //更新历史记录适配器 | |||||
| vm.updateHistoryAdapterLiveData.observe(this) { | |||||
| when { | |||||
| //历史记录 | |||||
| !it -> vm.adapter.apply { | |||||
| //如果非历史列表记录,则更新列表布局的状态 | |||||
| if (vm.detailState != STATE_HISTROY) { | |||||
| vm.detailState = STATE_HISTROY | |||||
| binding.apply { | |||||
| tvHistoryTitle.visibility = View.VISIBLE | |||||
| ivDelete.visibility = View.VISIBLE | |||||
| } | |||||
| } | |||||
| binding.layoutDetail.visibility = if (vm.historyList.isEmpty()) View.GONE else View.VISIBLE | |||||
| binding.tvSeeMore.visibility = if (vm.historyList.size > vm.histroyShowPage * vm.historyPageSize) View.VISIBLE else View.GONE | |||||
| //更新值 | |||||
| needShowEmptyView = false | |||||
| setData(vm.historyList) | |||||
| } | |||||
| //搜索结果 | |||||
| else -> vm.adapter.apply { | |||||
| if (vm.detailState != STATE_SEARCH) { | |||||
| vm.detailState = STATE_SEARCH | |||||
| binding.apply { | |||||
| tvHistoryTitle.visibility = View.GONE | |||||
| ivDelete.visibility = View.GONE | |||||
| } | |||||
| } | |||||
| binding.layoutDetail.visibility = View.VISIBLE | |||||
| binding.tvSeeMore.visibility = if (vm.searchDetailList.size > vm.searchShowPage * vm.historyPageSize) View.VISIBLE else View.GONE | |||||
| needShowEmptyView = vm.searchDetailList.size == 0 | |||||
| setData(vm.searchDetailList) | |||||
| } | |||||
| } | |||||
| } | |||||
| /**搜索监听*/ | |||||
| vm.etSearchLiveData.observe(this) { | |||||
| when { | |||||
| //直接历史记录更新 | |||||
| it.isNullOrEmpty() -> vm.updateHistoryAdapterLiveData.value = false | |||||
| //历史记录的详情 | |||||
| vm.searchItemDetailAble -> { | |||||
| } | |||||
| //关键字搜索 | |||||
| else -> vm.searchKeyWord(it) | |||||
| } | |||||
| } | |||||
| //查询历史记录 | |||||
| vm.loadHistory() | |||||
| } | |||||
| /** | |||||
| * 详情中的状态 | |||||
| * @param state Int 1历史记录 2搜索详情 | |||||
| */ | |||||
| private fun initLayoutDetailState(state : Int) { | |||||
| when (state) { | |||||
| //历史布局 | |||||
| STATE_HISTROY -> binding.apply { | |||||
| tvHistoryTitle.visibility = View.VISIBLE | |||||
| ivDelete.visibility = View.VISIBLE | |||||
| } | |||||
| //查询详情 | |||||
| STATE_SEARCH -> binding.apply { | |||||
| tvHistoryTitle.visibility = View.GONE | |||||
| ivDelete.visibility = View.GONE | |||||
| } | |||||
| } | |||||
| binding.tvSeeMore.visibility = View.GONE | |||||
| } | |||||
| } |
| package com.xkl.cdl.module.m_service_center | |||||
| import android.os.Handler | |||||
| import android.os.Looper | |||||
| import androidx.lifecycle.MutableLiveData | |||||
| import com.suliang.common.base.viewmodel.BaseViewModel | |||||
| import com.suliang.common.util.thread.AppExecutors | |||||
| import com.xkl.cdl.adapter.DictionaryAdapter | |||||
| import com.xkl.cdl.data.bean.DictionaryItem | |||||
| import com.xkl.cdl.data.exam_record.AppDatabase | |||||
| import com.xkl.cdl.data.manager.db.DictionaryManager | |||||
| import io.reactivex.rxjava3.core.Observable | |||||
| import io.reactivex.rxjava3.schedulers.Schedulers | |||||
| class DictionaryViewModel : BaseViewModel() { | |||||
| //courseId 记录为是否为课程查询,课程历史记录为课程,否则为0词典查询 | |||||
| var courseId : Long = 0 | |||||
| //记录状态 | |||||
| companion object { | |||||
| const val STATE_HISTROY = 1 | |||||
| const val STATE_SEARCH = 2 | |||||
| } | |||||
| //适配器 | |||||
| val adapter = DictionaryAdapter(this) | |||||
| //输入框监听 | |||||
| val etSearchLiveData = MutableLiveData<String>() | |||||
| //状态 : 默认历史记录 | |||||
| var detailState = STATE_HISTROY | |||||
| //历史记录集合 | |||||
| val historyList = mutableListOf<DictionaryItem>() | |||||
| //更新详情适配器 false:历史记录 true:联想搜索结果 | |||||
| val updateHistoryAdapterLiveData = MutableLiveData<Boolean>() | |||||
| //历史记录,显示的页数 | |||||
| var histroyShowPage = 1 | |||||
| var searchShowPage = 1 | |||||
| //一页显示的历史记录个数,最多历史记录显示30个 | |||||
| val historyPageSize = 10 | |||||
| //搜索结果,做多匹配显示50个 | |||||
| //是否显示搜索单词的详情 true:显示单条记录的详情 false:搜索显示的为搜索结果的列表详情 | |||||
| var searchItemDetailAble = false | |||||
| //搜索结果 多条为联想结果 单条基本为搜索的详情结果 | |||||
| var searchDetailList = mutableListOf<DictionaryItem>() | |||||
| val handler : Handler = Handler(Looper.getMainLooper()) | |||||
| //记录联想结果中为历史记录的位置 | |||||
| val searchListForHistoryPositionMap = mutableMapOf<Int,Int>() | |||||
| /** | |||||
| * 查询搜索历史 | |||||
| */ | |||||
| fun loadHistory() { | |||||
| Observable.fromCallable { | |||||
| val history = AppDatabase.instance.dictionaryDao().query(courseId) | |||||
| historyList.addAll(history) | |||||
| updateHistoryAdapterLiveData.postValue(false) | |||||
| }.observeOn(Schedulers.from(AppExecutors.io)).subscribe() | |||||
| } | |||||
| /**清空历史记录*/ | |||||
| fun clearHistory() { | |||||
| Observable.fromCallable { | |||||
| historyList.clear() | |||||
| updateHistoryAdapterLiveData.postValue(false) | |||||
| AppDatabase.instance.dictionaryDao().clear(courseId) | |||||
| }.observeOn(Schedulers.from(AppExecutors.io)).subscribe() | |||||
| } | |||||
| /** | |||||
| * 关键字搜索 | |||||
| * @param keyWord String | |||||
| */ | |||||
| fun searchKeyWord(keyWord : String) { | |||||
| handler.removeCallbacksAndMessages(null) | |||||
| handler.postDelayed({ | |||||
| Observable.fromCallable { | |||||
| //清空位置对应信息 | |||||
| searchListForHistoryPositionMap.clear() | |||||
| //联想查询结果 | |||||
| searchDetailList = DictionaryManager.queryKeyWordLikeMatchSimple(keyWord) | |||||
| //搜索记录中获取历史记录位置 需要判断是否有历史记录 | |||||
| if (historyList.isNotEmpty() && searchDetailList.isNotEmpty()) { | |||||
| historyList.forEachIndexed { historyIndex, historyItem -> | |||||
| searchDetailList.forEachIndexed { searchIndex, searchItem -> | |||||
| if (historyItem.word == searchItem.word) { | |||||
| searchItem.inHistory = true | |||||
| searchListForHistoryPositionMap.put(searchIndex, historyIndex) | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| //更新搜索结果 | |||||
| updateHistoryAdapterLiveData.postValue(true) | |||||
| }.observeOn(Schedulers.from(AppExecutors.io)).subscribe() | |||||
| }, 300) | |||||
| } | |||||
| } |
| import com.suliang.common.base.fragment.BaseFragmentVM | import com.suliang.common.base.fragment.BaseFragmentVM | ||||
| import com.suliang.common.extension.click | import com.suliang.common.extension.click | ||||
| import com.xkl.cdl.R | import com.xkl.cdl.R | ||||
| import com.xkl.cdl.adapter.DictionaryAdapter | |||||
| import com.xkl.cdl.databinding.FragmentMyBinding | import com.xkl.cdl.databinding.FragmentMyBinding | ||||
| import com.xkl.cdl.databinding.ItemServiceCenterItemBinding | import com.xkl.cdl.databinding.ItemServiceCenterItemBinding | ||||
| import com.xkl.cdl.databinding.ServiceCenterFragmentBinding | import com.xkl.cdl.databinding.ServiceCenterFragmentBinding | ||||
| import com.xkl.cdl.module.main.MainActivityViewModel | import com.xkl.cdl.module.main.MainActivityViewModel | ||||
| class ServiceCenterFragment : BaseFragmentVM<ServiceCenterFragmentBinding, MainActivityViewModel>() { | |||||
| class ServiceCenterFragment : BaseFragmentVM<ServiceCenterFragmentBinding, MainActivityViewModel>() { | |||||
| companion object { | companion object { | ||||
| @JvmStatic | @JvmStatic | ||||
| fun newInstance() = ServiceCenterFragment() | fun newInstance() = ServiceCenterFragment() | ||||
| override fun initFragment() { | override fun initFragment() { | ||||
| val items = mutableListOf(Item("课程测试", R.drawable.ic_test_course, Color.parseColor("#1A58D4DB")), | val items = mutableListOf(Item("课程测试", R.drawable.ic_test_course, Color.parseColor("#1A58D4DB")), | ||||
| Item("测词汇量", R.drawable.ic_test_count, Color.parseColor("#1AFF8B52")), | |||||
| Item("测试成绩", R.drawable.ic_test_score, Color.parseColor("#1AF26255")), | |||||
| Item("词典", R.drawable.ic_dictionary, Color.parseColor("#1A52CC52"))) | |||||
| Item("测词汇量", R.drawable.ic_test_count, Color.parseColor("#1AFF8B52")), | |||||
| Item("测试成绩", R.drawable.ic_test_score, Color.parseColor("#1AF26255")), | |||||
| Item("词典", R.drawable.ic_dictionary, Color.parseColor("#1A52CC52"))) | |||||
| binding.rv.apply { | binding.rv.apply { | ||||
| layoutManager = GridLayoutManager(requireContext(),2,GridLayoutManager.VERTICAL,false) | |||||
| layoutManager = GridLayoutManager(requireContext(), 2, GridLayoutManager.VERTICAL, false) | |||||
| setHasFixedSize(true) | setHasFixedSize(true) | ||||
| adapter = object : BaseRVAdapter<Item>() { | adapter = object : BaseRVAdapter<Item>() { | ||||
| override fun coverViewHolder(parent : ViewGroup, viewType : Int) : BaseAdapterViewHolder { | override fun coverViewHolder(parent : ViewGroup, viewType : Int) : BaseAdapterViewHolder { | ||||
| return BaseAdapterViewHolder(inflateBinding(parent,R.layout.item_service_center_item)) | |||||
| return BaseAdapterViewHolder(inflateBinding(parent, R.layout.item_service_center_item)) | |||||
| } | } | ||||
| override fun onBindVH(holder : BaseAdapterViewHolder, position : Int) { | override fun onBindVH(holder : BaseAdapterViewHolder, position : Int) { | ||||
| val item = getItem(position) | val item = getItem(position) | ||||
| (holder.binding as ItemServiceCenterItemBinding).apply { | (holder.binding as ItemServiceCenterItemBinding).apply { | ||||
| } | } | ||||
| private fun startTo(position : Int) { | private fun startTo(position : Int) { | ||||
| when(position){ | |||||
| 0 -> startActivity(CourseTestActivity::class.java) | |||||
| 1 -> startActivity(TestVocabularyActivity::class.java) | |||||
| 2 -> startActivity(TestScoreActivity::class.java) | |||||
| 3 -> "" | |||||
| context?.let { | |||||
| when (position) { | |||||
| 0 -> startActivity(CourseTestActivity::class.java) | |||||
| 1 -> startActivity(TestVocabularyActivity::class.java) | |||||
| 2 -> startActivity(TestScoreActivity::class.java) | |||||
| 3 -> DictionaryActivity.newInstance(it) | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| override fun loadData() { | override fun loadData() { | ||||
| } | } | ||||
| override fun initViewModel(): MainActivityViewModel { | |||||
| override fun initViewModel() : MainActivityViewModel { | |||||
| return ViewModelProvider(requireActivity())[MainActivityViewModel::class.java] | return ViewModelProvider(requireActivity())[MainActivityViewModel::class.java] | ||||
| } | } | ||||
| data class Item(val name : String, val icon : Int, val backgroundColor:Int) | |||||
| data class Item(val name : String, val icon : Int, val backgroundColor : Int) | |||||
| } | } |
| if (vm.learnExam.score > 0){ | if (vm.learnExam.score > 0){ | ||||
| groupVocabularyLittle.visibility = View.GONE | groupVocabularyLittle.visibility = View.GONE | ||||
| groupVocabularyNormal.visibility = View.VISIBLE | groupVocabularyNormal.visibility = View.VISIBLE | ||||
| tvVocabularyCount.text = "${vm.learnExam.score}" | |||||
| tvVocabularyCount.text = "${vm.learnExam.score.toInt()}" | |||||
| ratingBar.setStar(vm.learnExam.score/20) | ratingBar.setStar(vm.learnExam.score/20) | ||||
| tvVocabularyCoverRateStage.setHtml("覆盖率<font color=\'#F7874F\'>${vm.learnExam.coverRate}%</font>\t\t(${vm.learnExam.stage})") | tvVocabularyCoverRateStage.setHtml("覆盖率<font color=\'#F7874F\'>${vm.learnExam.coverRate}%</font>\t\t(${vm.learnExam.stage})") | ||||
| }else{ | }else{ |
| import android.view.ViewGroup | import android.view.ViewGroup | ||||
| import androidx.lifecycle.ViewModelProvider | import androidx.lifecycle.ViewModelProvider | ||||
| import androidx.recyclerview.widget.LinearLayoutManager | import androidx.recyclerview.widget.LinearLayoutManager | ||||
| import com.jeremyliao.liveeventbus.LiveEventBus | |||||
| import com.suliang.common.AppConfig | |||||
| import com.suliang.common.base.activity.BaseActivityVM | import com.suliang.common.base.activity.BaseActivityVM | ||||
| import com.suliang.common.base.adapter.BaseAdapterViewHolder | import com.suliang.common.base.adapter.BaseAdapterViewHolder | ||||
| import com.suliang.common.base.adapter.BaseRVAdapter | import com.suliang.common.base.adapter.BaseRVAdapter | ||||
| import com.suliang.common.extension.click | import com.suliang.common.extension.click | ||||
| import com.xkl.cdl.R | import com.xkl.cdl.R | ||||
| import com.xkl.cdl.data.AppConstants | |||||
| import com.xkl.cdl.data.DataTransferHolder | |||||
| import com.xkl.cdl.data.bean.VocabularyItem | import com.xkl.cdl.data.bean.VocabularyItem | ||||
| import com.xkl.cdl.data.bean.intentdata.ExamData | |||||
| import com.xkl.cdl.databinding.ActivityTestVocabularyBinding | import com.xkl.cdl.databinding.ActivityTestVocabularyBinding | ||||
| import com.xkl.cdl.databinding.ItemVocabularyLevelBinding | import com.xkl.cdl.databinding.ItemVocabularyLevelBinding | ||||
| import com.xkl.cdl.module.learn.LearnExamActivity | |||||
| class TestVocabularyActivity : BaseActivityVM<ActivityTestVocabularyBinding, TestVocabularyViewModle>() { | class TestVocabularyActivity : BaseActivityVM<ActivityTestVocabularyBinding, TestVocabularyViewModle>() { | ||||
| return BaseAdapterViewHolder(inflateBinding(parent, R.layout.item_vocabulary_level)) | return BaseAdapterViewHolder(inflateBinding(parent, R.layout.item_vocabulary_level)) | ||||
| } | } | ||||
| override fun onBindVH(holder : BaseAdapterViewHolder, position : Int) { | override fun onBindVH(holder : BaseAdapterViewHolder, position : Int) { | ||||
| getItem(position).let { | |||||
| getItem(position).let { item -> | |||||
| (holder.binding as ItemVocabularyLevelBinding).run { | (holder.binding as ItemVocabularyLevelBinding).run { | ||||
| iv.setImageResource(it.icon) | |||||
| tvLevel.text = it.level | |||||
| tvLevelE.text = it.level_e | |||||
| root.click { | |||||
| // vm.queryVocabulary(it) | |||||
| iv.setImageResource(item.icon) | |||||
| tvLevel.text = item.level | |||||
| tvLevelE.text = item.level_e | |||||
| root.click { v -> | |||||
| startTest(item) | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| override fun loadData() { | override fun loadData() { | ||||
| LiveEventBus.get<VocabularyItem>("vocabulary_test").observe(this){ | |||||
| it?.let { | |||||
| startTest(it) | |||||
| } | |||||
| } | |||||
| } | } | ||||
| /** | |||||
| * 开始测试 | |||||
| * @param item VocabularyItem | |||||
| */ | |||||
| private fun startTest(item:VocabularyItem){ | |||||
| vm.queryVocabularyTestData(item).observe(this@TestVocabularyActivity){ list -> | |||||
| val examData = ExamData(AppConstants.SUBJECT_ENGLISH,AppConstants.TEST_TYPE_NORMAL,"词汇量测试","词汇量测试:${item.level}").apply { | |||||
| testData = list | |||||
| vocabularyItem = item | |||||
| } | |||||
| DataTransferHolder.instance.putData(key = AppConfig.INTENT_1,examData) | |||||
| startActivity(LearnExamActivity::class.java) | |||||
| } | |||||
| } | |||||
| } | } |
| import com.xkl.cdl.data.bean.VocabularyItem | import com.xkl.cdl.data.bean.VocabularyItem | ||||
| import com.xkl.cdl.data.bean.course.ExamBean | import com.xkl.cdl.data.bean.course.ExamBean | ||||
| import com.xkl.cdl.data.manager.db.DBCourseManager | import com.xkl.cdl.data.manager.db.DBCourseManager | ||||
| import com.xkl.cdl.data.manager.db.VocabularyManager | |||||
| import io.reactivex.rxjava3.core.Observable | import io.reactivex.rxjava3.core.Observable | ||||
| /** | /** | ||||
| * Describe: | * Describe: | ||||
| */ | */ | ||||
| class TestVocabularyViewModle : BaseViewModel() { | class TestVocabularyViewModle : BaseViewModel() { | ||||
| // VOCABULARY":"{\"list\": | |||||
| // [{\"id\":10,\"title\":\"综合测试\",\"title_en\":\"Comprehensive test\",\"vocabulary\":13000,}, | |||||
| // {\"id\":2,\"title\":\"小学\",\"title_en\":\"Primary school\",\"vocabulary\":1000,}, | |||||
| // {\"id\":3,\"title\":\"初中\",\"title_en\":\"Junior high school\",\"vocabulary\":2100,}, | |||||
| // {\"id\":4,\"title\":\"高中\",\"title_en\":\"Senior high school\",\"vocabulary\":3500,}, | |||||
| // {\"id\":5,\"title\":\"大学四级\",\"title_en\":\"College English Test Band 4\",\"vocabulary\":4200,}, | |||||
| // {\"id\":6,\"title\":\"大学六级\",\"title_en\":\"College English Test Band 6\",\"vocabulary\":6000,}, | |||||
| // {\"id\":7,\"title\":\"雅思\",\"title_en\":\"Lelts\",\"vocabulary\":7500,}, | |||||
| // {\"id\":8,\"title\":\"托福\",\"title_en\":\"Toefl\",\"vocabulary\":8000,], | |||||
| val data = mutableListOf( | val data = mutableListOf( | ||||
| VocabularyItem(R.mipmap.ic_comprehensive_test,"综合测试",""), | |||||
| VocabularyItem(R.mipmap.ic_primary_school,"小学",""), | |||||
| VocabularyItem(R.mipmap.ic_junior_school,"初中",""), | |||||
| VocabularyItem(R.mipmap.ic_high_school,"高中",""), | |||||
| VocabularyItem(R.mipmap.ic_university_4,"大学四级",""), | |||||
| VocabularyItem(R.mipmap.ic_university_6,"大学六级",""), | |||||
| VocabularyItem(R.mipmap.ic_lelts,"雅思",""), | |||||
| VocabularyItem(R.mipmap.ic_toefl,"托福","") ) | |||||
| VocabularyItem(R.mipmap.ic_comprehensive_test,"综合测试","Comprehensive test",10,13000), | |||||
| VocabularyItem(R.mipmap.ic_primary_school,"小学","Primary school",2,1000), | |||||
| VocabularyItem(R.mipmap.ic_junior_school,"初中","Junior high school",3,2100), | |||||
| VocabularyItem(R.mipmap.ic_high_school,"高中","Senior high school",4,3500), | |||||
| VocabularyItem(R.mipmap.ic_university_4,"大学四级","College English Test Band 4",5,4200), | |||||
| VocabularyItem(R.mipmap.ic_university_6,"大学六级","College English Test Band 6",6,6000), | |||||
| VocabularyItem(R.mipmap.ic_lelts,"雅思","Lelts",7,7500), | |||||
| VocabularyItem(R.mipmap.ic_toefl,"托福","Toefl",8,8000) ) | |||||
| /** | /** | ||||
| * 查询测试数据 | * 查询测试数据 | ||||
| fun queryVocabularyTestData(item : VocabularyItem) : MutableLiveData<List<ExamBean>> { | fun queryVocabularyTestData(item : VocabularyItem) : MutableLiveData<List<ExamBean>> { | ||||
| val result = MutableLiveData<List<ExamBean>>() | val result = MutableLiveData<List<ExamBean>>() | ||||
| Observable.create<List<ExamBean>> { | Observable.create<List<ExamBean>> { | ||||
| it.onNext(DBCourseManager.queryLearnTest(dbControlBase, testType, lesson)) | |||||
| it.onNext(VocabularyManager.queryVocabularyTestData(item)) | |||||
| it.onComplete() | it.onComplete() | ||||
| }.compose(diskIo2Main()).subscribe({ | }.compose(diskIo2Main()).subscribe({ | ||||
| result.value = it | result.value = it |
| //复制词典 和 词汇量测试 | //复制词典 和 词汇量测试 | ||||
| val dictionary = FilePathManager.getDictionaryDbPath() | val dictionary = FilePathManager.getDictionaryDbPath() | ||||
| if (!dictionary.exists()) { | if (!dictionary.exists()) { | ||||
| val copyAssetResult = FileUtil.copyAsset("dictionary.db", dictionary) | |||||
| FileUtil.copyAsset("dictionary.db", dictionary) | |||||
| } | } | ||||
| val vocabulary = FilePathManager.getVocabularyDbPath() | val vocabulary = FilePathManager.getVocabularyDbPath() | ||||
| if (!dictionary.exists()) { | |||||
| val copyAssetResult = FileUtil.copyAsset("vocabulary.db", vocabulary) | |||||
| if (!vocabulary.exists()) { | |||||
| FileUtil.copyAsset("vocabulary.db", vocabulary) | |||||
| } | } | ||||
| // TODO: 2022/3/22 读取当前app绑定的课程数据, | // TODO: 2022/3/22 读取当前app绑定的课程数据, |
| <?xml version="1.0" encoding="utf-8"?> | |||||
| <layout xmlns:android="http://schemas.android.com/apk/res/android" | |||||
| xmlns:app="http://schemas.android.com/apk/res-auto" | |||||
| xmlns:tools="http://schemas.android.com/tools"> | |||||
| <data> | |||||
| <variable | |||||
| name="vm" | |||||
| type="com.xkl.cdl.module.m_service_center.DictionaryViewModel" /> | |||||
| </data> | |||||
| <androidx.constraintlayout.widget.ConstraintLayout | |||||
| android:layout_width="match_parent" | |||||
| android:layout_height="match_parent" | |||||
| tools:context=".module.m_service_center.DictionaryActivity" | |||||
| android:background="@color/white"> | |||||
| <com.suliang.common.widget.TitleBar | |||||
| android:id="@+id/title_bar" | |||||
| android:layout_width="match_parent" | |||||
| android:layout_height="@dimen/title_bar_height" | |||||
| app:layout_constraintTop_toTopOf="parent" /> | |||||
| <com.google.android.material.imageview.ShapeableImageView | |||||
| android:id="@+id/iv" | |||||
| android:layout_width="72dp" | |||||
| android:layout_height="72dp" | |||||
| android:src="@drawable/ic_dictionary" | |||||
| android:background="#1A58D4DB" | |||||
| app:shapeAppearance="@style/CircleStyle" | |||||
| app:contentPadding="@dimen/global_spacing" | |||||
| app:layout_constraintStart_toStartOf="parent" | |||||
| app:layout_constraintEnd_toEndOf="parent" | |||||
| app:layout_constraintTop_toBottomOf="@+id/title_bar" /> | |||||
| <TextView | |||||
| android:id="@+id/tv_title" | |||||
| android:layout_width="wrap_content" | |||||
| android:layout_height="wrap_content" | |||||
| android:text="@string/xkl_dictionary" | |||||
| app:layout_constraintTop_toBottomOf="@+id/iv" | |||||
| app:layout_constraintStart_toStartOf="parent" | |||||
| app:layout_constraintEnd_toEndOf="parent" | |||||
| android:textSize="22dp" | |||||
| android:textColor="@color/main_text_color" | |||||
| android:textStyle="bold" | |||||
| android:layout_marginTop="12dp" /> | |||||
| <com.suliang.common.widget.InputSearchEditText | |||||
| android:id="@+id/et_search" | |||||
| android:layout_width="0dp" | |||||
| android:layout_height="40dp" | |||||
| app:layout_constraintTop_toBottomOf="@+id/tv_title" | |||||
| app:layout_constraintStart_toStartOf="parent" | |||||
| app:layout_constraintEnd_toEndOf="parent" | |||||
| android:layout_marginTop="24dp" | |||||
| android:layout_marginStart="@dimen/global_spacing" | |||||
| android:layout_marginEnd="@dimen/global_spacing" | |||||
| android:background="@drawable/shape_rounder_8_stroke_gray1" | |||||
| android:paddingStart="@dimen/global_spacing" | |||||
| android:paddingEnd="@dimen/global_spacing" | |||||
| android:drawablePadding="4dp" | |||||
| android:textSize="@dimen/smallSize" | |||||
| android:gravity="center_vertical" | |||||
| android:hint="输入你要搜索的内容…" | |||||
| android:text="@{vm.etSearchLiveData}"/> | |||||
| <androidx.constraintlayout.widget.ConstraintLayout | |||||
| android:id="@+id/layout_detail" | |||||
| android:layout_width="0dp" | |||||
| android:layout_height="wrap_content" | |||||
| app:layout_constraintStart_toStartOf="parent" | |||||
| app:layout_constraintEnd_toEndOf="parent" | |||||
| app:layout_constraintTop_toBottomOf="@+id/et_search" | |||||
| android:layout_marginTop="12dp" | |||||
| android:background="@drawable/shape_rounder_8_solid_green1" | |||||
| android:backgroundTint="@color/gray_3" | |||||
| android:layout_marginStart="@dimen/global_spacing" | |||||
| android:layout_marginEnd="@dimen/global_spacing"> | |||||
| <View | |||||
| android:id="@+id/v_line" | |||||
| android:layout_width="match_parent" | |||||
| android:layout_height="@dimen/line_height" | |||||
| android:background="@color/gray_1" | |||||
| app:layout_constraintTop_toTopOf="parent" | |||||
| android:layout_marginTop="40dp" /> | |||||
| <TextView | |||||
| android:id="@+id/tv_history_title" | |||||
| android:layout_width="wrap_content" | |||||
| android:layout_height="wrap_content" | |||||
| android:textSize="@dimen/smallSize" | |||||
| android:textColor="@color/gray_2" | |||||
| app:layout_constraintTop_toTopOf="parent" | |||||
| app:layout_constraintBottom_toTopOf="@+id/v_line" | |||||
| app:layout_constraintStart_toStartOf="parent" | |||||
| android:text="历史搜索记录" | |||||
| android:layout_marginStart="@dimen/global_spacing" /> | |||||
| <ImageView | |||||
| android:id="@+id/iv_delete" | |||||
| android:layout_width="wrap_content" | |||||
| android:layout_height="0dp" | |||||
| app:layout_constraintEnd_toEndOf="parent" | |||||
| app:layout_constraintTop_toTopOf="parent" | |||||
| app:layout_constraintBottom_toTopOf="@+id/v_line" | |||||
| android:paddingEnd="8dp" | |||||
| android:paddingStart="8dp" | |||||
| android:layout_marginEnd="4dp" | |||||
| android:src="@drawable/ic_rubbish" /> | |||||
| <androidx.recyclerview.widget.RecyclerView | |||||
| android:id="@+id/rv" | |||||
| android:layout_width="match_parent" | |||||
| android:layout_height="wrap_content" | |||||
| app:layout_constraintTop_toBottomOf="@+id/v_line" /> | |||||
| <TextView | |||||
| android:id="@+id/tv_see_more" | |||||
| android:layout_width="wrap_content" | |||||
| android:layout_height="40dp" | |||||
| android:textSize="@dimen/smallerSize" | |||||
| android:textColor="@color/gray_2" | |||||
| app:layout_constraintTop_toBottomOf="@+id/rv" | |||||
| app:layout_constraintStart_toStartOf="parent" | |||||
| app:layout_constraintEnd_toEndOf="parent" | |||||
| android:text="查看更多" | |||||
| android:drawableEnd="@drawable/ic_down" | |||||
| android:drawableTint="@color/gray_2" | |||||
| android:gravity="center_vertical" | |||||
| android:drawablePadding="4dp" /> | |||||
| </androidx.constraintlayout.widget.ConstraintLayout> | |||||
| </androidx.constraintlayout.widget.ConstraintLayout> | |||||
| </layout> |
| app:layout_constraintEnd_toEndOf="parent" | app:layout_constraintEnd_toEndOf="parent" | ||||
| app:layout_constraintStart_toStartOf="parent" | app:layout_constraintStart_toStartOf="parent" | ||||
| app:layout_constraintTop_toBottomOf="@+id/title_bar" | app:layout_constraintTop_toBottomOf="@+id/title_bar" | ||||
| android:visibility="gone" | |||||
| tools:visibility="visible" | tools:visibility="visible" | ||||
| > | > | ||||
| app:layout_constraintStart_toStartOf="parent" | app:layout_constraintStart_toStartOf="parent" | ||||
| app:layout_constraintTop_toBottomOf="@+id/title_bar" | app:layout_constraintTop_toBottomOf="@+id/title_bar" | ||||
| app:layout_constraintVertical_bias="0" | app:layout_constraintVertical_bias="0" | ||||
| android:visibility="gone" | |||||
| tools:visibility="gone"> | tools:visibility="gone"> | ||||
| <androidx.constraintlayout.widget.ConstraintLayout | <androidx.constraintlayout.widget.ConstraintLayout |
| android:layout_height="@dimen/title_bar_height" | android:layout_height="@dimen/title_bar_height" | ||||
| app:titleTextValue="@string/test_vocabulary"/> | app:titleTextValue="@string/test_vocabulary"/> | ||||
| <View | |||||
| android:layout_width="match_parent" | |||||
| android:layout_height="@dimen/line_height" | |||||
| android:background="@color/gray_1"/> | |||||
| <TextView | <TextView | ||||
| android:layout_width="wrap_content" | android:layout_width="wrap_content" |
| <?xml version="1.0" encoding="utf-8"?> | |||||
| <layout xmlns:android="http://schemas.android.com/apk/res/android" | |||||
| xmlns:app="http://schemas.android.com/apk/res-auto" | |||||
| xmlns:tools="http://schemas.android.com/tools"> | |||||
| <data> | |||||
| </data> | |||||
| <LinearLayout | |||||
| android:layout_width="300dp" | |||||
| android:layout_height="wrap_content" | |||||
| android:orientation="vertical"> | |||||
| <androidx.constraintlayout.widget.ConstraintLayout | |||||
| android:id="@+id/layout_vocabulary" | |||||
| android:layout_width="match_parent" | |||||
| android:layout_height="wrap_content" | |||||
| android:background="@drawable/shape_rounder_12_white"> | |||||
| <TextView | |||||
| android:id="@+id/tv_vocabulary" | |||||
| android:layout_width="wrap_content" | |||||
| android:layout_height="wrap_content" | |||||
| android:layout_marginTop="32dp" | |||||
| tools:text="学考乐词汇量测试:小学" | |||||
| android:textColor="@color/main_text_color" | |||||
| android:textSize="@dimen/smallSize" | |||||
| app:layout_constraintEnd_toEndOf="parent" | |||||
| app:layout_constraintStart_toStartOf="parent" | |||||
| app:layout_constraintTop_toTopOf="parent" | |||||
| android:textStyle="bold"/> | |||||
| <TextView | |||||
| android:id="@+id/tv_vocabulary_test_time_flag" | |||||
| android:layout_width="wrap_content" | |||||
| android:layout_height="wrap_content" | |||||
| android:layout_marginTop="8dp" | |||||
| android:text="@string/test_time_1" | |||||
| android:textColor="@color/gray_2" | |||||
| android:textSize="@dimen/smallSize" | |||||
| app:layout_constraintEnd_toStartOf="@+id/tv_vocabulary_test_time" | |||||
| app:layout_constraintStart_toStartOf="parent" | |||||
| app:layout_constraintTop_toBottomOf="@id/tv_vocabulary" | |||||
| app:layout_constraintHorizontal_chainStyle="packed"/> | |||||
| <TextView | |||||
| android:id="@+id/tv_vocabulary_test_time" | |||||
| android:layout_width="wrap_content" | |||||
| android:layout_height="wrap_content" | |||||
| android:textColor="@color/gray_2" | |||||
| android:textSize="@dimen/smallSize" | |||||
| app:layout_constraintBaseline_toBaselineOf="@+id/tv_vocabulary_test_time_flag" | |||||
| app:layout_constraintEnd_toEndOf="parent" | |||||
| app:layout_constraintStart_toEndOf="@+id/tv_vocabulary_test_time_flag" | |||||
| tools:text="时间" /> | |||||
| <TextView | |||||
| android:id="@+id/tv_vocabulary_count_flag" | |||||
| android:layout_width="wrap_content" | |||||
| android:layout_height="wrap_content" | |||||
| android:layout_marginTop="24dp" | |||||
| android:text="@string/vocabulary" | |||||
| android:textColor="@color/gray_2" | |||||
| android:textSize="@dimen/smallSize" | |||||
| app:layout_constraintEnd_toEndOf="parent" | |||||
| app:layout_constraintStart_toStartOf="parent" | |||||
| app:layout_constraintTop_toBottomOf="@+id/tv_vocabulary_test_time_flag" /> | |||||
| <TextView | |||||
| android:id="@+id/tv_vocabulary_count" | |||||
| android:layout_width="wrap_content" | |||||
| android:layout_height="wrap_content" | |||||
| android:textColor="@color/red_1" | |||||
| android:textSize="60dp" | |||||
| android:textStyle="bold" | |||||
| app:layout_constraintEnd_toEndOf="parent" | |||||
| app:layout_constraintStart_toStartOf="parent" | |||||
| app:layout_constraintTop_toBottomOf="@+id/tv_vocabulary_count_flag" | |||||
| tools:text="1000" /> | |||||
| <com.xl.ratingbar.MyRatingBar | |||||
| android:id="@+id/rating_bar" | |||||
| android:layout_width="wrap_content" | |||||
| android:layout_height="24dp" | |||||
| android:layout_marginTop="12dp" | |||||
| android:clickable="false" | |||||
| android:gravity="center" | |||||
| app:layout_constraintEnd_toEndOf="parent" | |||||
| app:layout_constraintStart_toStartOf="parent" | |||||
| app:layout_constraintTop_toBottomOf="@+id/tv_vocabulary_count" | |||||
| app:starEmpty="@drawable/ic_star" | |||||
| app:starFill="@drawable/ic_star_1" | |||||
| app:starHalf="@drawable/ic_star_1" | |||||
| app:starCount = "5" | |||||
| tools:starNum = "2" | |||||
| app:starImageWidth="24dp" | |||||
| app:starImageHeight="24dp"/> | |||||
| <TextView | |||||
| android:id="@+id/tv_vocabulary_cover_rate_stage" | |||||
| android:layout_width="wrap_content" | |||||
| android:layout_height="wrap_content" | |||||
| android:layout_marginTop="8dp" | |||||
| android:textColor="@color/main_text_color" | |||||
| android:textSize="@dimen/normalSize" | |||||
| app:layout_constraintEnd_toEndOf="parent" | |||||
| app:layout_constraintStart_toStartOf="parent" | |||||
| app:layout_constraintTop_toBottomOf="@+id/rating_bar" | |||||
| tools:text="覆盖率67%(高中)"/> | |||||
| <TextView | |||||
| android:id="@+id/tv_vocabulary_little" | |||||
| android:layout_width="wrap_content" | |||||
| android:layout_height="wrap_content" | |||||
| android:layout_marginTop="@dimen/global_spacing" | |||||
| android:text="词汇量较少,建议再测一次" | |||||
| android:textColor="@color/main_text_color" | |||||
| android:textSize="@dimen/normalSize" | |||||
| android:drawableTop="@mipmap/cry" | |||||
| android:drawablePadding="12dp" | |||||
| app:layout_constraintEnd_toEndOf="parent" | |||||
| app:layout_constraintStart_toStartOf="parent" | |||||
| app:layout_constraintTop_toBottomOf="@id/tv_vocabulary_test_time" | |||||
| android:visibility="gone" | |||||
| tools:visibility="gone"/> | |||||
| <androidx.constraintlayout.widget.Group | |||||
| android:id="@+id/group_vocabulary_normal" | |||||
| android:layout_width="wrap_content" | |||||
| android:layout_height="wrap_content" | |||||
| app:constraint_referenced_ids="tv_vocabulary_count_flag,tv_vocabulary_count,rating_bar,tv_vocabulary_cover_rate_stage" | |||||
| android:visibility="gone" | |||||
| tools:visibility="visible"/> | |||||
| <androidx.constraintlayout.widget.Barrier | |||||
| android:id="@+id/barrier" | |||||
| android:layout_width="wrap_content" | |||||
| android:layout_height="wrap_content" | |||||
| app:barrierDirection="bottom" | |||||
| app:barrierMargin="@dimen/smallerSize" | |||||
| app:constraint_referenced_ids="tv_vocabulary_cover_rate_stage,tv_vocabulary_little"/> | |||||
| <View | |||||
| android:id="@+id/bottom_top_line" | |||||
| android:layout_width="wrap_content" | |||||
| android:layout_height="1dp" | |||||
| app:layout_constraintEnd_toEndOf="parent" | |||||
| app:layout_constraintStart_toStartOf="parent" | |||||
| android:background="@color/gray_3" | |||||
| app:layout_constraintTop_toBottomOf="@+id/barrier" | |||||
| android:layout_marginTop="@dimen/global_spacing"/> | |||||
| <TextView | |||||
| android:id="@+id/tv_right" | |||||
| android:layout_width="0dp" | |||||
| android:layout_height="40dp" | |||||
| android:gravity="center" | |||||
| android:text="@string/test_again" | |||||
| android:textColor="@color/theme_color" | |||||
| android:textSize="@dimen/smallSize" | |||||
| app:layout_constraintEnd_toEndOf="parent" | |||||
| app:layout_constraintTop_toBottomOf="@+id/bottom_top_line" | |||||
| app:layout_constraintStart_toEndOf="@id/vSplit" | |||||
| /> | |||||
| <View | |||||
| android:id="@+id/vSplit" | |||||
| android:layout_width="1dp" | |||||
| android:layout_height="0dp" | |||||
| app:layout_constraintEnd_toStartOf="@+id/tv_right" | |||||
| app:layout_constraintStart_toEndOf="@+id/tv_left" | |||||
| android:background="@color/gray_3" | |||||
| app:layout_constraintTop_toTopOf="@+id/tv_right" | |||||
| app:layout_constraintBottom_toBottomOf="@+id/tv_right"/> | |||||
| <!--左边按钮--> | |||||
| <TextView | |||||
| android:id="@+id/tv_left" | |||||
| android:layout_width="0dp" | |||||
| android:layout_height="40dp" | |||||
| android:gravity="center" | |||||
| android:text="@string/done" | |||||
| android:textColor="@color/main_text_color" | |||||
| android:textSize="@dimen/smallSize" | |||||
| app:layout_constraintStart_toStartOf="parent" | |||||
| app:layout_constraintEnd_toStartOf="@+id/vSplit" | |||||
| app:layout_constraintTop_toTopOf="@+id/vSplit" | |||||
| app:layout_constraintBottom_toBottomOf="@+id/vSplit" | |||||
| /> | |||||
| </androidx.constraintlayout.widget.ConstraintLayout> | |||||
| </LinearLayout> | |||||
| </layout> |
| <?xml version="1.0" encoding="utf-8"?> | |||||
| <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" | |||||
| android:layout_width="match_parent" | |||||
| android:layout_height="wrap_content" | |||||
| xmlns:app="http://schemas.android.com/apk/res-auto" | |||||
| xmlns:tools="http://schemas.android.com/tools"> | |||||
| <TextView | |||||
| android:id="@+id/tv_word" | |||||
| android:layout_width="0dp" | |||||
| android:layout_height="wrap_content" | |||||
| android:layout_marginStart="@dimen/global_spacing" | |||||
| android:layout_marginTop="16dp" | |||||
| android:layout_marginEnd="@dimen/global_spacing" | |||||
| android:text="jaapjaapjaap" | |||||
| android:textColor="@color/main_text_color" | |||||
| android:textSize="22dp" | |||||
| android:textStyle="bold" | |||||
| app:layout_constraintEnd_toEndOf="parent" | |||||
| app:layout_constraintHorizontal_bias="0.0" | |||||
| app:layout_constraintStart_toStartOf="parent" | |||||
| app:layout_constraintTop_toTopOf="parent" /> | |||||
| <TextView | |||||
| android:id="@+id/tv_phonetic" | |||||
| android:layout_width="wrap_content" | |||||
| android:layout_height="wrap_content" | |||||
| android:gravity="center_vertical" | |||||
| android:textColor="@color/gray_2" | |||||
| android:textSize="@dimen/smallerSize" | |||||
| app:layout_constraintEnd_toEndOf="@+id/tv_word" | |||||
| app:layout_constraintStart_toStartOf="@+id/tv_word" | |||||
| app:layout_constraintTop_toBottomOf="@+id/tv_word" | |||||
| tools:text="[gud:bai] " | |||||
| app:layout_constraintHorizontal_bias="0" | |||||
| android:layout_marginTop="8dp"/> | |||||
| <androidx.recyclerview.widget.RecyclerView | |||||
| android:id="@+id/recyclerView" | |||||
| android:layout_width="match_parent" | |||||
| android:layout_height="wrap_content" | |||||
| app:layout_constraintStart_toStartOf="parent" | |||||
| app:layout_constraintTop_toBottomOf="@+id/tv_phonetic" | |||||
| /> | |||||
| </androidx.constraintlayout.widget.ConstraintLayout> |
| <?xml version="1.0" encoding="utf-8"?> | |||||
| <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" | |||||
| android:layout_width="match_parent" | |||||
| android:layout_height="wrap_content" | |||||
| xmlns:tools="http://schemas.android.com/tools" | |||||
| xmlns:app="http://schemas.android.com/apk/res-auto" | |||||
| android:orientation="horizontal" | |||||
| android:gravity="center_vertical"> | |||||
| <TextView | |||||
| android:id="@+id/tv_word" | |||||
| android:layout_width="wrap_content" | |||||
| android:layout_height="wrap_content" | |||||
| android:singleLine="true" | |||||
| tools:text="introduction" | |||||
| android:textSize="@dimen/normalSize" | |||||
| android:textColor="@color/main_text_color" | |||||
| android:layout_marginTop="8dp" | |||||
| app:layout_constraintTop_toTopOf="parent" | |||||
| app:layout_constraintStart_toEndOf="@+id/iv_horuns" | |||||
| android:gravity="center_vertical" | |||||
| /> | |||||
| <ImageView | |||||
| android:id="@+id/iv_horuns" | |||||
| android:layout_width="wrap_content" | |||||
| android:layout_height="wrap_content" | |||||
| tools:src="@drawable/ic_horuns" | |||||
| android:layout_marginStart="@dimen/global_spacing" | |||||
| android:layout_marginEnd="8dp" | |||||
| app:layout_constraintTop_toTopOf="@+id/tv_word" | |||||
| app:layout_constraintBottom_toBottomOf="@+id/tv_word" | |||||
| app:layout_constraintStart_toStartOf="parent" | |||||
| android:paddingRight="4dp"/> | |||||
| <TextView | |||||
| android:id="@+id/tv_value" | |||||
| android:layout_width="wrap_content" | |||||
| android:layout_height="wrap_content" | |||||
| android:layout_marginEnd="@dimen/global_spacing" | |||||
| android:layout_marginStart="@dimen/global_spacing" | |||||
| android:textSize="@dimen/smallerSize" | |||||
| android:textColor="@color/gray_2" | |||||
| tools:text="简介" | |||||
| app:layout_constrainedWidth="true" | |||||
| app:layout_constraintHorizontal_bias="0" | |||||
| app:layout_constraintStart_toStartOf="parent" | |||||
| app:layout_constraintEnd_toEndOf="parent" | |||||
| app:layout_constraintTop_toBottomOf="@+id/tv_word" | |||||
| app:layout_constraintBottom_toBottomOf="parent" | |||||
| android:layout_marginBottom="8dp" | |||||
| android:layout_marginTop="4dp"/> | |||||
| </androidx.constraintlayout.widget.ConstraintLayout> |
| <?xml version="1.0" encoding="utf-8"?> | |||||
| <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" | |||||
| android:layout_width="match_parent" | |||||
| android:layout_height="wrap_content" | |||||
| xmlns:app="http://schemas.android.com/apk/res-auto" | |||||
| xmlns:tools="http://schemas.android.com/tools"> | |||||
| <TextView | |||||
| android:id="@+id/tv_word" | |||||
| android:layout_width="0dp" | |||||
| android:layout_height="wrap_content" | |||||
| android:layout_marginStart="@dimen/global_spacing" | |||||
| android:layout_marginTop="16dp" | |||||
| android:layout_marginEnd="@dimen/global_spacing" | |||||
| android:text="jaapjaapjaap" | |||||
| android:textColor="@color/main_text_color" | |||||
| android:textSize="22dp" | |||||
| android:textStyle="bold" | |||||
| app:layout_constraintEnd_toEndOf="parent" | |||||
| app:layout_constraintHorizontal_bias="0.0" | |||||
| app:layout_constraintStart_toStartOf="parent" | |||||
| app:layout_constraintTop_toTopOf="parent" /> | |||||
| <com.suliang.common.widget.TagLinearLayout | |||||
| android:id="@+id/layout_phonetic" | |||||
| android:layout_width="0dp" | |||||
| android:layout_height="wrap_content" | |||||
| app:item_horizontal_space="16dp" | |||||
| app:layout_constraintEnd_toEndOf="parent" | |||||
| app:layout_constraintStart_toStartOf="@+id/tv_word" | |||||
| app:layout_constraintTop_toBottomOf="@+id/tv_word" | |||||
| android:layout_marginTop="8dp" | |||||
| android:layout_marginEnd="@dimen/global_spacing"> | |||||
| <TextView | |||||
| android:id="@+id/tv_phonetic_uk" | |||||
| android:layout_width="wrap_content" | |||||
| android:layout_height="wrap_content" | |||||
| android:drawableEnd="@drawable/ic_horuns" | |||||
| android:gravity="center" | |||||
| android:textColor="@color/gray_2" | |||||
| android:textSize="@dimen/smallerSize" | |||||
| tools:text="英 [gud:bai] " /> | |||||
| <TextView | |||||
| android:id="@+id/tv_phonetic_us" | |||||
| android:layout_width="wrap_content" | |||||
| android:layout_height="wrap_content" | |||||
| android:drawableEnd="@drawable/ic_horuns" | |||||
| android:gravity="center" | |||||
| android:textColor="@color/gray_2" | |||||
| android:textSize="@dimen/smallerSize" | |||||
| tools:text="美 [gud:bai] " /> | |||||
| </com.suliang.common.widget.TagLinearLayout> | |||||
| <TextView | |||||
| android:id="@+id/tv_explain" | |||||
| android:layout_width="0dp" | |||||
| android:layout_height="wrap_content" | |||||
| android:layout_marginTop="10dp" | |||||
| android:layout_marginEnd="@dimen/global_spacing" | |||||
| android:textColor="@color/main_text_color" | |||||
| android:textSize="@dimen/smallSize" | |||||
| app:layout_constraintEnd_toEndOf="parent" | |||||
| app:layout_constraintStart_toStartOf="@+id/tv_word" | |||||
| app:layout_constraintTop_toBottomOf="@+id/layout_phonetic" | |||||
| app:layout_constraintHorizontal_bias="0" | |||||
| android:textStyle="bold" | |||||
| tools:text="基本释义"/> | |||||
| <TextView | |||||
| android:id="@+id/tv_expand_explain" | |||||
| android:layout_width="0dp" | |||||
| android:layout_height="wrap_content" | |||||
| android:layout_marginTop="2dp" | |||||
| android:textColor="@color/gray_2" | |||||
| android:textSize="@dimen/smallSize" | |||||
| app:layout_constraintEnd_toEndOf="@+id/tv_word" | |||||
| app:layout_constraintStart_toStartOf="@+id/tv_word" | |||||
| app:layout_constraintTop_toBottomOf="@+id/tv_explain" | |||||
| tools:text="扩展释义>"/> | |||||
| <include | |||||
| android:id="@+id/inc_word_detail" | |||||
| android:layout_width="0dp" | |||||
| android:layout_height="wrap_content" | |||||
| layout="@layout/inc_word_detail" | |||||
| app:layout_constraintTop_toBottomOf="@+id/tv_expand_explain" | |||||
| app:layout_constraintStart_toStartOf="parent" | |||||
| app:layout_constraintEnd_toEndOf="parent"/> | |||||
| </androidx.constraintlayout.widget.ConstraintLayout> |
| <?xml version="1.0" encoding="utf-8"?> | |||||
| <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" | |||||
| android:layout_width="match_parent" | |||||
| android:layout_height="32dp" | |||||
| xmlns:tools="http://schemas.android.com/tools" | |||||
| android:orientation="horizontal" | |||||
| android:gravity="center_vertical"> | |||||
| <ImageView | |||||
| android:id="@+id/iv" | |||||
| android:layout_width="16dp" | |||||
| android:layout_height="16dp" | |||||
| tools:src="@drawable/ic_clock" | |||||
| android:layout_marginStart="@dimen/global_spacing" | |||||
| android:layout_marginEnd="8dp"/> | |||||
| <TextView | |||||
| android:id="@+id/tv_word" | |||||
| android:layout_width="wrap_content" | |||||
| android:layout_height="wrap_content" | |||||
| android:singleLine="true" | |||||
| tools:text="jaap" | |||||
| android:textSize="@dimen/smallSize" | |||||
| android:textColor="@color/main_text_color" | |||||
| /> | |||||
| <TextView | |||||
| android:id="@+id/tv_value" | |||||
| android:layout_width="wrap_content" | |||||
| android:layout_height="wrap_content" | |||||
| android:singleLine="true" | |||||
| android:ellipsize="end" | |||||
| android:layout_marginEnd="@dimen/global_spacing" | |||||
| android:layout_marginStart="@dimen/global_spacing" | |||||
| android:textSize="@dimen/smallSize" | |||||
| android:textColor="@color/main_text_color" | |||||
| tools:text="治疗"/> | |||||
| </LinearLayout> |
| tools:text="12:12:12" | tools:text="12:12:12" | ||||
| android:textSize="@dimen/smallSize" | android:textSize="@dimen/smallSize" | ||||
| android:textColor="@color/gray_2" | android:textColor="@color/gray_2" | ||||
| android:layout_marginStart="24dp" /> | |||||
| android:layout_marginStart="12dp" /> | |||||
| <TextView | <TextView | ||||
| android:id="@+id/tv_score" | android:id="@+id/tv_score" |
| <androidx.constraintlayout.widget.ConstraintLayout | <androidx.constraintlayout.widget.ConstraintLayout | ||||
| android:layout_width="match_parent" | android:layout_width="match_parent" | ||||
| android:layout_height="wrap_content" | android:layout_height="wrap_content" | ||||
| android:background="@drawable/shape_rounder_12_white" | |||||
| android:background="@drawable/shape_rounder_8_stroke_gray1" | |||||
| android:padding="@dimen/global_spacing" | android:padding="@dimen/global_spacing" | ||||
| android:layout_marginBottom="12dp" | android:layout_marginBottom="12dp" | ||||
| android:layout_marginStart="@dimen/global_spacing" | android:layout_marginStart="@dimen/global_spacing" |
| <string name="vocabulary_level">测试等级:</string> | <string name="vocabulary_level">测试等级:</string> | ||||
| <string name="vocabulary">词汇量</string> | <string name="vocabulary">词汇量</string> | ||||
| <string name="test_vocabulary">测词汇量</string> | <string name="test_vocabulary">测词汇量</string> | ||||
| <string name="done">完成</string> | |||||
| <string name="xkl_dictionary">学考乐英汉双向词典</string> | |||||
| <string name="dialog_delete_history">你确定要删除历史记录吗?</string> | |||||
| <string name="delete">删除</string> | |||||
| </resources> | </resources> |
| <vector xmlns:android="http://schemas.android.com/apk/res/android" | |||||
| android:width="16dp" | |||||
| android:height="16dp" | |||||
| android:viewportWidth="16" | |||||
| android:viewportHeight="16"> | |||||
| <path | |||||
| android:pathData="M0,0h16v16h-16z" | |||||
| android:strokeAlpha="0" | |||||
| android:strokeWidth="1" | |||||
| android:fillColor="#000000" | |||||
| android:fillType="nonZero" | |||||
| android:strokeColor="#00000000" | |||||
| android:fillAlpha="0"/> | |||||
| <path | |||||
| android:pathData="M8,1.6C11.5346,1.6 14.4,4.4654 14.4,8C14.4,11.5346 11.5346,14.4 8,14.4C4.4654,14.4 1.6,11.5346 1.6,8C1.6,4.4654 4.4654,1.6 8,1.6ZM8,2.6667C5.0545,2.6667 2.6667,5.0545 2.6667,8C2.6667,10.9455 5.0545,13.3333 8,13.3333C10.9455,13.3333 13.3333,10.9455 13.3333,8C13.3333,5.0545 10.9455,2.6667 8,2.6667ZM8,4.2667C8.2735,4.2667 8.4989,4.4726 8.5297,4.7378L8.5333,4.8L8.5333,7.7141L10.8715,9.2699C11.0992,9.4214 11.1728,9.7177 11.0515,9.9556L11.0201,10.0094C10.8686,10.2371 10.5723,10.3107 10.3344,10.1895L10.2806,10.158L7.7046,8.444C7.5745,8.3575 7.4899,8.2191 7.4708,8.0663L7.4667,8L7.4667,4.8C7.4667,4.5054 7.7054,4.2667 8,4.2667Z" | |||||
| android:strokeWidth="1" | |||||
| android:fillColor="#8A8A99" | |||||
| android:fillType="evenOdd" | |||||
| android:strokeColor="#00000000"/> | |||||
| </vector> |
| <vector xmlns:android="http://schemas.android.com/apk/res/android" | |||||
| android:width="16dp" | |||||
| android:height="16dp" | |||||
| android:viewportWidth="16" | |||||
| android:viewportHeight="16"> | |||||
| <path | |||||
| android:pathData="M9.9556,1.6C10.2055,1.6 10.422,1.7736 10.4762,2.0176L10.4762,2.0176L10.774,3.36L13.8667,3.36C14.1612,3.36 14.4,3.5988 14.4,3.8933C14.4,4.1668 14.1941,4.3923 13.9289,4.4231L13.8667,4.4267L12.64,4.426L12.64,12.8C12.64,13.6346 12.001,14.3199 11.1856,14.3935L11.04,14.4L4.96,14.4C4.0763,14.4 3.36,13.6837 3.36,12.8L3.36,12.8L3.359,4.426L2.1333,4.4267C1.8388,4.4267 1.6,4.1879 1.6,3.8933C1.6,3.6198 1.8059,3.3944 2.0711,3.3636L2.1333,3.36L5.225,3.36L5.5238,2.0176C5.5713,1.8041 5.7429,1.6445 5.9525,1.6079L6.0444,1.6ZM11.5733,4.4267L4.4267,4.4267L4.4267,12.8C4.4267,13.0735 4.6326,13.2989 4.8978,13.3297L4.8978,13.3297L4.96,13.3333L11.04,13.3333C11.3346,13.3333 11.5733,13.0946 11.5733,12.8L11.5733,12.8L11.5733,4.4267ZM6.8267,6.2933C7.1002,6.2933 7.3256,6.4992 7.3564,6.7645L7.36,6.8267L7.36,10.9333C7.36,11.2279 7.1212,11.4667 6.8267,11.4667C6.5532,11.4667 6.3277,11.2608 6.2969,10.9955L6.2933,10.9333L6.2933,6.8267C6.2933,6.5321 6.5321,6.2933 6.8267,6.2933ZM9.1733,6.2933C9.4468,6.2933 9.6723,6.4992 9.7031,6.7645L9.7067,6.8267L9.7067,10.9333C9.7067,11.2279 9.4679,11.4667 9.1733,11.4667C8.8998,11.4667 8.6744,11.2608 8.6436,10.9955L8.64,10.9333L8.64,6.8267C8.64,6.5321 8.8788,6.2933 9.1733,6.2933ZM9.5275,2.6667L6.472,2.6667L6.3179,3.36L9.6816,3.36L9.5275,2.6667Z" | |||||
| android:strokeWidth="1" | |||||
| android:fillColor="#9A9EB3" | |||||
| android:fillType="evenOdd" | |||||
| android:strokeColor="#00000000"/> | |||||
| </vector> |
| package com.suliang.common.base | package com.suliang.common.base | ||||
| import android.R.attr | |||||
| import android.graphics.Color | import android.graphics.Color | ||||
| import android.graphics.drawable.ColorDrawable | |||||
| import android.os.Bundle | import android.os.Bundle | ||||
| import android.view.Gravity | |||||
| import android.view.LayoutInflater | import android.view.LayoutInflater | ||||
| import android.view.View | import android.view.View | ||||
| import android.view.ViewGroup | import android.view.ViewGroup | ||||
| import androidx.fragment.app.DialogFragment | import androidx.fragment.app.DialogFragment | ||||
| import androidx.fragment.app.FragmentManager | |||||
| import androidx.viewbinding.ViewBinding | import androidx.viewbinding.ViewBinding | ||||
| import com.suliang.common.extension.initBinding | import com.suliang.common.extension.initBinding | ||||
| import android.graphics.drawable.ColorDrawable | |||||
| import android.util.DisplayMetrics | |||||
| import androidx.fragment.app.FragmentManager | |||||
| import androidx.fragment.app.FragmentTransaction | |||||
| import android.R.attr.tag | |||||
| import androidx.fragment.app.Fragment | |||||
| import java.lang.IllegalStateException | |||||
| import com.suliang.common.util.os.ScreenUtil | |||||
| /** | /** | ||||
| override fun onCreateView( | override fun onCreateView( | ||||
| inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? | inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? | ||||
| ): View? { | ): View? { | ||||
| //设置透明背景,避免DecorView的自带padding | |||||
| dialog?.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) | |||||
| _binding = initBinding(inflater, container) | _binding = initBinding(inflater, container) | ||||
| return binding.root | return binding.root | ||||
| } | } | ||||
| //设置背景透明 | //设置背景透明 | ||||
| dialog!!.window!!.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) | dialog!!.window!!.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT)) | ||||
| } | } | ||||
| resizeDialog() | |||||
| } | |||||
| protected open fun resizeDialog() { | |||||
| //设置dialog位置 | |||||
| dialog?.window?.let { | |||||
| it.attributes.run { | |||||
| this.y = ScreenUtil.getScreenHeight() / 5 | |||||
| this.width = ScreenUtil.dp2px(300f).toInt() | |||||
| it.attributes = this | |||||
| } | |||||
| it.setGravity(Gravity.TOP) | |||||
| } | |||||
| } | } | ||||
| abstract fun initFragment() | abstract fun initFragment() |