Browse Source

service_center

master
suliang 2 years ago
parent
commit
ffbec8bcef
40 changed files with 1653 additions and 102 deletions
  1. 9
    1
      .idea/misc.xml
  2. 3
    0
      app/src/main/AndroidManifest.xml
  3. BIN
      app/src/main/assets/dictionary.db
  4. 1
    1
      app/src/main/java/com/xkl/cdl/adapter/AdapterTestScore.kt
  5. 83
    0
      app/src/main/java/com/xkl/cdl/adapter/DictionaryAdapter.kt
  6. 21
    0
      app/src/main/java/com/xkl/cdl/data/bean/DictionaryBean.kt
  7. 24
    0
      app/src/main/java/com/xkl/cdl/data/bean/DictionaryItem.kt
  8. 1
    1
      app/src/main/java/com/xkl/cdl/data/bean/VocabularyItem.kt
  9. 5
    0
      app/src/main/java/com/xkl/cdl/data/bean/intentdata/ExamData.kt
  10. 1
    0
      app/src/main/java/com/xkl/cdl/data/exam_record/AppDatabase.kt
  11. 22
    0
      app/src/main/java/com/xkl/cdl/data/exam_record/DictionaryDao.kt
  12. 224
    0
      app/src/main/java/com/xkl/cdl/data/manager/db/DictionaryManager.kt
  13. 75
    5
      app/src/main/java/com/xkl/cdl/data/manager/db/VocabularyManager.kt
  14. 43
    0
      app/src/main/java/com/xkl/cdl/data/repository/AudioCache.kt
  15. 1
    1
      app/src/main/java/com/xkl/cdl/dialog/CommonDialog.kt
  16. 2
    12
      app/src/main/java/com/xkl/cdl/dialog/LearnDialog.kt
  17. 97
    0
      app/src/main/java/com/xkl/cdl/dialog/VocabularyDialog.kt
  18. 47
    13
      app/src/main/java/com/xkl/cdl/module/learn/LearnExamActivity.kt
  19. 10
    13
      app/src/main/java/com/xkl/cdl/module/learn/LearnExamViewModel.kt
  20. 165
    0
      app/src/main/java/com/xkl/cdl/module/m_service_center/DictionaryActivity.kt
  21. 111
    0
      app/src/main/java/com/xkl/cdl/module/m_service_center/DictionaryViewModel.kt
  22. 22
    18
      app/src/main/java/com/xkl/cdl/module/m_service_center/ServiceCenterFragment.kt
  23. 1
    1
      app/src/main/java/com/xkl/cdl/module/m_service_center/TestDetailActivity.kt
  24. 31
    8
      app/src/main/java/com/xkl/cdl/module/m_service_center/TestVocabularyActivity.kt
  25. 20
    10
      app/src/main/java/com/xkl/cdl/module/m_service_center/TestVocabularyViewModle.kt
  26. 3
    3
      app/src/main/java/com/xkl/cdl/module/splash/SplashActivity.kt
  27. 138
    0
      app/src/main/res/layout/activity_dictionary.xml
  28. 2
    0
      app/src/main/res/layout/activity_test_detail.xml
  29. 0
    4
      app/src/main/res/layout/activity_test_vocabulary.xml
  30. 198
    0
      app/src/main/res/layout/dialog_vocabulary.xml
  31. 47
    0
      app/src/main/res/layout/item_dic_detail_chinese.xml
  32. 55
    0
      app/src/main/res/layout/item_dic_detail_chinese_for_english_item.xml
  33. 94
    0
      app/src/main/res/layout/item_dic_detail_english.xml
  34. 40
    0
      app/src/main/res/layout/item_dic_search.xml
  35. 1
    1
      app/src/main/res/layout/item_test_score.xml
  36. 1
    1
      app/src/main/res/layout/item_vocabulary_level.xml
  37. 4
    0
      app/src/main/res/values/strings.xml
  38. 20
    0
      app/svg/drawable/ic_clock.xml
  39. 12
    0
      app/svg/drawable/ic_rubbish.xml
  40. 19
    9
      lib/common/src/main/java/com/suliang/common/base/BaseDialogFragment.kt

+ 9
- 1
.idea/misc.xml View File

@@ -68,6 +68,7 @@
<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_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_learn_base.xml" value="0.4979166666666667" />
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/activity_learn_creading.xml" value="0.4304093567251462" />
@@ -95,6 +96,7 @@
<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_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_main.xml" value="0.4979166666666667" />
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/fragment_course_pack.xml" value="0.34427083333333336" />
@@ -127,6 +129,12 @@
<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_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_historical_route.xml" value="0.4859375" />
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/item_memo.xml" value="0.67" />
@@ -136,7 +144,7 @@
<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_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_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" />

+ 3
- 0
app/src/main/AndroidManifest.xml View File

@@ -12,6 +12,9 @@
android:supportsRtl="true"
android:theme="@style/Theme.XklLocal"
tools:ignore="LockedOrientationActivity">
<activity
android:name=".module.m_service_center.DictionaryActivity"
android:exported="true" />
<activity
android:name=".module.m_service_center.TestVocabularyActivity"
android:exported="true" />

BIN
app/src/main/assets/dictionary.db View File


+ 1
- 1
app/src/main/java/com/xkl/cdl/adapter/AdapterTestScore.kt View File

@@ -33,7 +33,7 @@ class AdapterTestScore(vm : TestScoreViewModel) : BaseRVAdapterVM<Exam,TestScore
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")

+ 83
- 0
app/src/main/java/com/xkl/cdl/adapter/DictionaryAdapter.kt View File

@@ -0,0 +1,83 @@
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 -> {
}
}
}
}

+ 21
- 0
app/src/main/java/com/xkl/cdl/data/bean/DictionaryBean.kt View File

@@ -0,0 +1,21 @@
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
}

+ 24
- 0
app/src/main/java/com/xkl/cdl/data/bean/DictionaryItem.kt View File

@@ -0,0 +1,24 @@
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
}

+ 1
- 1
app/src/main/java/com/xkl/cdl/data/bean/VocabularyItem.kt View File

@@ -5,4 +5,4 @@ package com.xkl.cdl.data.bean
* create 2022/7/13 10:48
* 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)

+ 5
- 0
app/src/main/java/com/xkl/cdl/data/bean/intentdata/ExamData.kt View File

@@ -1,5 +1,6 @@
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.Lesson

@@ -16,6 +17,7 @@ import com.xkl.cdl.data.bean.course.Lesson
*
* 课时学后测: coursePackType, courseType, testData ,lesson.
*
* 词汇量测试: testData, vocabularyItem
*/
data class ExamData(
val subjectId : Int, //项目类型
@@ -36,5 +38,8 @@ data class ExamData(
// 课程/课时学前测试正确错误列表 key=> {chapter_id}_{lesson_id}_{entity_id} value=>正确 true;错误 false
var mExamWRMap : HashMap<String, Boolean>? = null
//测词汇量item
var vocabularyItem : VocabularyItem? = null
}

+ 1
- 0
app/src/main/java/com/xkl/cdl/data/exam_record/AppDatabase.kt View File

@@ -18,6 +18,7 @@ abstract class AppDatabase : RoomDatabase() {
abstract fun examDao() : ExamDao
abstract fun examItemDao(): ExamItemDao
abstract fun examMiddleDao(): ExamMiddleDao
abstract fun dictionaryDao(): DictionaryDao
companion object{
private var DATABASE_NAME :String = "${FileUtil.getSaveDirPath("db")}${File.separator}app.db"

+ 22
- 0
app/src/main/java/com/xkl/cdl/data/exam_record/DictionaryDao.kt View File

@@ -0,0 +1,22 @@
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)
}

+ 224
- 0
app/src/main/java/com/xkl/cdl/data/manager/db/DictionaryManager.kt View File

@@ -0,0 +1,224 @@
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)
}
}
}

+ 75
- 5
app/src/main/java/com/xkl/cdl/data/manager/db/VocabularyManager.kt View File

@@ -1,14 +1,18 @@
package com.xkl.cdl.data.manager.db

import android.widget.Toast
import androidx.core.database.getBlobOrNull
import appApi.AppApi
import com.suliang.common.AppConfig
import com.suliang.common.util.AppGlobals
import com.suliang.common.util.file.FileUtil
import com.suliang.common.util.thread.AppExecutors
import com.xkl.cdl.data.AppConstants
import com.xkl.cdl.data.bean.VocabularyItem
import com.xkl.cdl.data.bean.course.ExamBean
import com.xkl.cdl.data.manager.FilePathManager
import net.sqlcipher.database.SQLiteDatabase
import java.io.File

/**
* author suliang
@@ -17,12 +21,15 @@ import net.sqlcipher.database.SQLiteDatabase
*/
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() {
synchronized(VocabularyManager) {
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) {
AppExecutors.mainThread.run {
@@ -37,12 +44,75 @@ object VocabularyManager {
* @param level VocabularyItem
* @return List<ExamBean>
*/
fun queryVocabularyTestData(level : VocabularyItem) : List<ExamBean>{
fun queryVocabularyTestData(level : VocabularyItem) : List<ExamBean> {
open()
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
}
}

+ 43
- 0
app/src/main/java/com/xkl/cdl/data/repository/AudioCache.kt View File

@@ -8,6 +8,7 @@ import com.suliang.common.util.file.FileUtil
import com.xkl.cdl.data.AppConstants
import com.xkl.cdl.data.manager.db.DBCourseManager
import com.xkl.cdl.data.manager.db.DbControlBase
import com.xkl.cdl.data.manager.db.VocabularyManager
import io.reactivex.rxjava3.core.Observable
import java.io.File
import java.util.*
@@ -94,4 +95,46 @@ object AudioCache {
}
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
}
}
}

+ 1
- 1
app/src/main/java/com/xkl/cdl/dialog/CommonDialog.kt View File

@@ -95,5 +95,5 @@ class CommonDialog private constructor() : BaseDialogFragment<DialogCommonBindin
}
override fun resizeDialog(){}
}

+ 2
- 12
app/src/main/java/com/xkl/cdl/dialog/LearnDialog.kt View File

@@ -71,6 +71,8 @@ class LearnDialog private constructor() : BaseDialogFragment<DialogLessonLearnBi
//备忘本测试 课程测试
AppConstants.TEST_TYPE_SERVICE_CENTER,
AppConstants.TEST_TYPE_MEMO -> initMemoTestOver()
//词汇量测试结束
}
//学习结束弹窗
AppConstants.DIALOG_TYPE_LEARNING_OVER -> initLessonLearningOver(false)
@@ -87,18 +89,6 @@ class LearnDialog private constructor() : BaseDialogFragment<DialogLessonLearnBi
}
}
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() {
//插画

+ 97
- 0
app/src/main/java/com/xkl/cdl/dialog/VocabularyDialog.kt View File

@@ -0,0 +1,97 @@
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)
}
}
}
}
}
}

+ 47
- 13
app/src/main/java/com/xkl/cdl/module/learn/LearnExamActivity.kt View File

@@ -27,6 +27,7 @@ import com.xkl.cdl.adapter.itemdecoration.SpellItemDecoration
import com.xkl.cdl.data.AppConstants
import com.xkl.cdl.data.DataTransferHolder
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.event.LearnEventData
import com.xkl.cdl.data.manager.CourseManager
@@ -36,6 +37,7 @@ import com.xkl.cdl.databinding.*
import com.xkl.cdl.dialog.CommonDialog
import com.xkl.cdl.dialog.CommonDialogBean
import com.xkl.cdl.dialog.LearnDialog
import com.xkl.cdl.dialog.VocabularyDialog
import com.xkl.cdl.module.m_service_center.TestDetailActivity

/**
@@ -137,6 +139,11 @@ class LearnExamActivity : BaseActivityVM<ActivityLearnExamBinding, LearnExamView
/** 新单词来了的发音事件 */
private fun initNewWordRead(it : ExamBean) {
//词汇量测试,新单词发音
if (vm.intentData.examType == AppConstants.TEST_TYPE_NORMAL){
wordChooseBinding.ivVoice.performClick()
return
}
when (vm.intentData.courseType) {
//拼写初始不发音,作文不发音, 音标课程测试不发音
AppConstants.COURSE_TYPE_ENGLISH_SOUNDMARK, AppConstants.COURSE_TYPE_ENGLISH_SPELL, AppConstants.COURSE_TYPE_CHINESE_COMPOSITION -> {
@@ -147,7 +154,6 @@ class LearnExamActivity : BaseActivityVM<ActivityLearnExamBinding, LearnExamView
AppConstants.COURSE_TYPE_ENGLISH_VOICE -> {
wordChooseBinding.ivVoice.performClick()
}
}
}
@@ -188,7 +194,11 @@ class LearnExamActivity : BaseActivityVM<ActivityLearnExamBinding, LearnExamView
private fun initStatistics() {
binding.incStatistics.run {
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) {
tvTestTime.text = DateUtil.formatGMT(it, DateUtil.FORMAT_2)
@@ -200,6 +210,7 @@ class LearnExamActivity : BaseActivityVM<ActivityLearnExamBinding, LearnExamView
vm.errorLiveData.observe(this@LearnExamActivity) {
tvErrorNumber.text = "错误: $it"
}
}
}
@@ -497,7 +508,7 @@ class LearnExamActivity : BaseActivityVM<ActivityLearnExamBinding, LearnExamView
}
}
}
} ?: let { //取消事件
} ?: let { //取消选项答案选择事件,设置选项发音事件
vm.optionList.forEachIndexed { index, optionItemBinding ->
optionItemBinding.root.click(null)
optionItemBinding.tvOption.click { optionItemBinding.ivOption.performClick() }
@@ -523,12 +534,13 @@ class LearnExamActivity : BaseActivityVM<ActivityLearnExamBinding, LearnExamView
//口语的音频,有问题,与选项 直接获取其tag获取音频
currentPlayView?.cancelAnimation()
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)
}
}
}
@@ -593,14 +605,37 @@ class LearnExamActivity : BaseActivityVM<ActivityLearnExamBinding, LearnExamView
/** 测试完成 : 弹窗显示 */
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 {
examType = vm.intentData.examType
score = vm.scoreValue
correctNumber = vm.correctLiveData.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
}
}
@@ -717,8 +752,7 @@ class LearnExamActivity : BaseActivityVM<ActivityLearnExamBinding, LearnExamView
}
}
//备忘本测试
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 -> {
dialog.dismissAllowingStateLoss()

+ 10
- 13
app/src/main/java/com/xkl/cdl/module/learn/LearnExamViewModel.kt View File

@@ -380,8 +380,10 @@ class LearnExamViewModel : LearnBaseViewModel() {
createErrorRecord()
}
}
//添加到记录集合
mExamRecordList.add(currentExamRecord!!.build())
//添加到记录集合 词汇量测试不添加记录
if (intentData.examType != AppConstants.TEST_TYPE_NORMAL) {
mExamRecordList.add(currentExamRecord!!.build())
}
currentChooseResultLiveData.value = chooseResult
}
@@ -484,8 +486,8 @@ class LearnExamViewModel : LearnBaseViewModel() {
//分数 与 覆盖率 只有测试成功才进行计算
if (isVocablularySuccess) {
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() //测试类型的覆盖率
}
}
@@ -580,16 +582,11 @@ class LearnExamViewModel : LearnBaseViewModel() {
stage = "小学"
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) //测试试卷
//时间 学习中心的测试需要添加为学习时间

+ 165
- 0
app/src/main/java/com/xkl/cdl/module/m_service_center/DictionaryActivity.kt View File

@@ -0,0 +1,165 @@
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
}
}

+ 111
- 0
app/src/main/java/com/xkl/cdl/module/m_service_center/DictionaryViewModel.kt View File

@@ -0,0 +1,111 @@
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)
}
}

+ 22
- 18
app/src/main/java/com/xkl/cdl/module/m_service_center/ServiceCenterFragment.kt View File

@@ -13,13 +13,14 @@ import com.suliang.common.base.adapter.BaseRVAdapter
import com.suliang.common.base.fragment.BaseFragmentVM
import com.suliang.common.extension.click
import com.xkl.cdl.R
import com.xkl.cdl.adapter.DictionaryAdapter
import com.xkl.cdl.databinding.FragmentMyBinding
import com.xkl.cdl.databinding.ItemServiceCenterItemBinding
import com.xkl.cdl.databinding.ServiceCenterFragmentBinding
import com.xkl.cdl.module.main.MainActivityViewModel

class ServiceCenterFragment : BaseFragmentVM<ServiceCenterFragmentBinding, MainActivityViewModel>() {
class ServiceCenterFragment : BaseFragmentVM<ServiceCenterFragmentBinding, MainActivityViewModel>() {
companion object {
@JvmStatic
fun newInstance() = ServiceCenterFragment()
@@ -27,16 +28,17 @@ class ServiceCenterFragment : BaseFragmentVM<ServiceCenterFragmentBinding, Main
override fun initFragment() {
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 {
layoutManager = GridLayoutManager(requireContext(),2,GridLayoutManager.VERTICAL,false)
layoutManager = GridLayoutManager(requireContext(), 2, GridLayoutManager.VERTICAL, false)
setHasFixedSize(true)
adapter = object : BaseRVAdapter<Item>() {
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) {
val item = getItem(position)
(holder.binding as ItemServiceCenterItemBinding).apply {
@@ -55,23 +57,25 @@ class ServiceCenterFragment : BaseFragmentVM<ServiceCenterFragmentBinding, Main
}
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 initViewModel(): MainActivityViewModel {
override fun initViewModel() : MainActivityViewModel {
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)
}

+ 1
- 1
app/src/main/java/com/xkl/cdl/module/m_service_center/TestDetailActivity.kt View File

@@ -36,7 +36,7 @@ class TestDetailActivity : BaseActivityVM<ActivityTestDetailBinding,TestDetailVi
if (vm.learnExam.score > 0){
groupVocabularyLittle.visibility = View.GONE
groupVocabularyNormal.visibility = View.VISIBLE
tvVocabularyCount.text = "${vm.learnExam.score}"
tvVocabularyCount.text = "${vm.learnExam.score.toInt()}"
ratingBar.setStar(vm.learnExam.score/20)
tvVocabularyCoverRateStage.setHtml("覆盖率<font color=\'#F7874F\'>${vm.learnExam.coverRate}%</font>\t\t(${vm.learnExam.stage})")
}else{

+ 31
- 8
app/src/main/java/com/xkl/cdl/module/m_service_center/TestVocabularyActivity.kt View File

@@ -4,14 +4,20 @@ import android.os.Bundle
import android.view.ViewGroup
import androidx.lifecycle.ViewModelProvider
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.adapter.BaseAdapterViewHolder
import com.suliang.common.base.adapter.BaseRVAdapter
import com.suliang.common.extension.click
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.intentdata.ExamData
import com.xkl.cdl.databinding.ActivityTestVocabularyBinding
import com.xkl.cdl.databinding.ItemVocabularyLevelBinding
import com.xkl.cdl.module.learn.LearnExamActivity

class TestVocabularyActivity : BaseActivityVM<ActivityTestVocabularyBinding, TestVocabularyViewModle>() {
@@ -31,13 +37,13 @@ class TestVocabularyActivity : BaseActivityVM<ActivityTestVocabularyBinding, Tes
return BaseAdapterViewHolder(inflateBinding(parent, R.layout.item_vocabulary_level))
}
override fun onBindVH(holder : BaseAdapterViewHolder, position : Int) {
getItem(position).let {
getItem(position).let { item ->
(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)
}
}
}
@@ -47,8 +53,25 @@ class TestVocabularyActivity : BaseActivityVM<ActivityTestVocabularyBinding, Tes
}
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)
}
}
}

+ 20
- 10
app/src/main/java/com/xkl/cdl/module/m_service_center/TestVocabularyViewModle.kt View File

@@ -7,6 +7,7 @@ import com.xkl.cdl.R
import com.xkl.cdl.data.bean.VocabularyItem
import com.xkl.cdl.data.bean.course.ExamBean
import com.xkl.cdl.data.manager.db.DBCourseManager
import com.xkl.cdl.data.manager.db.VocabularyManager
import io.reactivex.rxjava3.core.Observable

/**
@@ -15,16 +16,25 @@ import io.reactivex.rxjava3.core.Observable
* Describe:
*/
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(
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) )
/**
* 查询测试数据
@@ -33,7 +43,7 @@ class TestVocabularyViewModle : BaseViewModel() {
fun queryVocabularyTestData(item : VocabularyItem) : MutableLiveData<List<ExamBean>> {
val result = MutableLiveData<List<ExamBean>>()
Observable.create<List<ExamBean>> {
it.onNext(DBCourseManager.queryLearnTest(dbControlBase, testType, lesson))
it.onNext(VocabularyManager.queryVocabularyTestData(item))
it.onComplete()
}.compose(diskIo2Main()).subscribe({
result.value = it

+ 3
- 3
app/src/main/java/com/xkl/cdl/module/splash/SplashActivity.kt View File

@@ -55,11 +55,11 @@ class SplashActivity : BaseActivity<ActivitySplashBinding>() {
//复制词典 和 词汇量测试
val dictionary = FilePathManager.getDictionaryDbPath()
if (!dictionary.exists()) {
val copyAssetResult = FileUtil.copyAsset("dictionary.db", dictionary)
FileUtil.copyAsset("dictionary.db", dictionary)
}
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绑定的课程数据,

+ 138
- 0
app/src/main/res/layout/activity_dictionary.xml View File

@@ -0,0 +1,138 @@
<?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>

+ 2
- 0
app/src/main/res/layout/activity_test_detail.xml View File

@@ -40,6 +40,7 @@
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/title_bar"
android:visibility="gone"
tools:visibility="visible"
>

@@ -213,6 +214,7 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/title_bar"
app:layout_constraintVertical_bias="0"
android:visibility="gone"
tools:visibility="gone">

<androidx.constraintlayout.widget.ConstraintLayout

+ 0
- 4
app/src/main/res/layout/activity_test_vocabulary.xml View File

@@ -20,10 +20,6 @@
android:layout_height="@dimen/title_bar_height"
app:titleTextValue="@string/test_vocabulary"/>

<View
android:layout_width="match_parent"
android:layout_height="@dimen/line_height"
android:background="@color/gray_1"/>

<TextView
android:layout_width="wrap_content"

+ 198
- 0
app/src/main/res/layout/dialog_vocabulary.xml View File

@@ -0,0 +1,198 @@
<?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>

+ 47
- 0
app/src/main/res/layout/item_dic_detail_chinese.xml View File

@@ -0,0 +1,47 @@
<?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>

+ 55
- 0
app/src/main/res/layout/item_dic_detail_chinese_for_english_item.xml View File

@@ -0,0 +1,55 @@
<?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>

+ 94
- 0
app/src/main/res/layout/item_dic_detail_english.xml View File

@@ -0,0 +1,94 @@
<?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>

+ 40
- 0
app/src/main/res/layout/item_dic_search.xml View File

@@ -0,0 +1,40 @@
<?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>

+ 1
- 1
app/src/main/res/layout/item_test_score.xml View File

@@ -69,7 +69,7 @@
tools:text="12:12:12"
android:textSize="@dimen/smallSize"
android:textColor="@color/gray_2"
android:layout_marginStart="24dp" />
android:layout_marginStart="12dp" />

<TextView
android:id="@+id/tv_score"

+ 1
- 1
app/src/main/res/layout/item_vocabulary_level.xml View File

@@ -10,7 +10,7 @@
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
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:layout_marginBottom="12dp"
android:layout_marginStart="@dimen/global_spacing"

+ 4
- 0
app/src/main/res/values/strings.xml View File

@@ -99,5 +99,9 @@
<string name="vocabulary_level">测试等级:</string>
<string name="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>

+ 20
- 0
app/svg/drawable/ic_clock.xml View File

@@ -0,0 +1,20 @@
<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>

+ 12
- 0
app/svg/drawable/ic_rubbish.xml View File

@@ -0,0 +1,12 @@
<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>

+ 19
- 9
lib/common/src/main/java/com/suliang/common/base/BaseDialogFragment.kt View File

@@ -1,22 +1,17 @@
package com.suliang.common.base

import android.R.attr
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.os.Bundle
import android.view.Gravity
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.FragmentManager
import androidx.viewbinding.ViewBinding
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


/**
@@ -33,6 +28,8 @@ abstract class BaseDialogFragment<VB : ViewBinding> : DialogFragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
): View? {
//设置透明背景,避免DecorView的自带padding
dialog?.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
_binding = initBinding(inflater, container)
return binding.root
}
@@ -52,6 +49,19 @@ abstract class BaseDialogFragment<VB : ViewBinding> : DialogFragment() {
//设置背景透明
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()

Loading…
Cancel
Save