Browse Source

悬浮词典实现

master
suliang 2 years ago
parent
commit
9b6a24ea88
35 changed files with 957 additions and 153 deletions
  1. 0
    24
      .idea/codeStyles/Project.xml
  2. 11
    0
      .idea/misc.xml
  3. 1
    1
      app/build.gradle
  4. 7
    0
      app/src/main/AndroidManifest.xml
  5. 18
    74
      app/src/main/java/com/xkl/cdl/data/exam_record/AppDatabase.kt
  6. 2
    0
      app/src/main/java/com/xkl/cdl/data/exam_record/DictionaryDao.kt
  7. 65
    0
      app/src/main/java/com/xkl/cdl/data/manager/CourseManager.kt
  8. 1
    1
      app/src/main/java/com/xkl/cdl/data/manager/UserInfoManager.kt
  9. 5
    2
      app/src/main/java/com/xkl/cdl/data/repository/DataRepository.kt
  10. 11
    1
      app/src/main/java/com/xkl/cdl/dialog/CommonDialog.kt
  11. 46
    0
      app/src/main/java/com/xkl/cdl/module/XKLApplication.kt
  12. 225
    0
      app/src/main/java/com/xkl/cdl/module/floating/DictionaryFloatingSearchActivity.kt
  13. 176
    0
      app/src/main/java/com/xkl/cdl/module/floating/DictionaryFloatingWindowManager.kt
  14. 15
    2
      app/src/main/java/com/xkl/cdl/module/learn/LearnExamViewModel.kt
  15. 9
    0
      app/src/main/java/com/xkl/cdl/module/learn/LearnWordViewModel.kt
  16. 37
    36
      app/src/main/java/com/xkl/cdl/module/m_memo/MemoFragmentViewModel.kt
  17. 14
    0
      app/src/main/java/com/xkl/cdl/module/m_memo/MemoListDetailViewModel.kt
  18. 11
    2
      app/src/main/java/com/xkl/cdl/module/m_service_center/DictionaryViewModel.kt
  19. 2
    1
      app/src/main/java/com/xkl/cdl/module/m_service_center/TestScoreActivity.kt
  20. 4
    1
      app/src/main/java/com/xkl/cdl/module/m_statics/StaticsFragment.kt
  21. 42
    0
      app/src/main/java/com/xkl/cdl/module/main/MainActivity.kt
  22. 5
    1
      app/src/main/java/com/xkl/cdl/module/splash/SplashActivity.kt
  23. 6
    0
      app/src/main/res/drawable/shape_rounder_bottomlr_16_solider_white.xml
  24. 1
    0
      app/src/main/res/layout/activity_dictionary.xml
  25. 131
    0
      app/src/main/res/layout/activity_dictionary_floating_search.xml
  26. 5
    4
      app/src/main/res/layout/activity_test_detail.xml
  27. 3
    1
      app/src/main/res/layout/dialog_common.xml
  28. 39
    0
      app/src/main/res/layout/dictionary_floating_layout.xml
  29. 3
    0
      app/src/main/res/values/strings.xml
  30. 14
    1
      app/src/main/res/values/styles.xml
  31. 12
    0
      app/svg/drawable/ic_dictionary_floating.xml
  32. 4
    0
      lib/common/src/main/java/com/suliang/common/base/viewmodel/BaseViewModel.kt
  33. 23
    0
      lib/common/src/main/java/com/suliang/common/util/ActivityStackManager.kt
  34. 1
    1
      lib/common/src/main/java/com/suliang/common/util/os/FloatingWindowUtil.kt
  35. 8
    0
      lib/common/src/main/java/com/suliang/common/util/os/IntentUtils.kt

+ 0
- 24
.idea/codeStyles/Project.xml View File

<option name="IF_RPAREN_ON_NEW_LINE" value="false" /> <option name="IF_RPAREN_ON_NEW_LINE" value="false" />
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" /> <option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
</JetCodeStyleSettings> </JetCodeStyleSettings>
<DBN-PSQL>
<case-options enabled="true">
<option name="KEYWORD_CASE" value="lower" />
<option name="FUNCTION_CASE" value="lower" />
<option name="PARAMETER_CASE" value="lower" />
<option name="DATATYPE_CASE" value="lower" />
<option name="OBJECT_CASE" value="preserve" />
</case-options>
<formatting-settings enabled="false" />
</DBN-PSQL>
<DBN-SQL>
<case-options enabled="true">
<option name="KEYWORD_CASE" value="lower" />
<option name="FUNCTION_CASE" value="lower" />
<option name="PARAMETER_CASE" value="lower" />
<option name="DATATYPE_CASE" value="lower" />
<option name="OBJECT_CASE" value="preserve" />
</case-options>
<formatting-settings enabled="false">
<option name="STATEMENT_SPACING" value="one_line" />
<option name="CLAUSE_CHOP_DOWN" value="chop_down_if_statement_long" />
<option name="ITERATION_ELEMENTS_WRAPPING" value="chop_down_if_not_single" />
</formatting-settings>
</DBN-SQL>
<codeStyleSettings language="XML"> <codeStyleSettings language="XML">
<option name="FORCE_REARRANGE_MODE" value="1" /> <option name="FORCE_REARRANGE_MODE" value="1" />
<indentOptions> <indentOptions>

+ 11
- 0
.idea/misc.xml View File

<entry key="..\:/Work/XKL/XklLocal/app/src/main/res/layout/activity_fullscreen.xml" value="0.10144927536231885" /> <entry key="..\:/Work/XKL/XklLocal/app/src/main/res/layout/activity_fullscreen.xml" value="0.10144927536231885" />
<entry key="..\:/Work/XKL/XklLocal/app/src/main/res/layout/activity_main.xml" value="0.1" /> <entry key="..\:/Work/XKL/XklLocal/app/src/main/res/layout/activity_main.xml" value="0.1" />
<entry key="..\:/Work/XKL/XklLocal/app/src/main/res/layout/activity_splash.xml" value="0.1" /> <entry key="..\:/Work/XKL/XklLocal/app/src/main/res/layout/activity_splash.xml" value="0.1" />
<entry key="..\:/xuekaole/XKLLocal/app/src/main/res/drawable/shape_rounder_bottomlr_16_solider_white.xml" value="0.203125" />
<entry key="..\:/xuekaole/XKLLocal/app/src/main/res/drawable/shape_rounder_bottomlr_8_solider_white_1.xml" value="0.203125" />
<entry key="..\:/xuekaole/XKLLocal/app/src/main/res/layout/activity_dictionary.xml" value="0.1933876811594203" />
<entry key="..\:/xuekaole/XKLLocal/app/src/main/res/layout/activity_dictionary_floating_search.xml" value="0.75" />
<entry key="..\:/xuekaole/XKLLocal/app/src/main/res/layout/activity_learn_exam.xml" value="0.21666666666666667" />
<entry key="..\:/xuekaole/XKLLocal/app/src/main/res/layout/activity_test_detail.xml" value="0.21666666666666667" />
<entry key="..\:/xuekaole/XKLLocal/app/src/main/res/layout/dialog_common.xml" value="0.33" />
<entry key="..\:/xuekaole/XKLLocal/app/src/main/res/layout/dictionary_floating_layout.xml" value="0.5" />
<entry key="..\:/xuekaole/XKLLocal/app/src/main/res/layout/fragment_course_pack.xml" value="0.3338541666666667" />
<entry key="..\:/xuekaole/XKLLocal/app/src/main/res/layout/fragment_learn_center.xml" value="0.3338541666666667" />
<entry key="..\:/xuekaole/XKLLocal/lib/common/src/main/res/drawable/ic_search.xml" value="0.2212962962962963" />
</map> </map>
</option> </option>
</component> </component>

+ 1
- 1
app/build.gradle View File

// implementation "me.zhanghai.android.materialratingbar:library:1.4.0" // implementation "me.zhanghai.android.materialratingbar:library:1.4.0"
implementation 'com.xl.ratingbar:ratingbar:0.1.1' implementation 'com.xl.ratingbar:ratingbar:0.1.1'
implementation 'com.github.HuanTanSheng:EasyPhotos:3.1.5' implementation 'com.github.HuanTanSheng:EasyPhotos:3.1.5'
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.9.1'
} }

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

xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
package="com.xkl.cdl"> package="com.xkl.cdl">


<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>

<application <application
android:name=".module.XKLApplication" android:name=".module.XKLApplication"
android:allowBackup="true" android:allowBackup="true"
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.floating.DictionaryFloatingSearchActivity"
android:theme="@style/DialogActivityTheme"
android:launchMode="singleTask"
android:exported="true" />
<activity <activity
android:name=".module.m_my.CacheClearActivity" android:name=".module.m_my.CacheClearActivity"
android:exported="true" /> android:exported="true" />

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

* create 2022/7/7 16:50 * create 2022/7/7 16:50
* Describe: * Describe:
*/ */
@Database(entities = [Exam::class,ExamItem::class,DictionaryItem::class,Collect::class], version = 3, exportSchema = true)
@Database(entities = [Exam::class,ExamItem::class,DictionaryItem::class,Collect::class], version = 1, exportSchema = true)
abstract class AppDatabase : RoomDatabase() { abstract class AppDatabase : RoomDatabase() {
abstract fun examDao() : ExamDao abstract fun examDao() : ExamDao
abstract fun examItemDao(): ExamItemDao abstract fun examItemDao(): ExamItemDao
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"
private val MIGRATION_1_2 = object :Migration(1,2){
override fun migrate(database : SupportSQLiteDatabase) {
//版本升级策略,增加一个dictionary表
database.execSQL("CREATE TABLE IF NOT EXISTS `dic_history` (`courseId` INTEGER NOT NULL, `queryTime` INTEGER NOT NULL, `id` INTEGER NOT NULL, `word` TEXT NOT NULL, `form` INTEGER NOT NULL, `pre_index` TEXT, `phonetic_uk` TEXT, `phonectic_us` TEXT, `phonectic_cn` TEXT, `basic_explaination` TEXT, `all_explaination` TEXT, `phrase` TEXT, `example` TEXT, `reference` TEXT, PRIMARY KEY(`word`))")
}
}
private val MIGRATION_2_3 = object :Migration(2,3){
override fun migrate(database : SupportSQLiteDatabase) {
//版本升级策略,增加一个dictionary表
database.execSQL("CREATE TABLE IF NOT EXISTS `c_collect` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `courseId` INTEGER NOT NULL, `chapterId` INTEGER NOT NULL, `wordId` INTEGER NOT NULL, `lessonType` INTEGER NOT NULL)")
}
}
val instance by lazy(LazyThreadSafetyMode.SYNCHRONIZED) {
Room.databaseBuilder(XKLApplication.instance(), AppDatabase::class.java, DATABASE_NAME)
.addMigrations(MIGRATION_1_2)
.addMigrations(MIGRATION_2_3).build()
}
@JvmStatic
fun examBuilderToExamWithDetail(learnExam : Struct.LearnExam) : ExamWithDetail {
val exam = learnExam.run {
Exam(projectId.toInt(), packId, courseId, chapterId, lessonId, title, type.toInt(), score, totalNum.toInt(),
correctNum.toInt(), errorNum.toInt(), unanswerNum.toInt(), typeId, duration, ext, created, coverRate.toInt(),
stage)
}
val examItemList = mutableListOf<ExamItem>().apply {
learnExam.recordList.forEach {
add(ExamItem(it.questionId, it.questionType.toInt(), it.question, it.userAnswer, it.answerStatus.toInt(),
it.duration))
}
}
return ExamWithDetail(exam, examItemList)
}
@JvmStatic
fun examWithDetailToExamBuild(examWithDetail : ExamWithDetail) : Struct.LearnExam {
val examRecordList = mutableListOf<Struct.ExamRecord>().apply {
examWithDetail.examItemList.forEach {
add(Struct.ExamRecord.newBuilder().apply {
questionId = it.questionId
questionType = it.questionType.toLong()
question = it.question
userAnswer = it.userAnswer
answerStatus = it.answerStatus.toLong()
duration = it.duration
}.build())
}
}
return Struct.LearnExam.newBuilder().apply {
examWithDetail.exam.let {
projectId = it.projectId.toLong()
packId = it.packId
courseId = it.courseId
chapterId = it.chapterId
lessonId = it.lessonId
title = it.title
type = it.examType.toLong()
score = it.score
totalNum = it.totalNum.toLong()
correctNum = it.correctNum.toLong()
errorNum = it.errorNum.toLong()
unanswerNum = it.unAnswerNum.toLong()
duration = it.duration
ext = it.ext
created = it.createTime
typeId = it.typeId
coverRate = it.coverRate.toFloat()
stage = it.stage
}
addAllRecord(examRecordList)
}.build()
val instance by lazy(LazyThreadSafetyMode.SYNCHRONIZED) {
Room.databaseBuilder(XKLApplication.instance(), AppDatabase::class.java, DATABASE_NAME).build()
// .addMigrations(MIGRATION_1_2)
// .addMigrations(MIGRATION_2_3).build()
} }
// private val MIGRATION_1_2 = object :Migration(1,2){
// override fun migrate(database : SupportSQLiteDatabase) {
// //版本升级策略,增加一个dictionary表
// database.execSQL("CREATE TABLE IF NOT EXISTS `dic_history` (`courseId` INTEGER NOT NULL, `queryTime` INTEGER NOT NULL, `id` INTEGER NOT NULL, `word` TEXT NOT NULL, `form` INTEGER NOT NULL, `pre_index` TEXT, `phonetic_uk` TEXT, `phonectic_us` TEXT, `phonectic_cn` TEXT, `basic_explaination` TEXT, `all_explaination` TEXT, `phrase` TEXT, `example` TEXT, `reference` TEXT, PRIMARY KEY(`word`))")
// }
// }
// private val MIGRATION_2_3 = object :Migration(2,3){
// override fun migrate(database : SupportSQLiteDatabase) {
// //版本升级策略,增加一个dictionary表
// database.execSQL("CREATE TABLE IF NOT EXISTS `c_collect` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `courseId` INTEGER NOT NULL, `chapterId` INTEGER NOT NULL, `wordId` INTEGER NOT NULL, `lessonType` INTEGER NOT NULL)")
// }
// }
} }
} }

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

@Query("DELETE FROM dic_history WHERE courseId = :courseId") @Query("DELETE FROM dic_history WHERE courseId = :courseId")
fun clear(courseId: Long) fun clear(courseId: Long)
@Query("DELETE FROM dic_history WHERE courseId = :courseId AND id not in(SELECT id FROM dic_history WHERE courseId =:courseId ORDER BY queryTime DESC LIMIT 30)")
fun clearMore(courseId : Long)
} }

+ 65
- 0
app/src/main/java/com/xkl/cdl/data/manager/CourseManager.kt View File

import com.xkl.cdl.data.bean.course.CoursePack import com.xkl.cdl.data.bean.course.CoursePack
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
import com.xkl.cdl.data.exam_record.Exam
import com.xkl.cdl.data.exam_record.ExamItem
import com.xkl.cdl.data.exam_record.ExamWithDetail
import mqComsumerV1.Struct
import org.json.JSONObject import org.json.JSONObject
import java.io.* import java.io.*
import java.lang.Exception import java.lang.Exception
return false return false
} }
/**
* Struct.LearnExam 转为 ExamWithDetail
*/
@JvmStatic
fun examBuilderToExamWithDetail(learnExam : Struct.LearnExam) : ExamWithDetail {
val exam = learnExam.run {
Exam(projectId.toInt(), packId, courseId, chapterId, lessonId, title, type.toInt(), score, totalNum.toInt(),
correctNum.toInt(), errorNum.toInt(), unanswerNum.toInt(), typeId, duration, ext, created, coverRate.toInt(),
stage)
}
val examItemList = mutableListOf<ExamItem>().apply {
learnExam.recordList.forEach {
add(ExamItem(it.questionId, it.questionType.toInt(), it.question, it.userAnswer, it.answerStatus.toInt(),
it.duration))
}
}
return ExamWithDetail(exam, examItemList)
}
/**
* ExamWithDetail 转为 Struct.LearnExam
*/
@JvmStatic
fun examWithDetailToExamBuild(examWithDetail : ExamWithDetail) : Struct.LearnExam {
val examRecordList = mutableListOf<Struct.ExamRecord>().apply {
examWithDetail.examItemList.forEach {
add(Struct.ExamRecord.newBuilder().apply {
questionId = it.questionId
questionType = it.questionType.toLong()
question = it.question
userAnswer = it.userAnswer
answerStatus = it.answerStatus.toLong()
duration = it.duration
}.build())
}
}
return Struct.LearnExam.newBuilder().apply {
examWithDetail.exam.let {
projectId = it.projectId.toLong()
packId = it.packId
courseId = it.courseId
chapterId = it.chapterId
lessonId = it.lessonId
title = it.title
type = it.examType.toLong()
score = it.score
totalNum = it.totalNum.toLong()
correctNum = it.correctNum.toLong()
errorNum = it.errorNum.toLong()
unanswerNum = it.unAnswerNum.toLong()
duration = it.duration
ext = it.ext
created = it.createTime
typeId = it.typeId
coverRate = it.coverRate.toFloat()
stage = it.stage
}
addAllRecord(examRecordList)
}.build()
}
} }

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

/** 存放用户头像 */ /** 存放用户头像 */
fun putUserHeadPortrait(readFile : File){ fun putUserHeadPortrait(readFile : File){
AppExecutors.io.run {
AppExecutors.io.execute {
val file = File(FileUtil.getSaveDirFile("user"),"head") val file = File(FileUtil.getSaveDirFile("user"),"head")
FileUtil.copyFile(readFile,file,false) FileUtil.copyFile(readFile,file,false)
SpUtils.instance.encode("head_portrait",file.path) SpUtils.instance.encode("head_portrait",file.path)

+ 5
- 2
app/src/main/java/com/xkl/cdl/data/repository/DataRepository.kt View File

import com.xkl.cdl.data.bean.course.CourseDetail import com.xkl.cdl.data.bean.course.CourseDetail
import com.xkl.cdl.data.bean.course.Lesson import com.xkl.cdl.data.bean.course.Lesson
import com.xkl.cdl.data.exam_record.* import com.xkl.cdl.data.exam_record.*
import com.xkl.cdl.data.manager.CourseManager
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.module.XKLApplication import com.xkl.cdl.module.XKLApplication
//如果是测试数据,进行数据转换,并将数据进行保存 //如果是测试数据,进行数据转换,并将数据进行保存
if (record.examCount > 0) { if (record.examCount > 0) {
val examWithDetail = AppDatabase.examBuilderToExamWithDetail(record.getExam(0))
val examWithDetail = CourseManager.examBuilderToExamWithDetail(record.getExam(0))
AppDatabase.instance.examMiddleDao().insert(AppDatabase.instance,examWithDetail) AppDatabase.instance.examMiddleDao().insert(AppDatabase.instance,examWithDetail)
} }
return Observable.create { return Observable.create {
//近90天词条数统计 //近90天词条数统计
val entityCountList = XKLApplication.mobileCache.entityCountList(projectId.toLong(), 0) val entityCountList = XKLApplication.mobileCache.entityCountList(projectId.toLong(), 0)
val parseFrom = AppApi.EntityCountListResponse.parseFrom(entityCountList)
val parseFrom = entityCountList?.let {
AppApi.EntityCountListResponse.parseFrom(entityCountList)
} ?: AppApi.EntityCountListResponse.newBuilder().build()
it.onNext(parseFrom) it.onNext(parseFrom)
it.onComplete() it.onComplete()
} }

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



import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
import android.os.Bundle import android.os.Bundle
import android.view.Gravity
import android.view.View import android.view.View
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import com.suliang.common.AppConfig import com.suliang.common.AppConfig
import com.suliang.common.base.BaseDialogFragment import com.suliang.common.base.BaseDialogFragment
import com.suliang.common.extension.click import com.suliang.common.extension.click
import com.suliang.common.util.DrawableUti import com.suliang.common.util.DrawableUti
import com.suliang.common.util.os.ScreenUtil
import com.xkl.cdl.databinding.DialogCommonBinding import com.xkl.cdl.databinding.DialogCommonBinding


/** /**
} }
override fun resizeDialog(){}
override fun resizeDialog(){
//设置dialog位置
dialog?.window?.let {
it.attributes.run {
this.width = ScreenUtil.dp2px(300f).toInt()
it.attributes = this
}
}
}
} }

+ 46
- 0
app/src/main/java/com/xkl/cdl/module/XKLApplication.kt View File

package com.xkl.cdl.module package com.xkl.cdl.module


import android.app.Activity
import android.app.Application import android.app.Application
import android.os.Bundle
import com.suliang.common.util.ActivityStackManager
import com.suliang.common.util.LogUtil import com.suliang.common.util.LogUtil
import com.suliang.common.util.file.FileUtil import com.suliang.common.util.file.FileUtil
import com.tencent.mmkv.MMKV import com.tencent.mmkv.MMKV
import com.xkl.cdl.module.floating.DictionaryFloatingWindowManager
import com.xkl.cdl.module.main.MainActivity
import io.reactivex.rxjava3.exceptions.UndeliverableException import io.reactivex.rxjava3.exceptions.UndeliverableException
import io.reactivex.rxjava3.functions.Consumer import io.reactivex.rxjava3.functions.Consumer
import io.reactivex.rxjava3.plugins.RxJavaPlugins import io.reactivex.rxjava3.plugins.RxJavaPlugins
LogUtil.e(rootDir) LogUtil.e(rootDir)
setRxJavaErrorHandler() setRxJavaErrorHandler()
// HookMobileCache().hook() // HookMobileCache().hook()
// registerActivityLifecycleCallbacks(lifecycleCallback)
} }
/*** /***
}) })
} }
private object lifecycleCallback : Application.ActivityLifecycleCallbacks {
private var count = 0
override fun onActivityCreated(activity : Activity, savedInstanceState : Bundle?) {
}
override fun onActivityStarted(activity : Activity) {
count ++
if (ActivityStackManager.isExistActivity(MainActivity::class.java)){
DictionaryFloatingWindowManager.getInstance().backToFront()
}
}
override fun onActivityResumed(activity : Activity) {
}
override fun onActivityPaused(activity : Activity) {
}
override fun onActivityStopped(activity : Activity) {
count --
if (count == 0){
DictionaryFloatingWindowManager.getInstance().frontToBack()
}
}
override fun onActivitySaveInstanceState(activity : Activity, outState : Bundle) {
}
override fun onActivityDestroyed(activity : Activity) {
}
}


} }

+ 225
- 0
app/src/main/java/com/xkl/cdl/module/floating/DictionaryFloatingSearchActivity.kt View File

package com.xkl.cdl.module.floating

import android.annotation.SuppressLint
import android.app.Activity
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.Gravity
import android.view.View
import android.view.ViewGroup
import androidx.core.widget.addTextChangedListener
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.suliang.common.util.LogUtil
import com.suliang.common.util.media.MPManager
import com.suliang.common.util.os.KeyboardUtil
import com.xkl.cdl.R
import com.xkl.cdl.data.repository.AudioCache
import com.xkl.cdl.databinding.ActivityDictionaryFloatingSearchBinding
import com.xkl.cdl.dialog.CommonDialog
import com.xkl.cdl.dialog.CommonDialogBean
import com.xkl.cdl.module.m_service_center.DictionaryViewModel
import android.view.WindowManager

import android.os.Build




class DictionaryFloatingSearchActivity : BaseActivityVM<ActivityDictionaryFloatingSearchBinding,DictionaryViewModel>() {
companion object{
fun instance(activity: Activity,courseId:Long = 0L){
activity.startActivity(Intent(activity,DictionaryFloatingSearchActivity::class.java).apply {
putExtra(AppConfig.INTENT_1,courseId)
})
}
}

override fun initViewModel() : DictionaryViewModel {
return ViewModelProvider(this)[DictionaryViewModel::class.java]
}
override fun initStatusBar() {
super.initStatusBar()
}
override fun initActivity(savedInstanceState : Bundle?) {
window?.let {
it.setLayout(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.WRAP_CONTENT)
it.setGravity(Gravity.TOP)
//避免状态栏不显示
if (Build.VERSION.SDK_INT >= 28) {
val params = it.attributes
params.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
it.attributes = params
}
}
vm.courseId = intent.getLongExtra(AppConfig.INTENT_1, 0)
initHistoryRecyclerView()
binding.tvClose.click {
KeyboardUtil.hideKeyboard(it)
finish()
}
//点击 查看更多
binding.tvSeeMore.click {
when (vm.detailState) {
DictionaryViewModel.STATE_HISTROY -> {
//显示页面加1, 列表更新
vm.histroyShowPage++
vm.adapter.notifyDataSetChanged()
//根据数量判断,是否还要显示
binding.tvSeeMore.visibility = if (vm.historyList.size > vm.histroyShowPage * vm.pageShowCount) View.VISIBLE else View.GONE
binding.rv.smoothScrollToPosition(vm.histroyShowPage * vm.pageShowCount - 1)
}
DictionaryViewModel.STATE_SEARCH -> {
//显示页面加1, 列表更新
vm.searchShowPage++
vm.adapter.notifyDataSetChanged()
//根据数量判断,是否还要显示
binding.tvSeeMore.visibility = if (vm.searchAssociateList.size > vm.searchShowPage * vm.pageShowCount) View.VISIBLE else View.GONE
binding.rv.smoothScrollToPosition(vm.searchShowPage * vm.pageShowCount - 1)
}
}
}
//删除历史记录,弹窗提示
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)
}
//监听EditText变化
// 1 点清空或没有内容时 显示历史记录
// 2 关键字搜索 显示搜索记录
// 3 点击历史记录或者点击搜索记录,更新显示详情
// 4 单独定义一个值,定义为点击了历史记录或搜索记录
binding.etSearch.addTextChangedListener{
vm.handler.removeCallbacksAndMessages(null)
when {
it.isNullOrEmpty() -> { //内容为空,显示为历史记录
LogUtil.e("EditText输入数据为空: 空数据,显示历史记录")
vm.detailState = DictionaryViewModel.STATE_HISTROY
vm.updateHistoryAdapterLiveData.value = vm.detailState
}
else -> { //不为空
when(vm.detailState){
DictionaryViewModel.STATE_DETAIL -> { //点击显示详情了, 更新详情显示
LogUtil.e("EditText输入数据 : 点击item显示详情")
KeyboardUtil.hideKeyboard(binding.etSearch) //关闭键盘
vm.updateHistoryAdapterLiveData.value = vm.detailState
}
else -> { //关键字搜索
LogUtil.e("EditText输入数据 : 进行关键字搜索")
vm.detailState = DictionaryViewModel.STATE_SEARCH
vm.searchKeyWord(it.toString())
}
}
}
}
}
/**搜索监听*/
vm.etSearchLiveData.observe(this){
binding.etSearch.setText(it)
binding.etSearch.setSelection(it.length)
}
//更新历史记录适配器
// true 跟新搜索结果
// false 更新列表
vm.updateHistoryAdapterLiveData.observe(this) {
LogUtil.e("Adapter 进行数据更新 $it")
when(it){
DictionaryViewModel.STATE_HISTROY -> { //历史记录
//布局显示处理
binding.run {
tvHistoryTitle.visibility = View.VISIBLE
ivDelete.visibility = View.VISIBLE
vLine.visibility = View.VISIBLE
layoutDetail.visibility = if (vm.historyList.isEmpty()) View.GONE else View.VISIBLE
}
binding.tvSeeMore.visibility = if (vm.historyList.size > vm.histroyShowPage * vm.pageShowCount) View.VISIBLE else View.GONE
vm.adapter.run {
needShowEmptyView = false
setData(vm.historyList)
}
}
DictionaryViewModel.STATE_SEARCH -> { //关键字搜索记录
binding.run {
vLine.visibility = View.GONE
tvHistoryTitle.visibility = View.GONE
ivDelete.visibility = View.GONE
layoutDetail.visibility = View.VISIBLE
tvSeeMore.visibility = if (vm.searchAssociateList.size > vm.searchShowPage * vm.pageShowCount) View.VISIBLE else View.GONE
}
vm.searchShowPage = 1
vm.adapter.run {
needShowEmptyView = true
setData(vm.searchAssociateList)
}
}
DictionaryViewModel.STATE_DETAIL -> { //item详情
binding.run {
vLine.visibility = View.GONE
tvHistoryTitle.visibility = View.GONE
ivDelete.visibility = View.GONE
layoutDetail.visibility = View.VISIBLE
tvSeeMore.visibility = View.GONE
}
vm.adapter.run {
needShowEmptyView = false
setData(vm.detailItemList)
}
}
}
}
/**发音监听*/
AudioCache.initAudioLiveData().observe(this){
it?.let {
MPManager.play(it)
}?: showToast("未找到发音文件")
}
}
private fun initHistoryRecyclerView() {
binding.rv.apply {
layoutManager = LinearLayoutManager(this@DictionaryFloatingSearchActivity, LinearLayoutManager.VERTICAL, false)
adapter = vm.adapter
}
}
@SuppressLint("NotifyDataSetChanged")
override fun loadData() {
//查询历史记录
vm.loadHistory()
}
override fun onResume() {
super.onResume()
DictionaryFloatingWindowManager.getInstance().hide()
}

}

+ 176
- 0
app/src/main/java/com/xkl/cdl/module/floating/DictionaryFloatingWindowManager.kt View File

package com.xkl.cdl.module.floating

import android.app.Activity
import android.content.Context
import android.content.Intent
import android.graphics.PixelFormat
import android.net.Uri
import android.provider.Settings
import android.view.*
import androidx.databinding.DataBindingUtil
import com.suliang.common.extension.click
import com.suliang.common.util.ActivityStackManager
import com.suliang.common.util.os.ScreenUtil
import com.suliang.common.util.os.VersionUtil
import com.xkl.cdl.R
import com.xkl.cdl.databinding.DictionaryFloatingLayoutBinding
import com.xkl.cdl.module.XKLApplication
import kotlin.math.abs

/**
* @Author: suliang
* @create: 2022/8/19 15:27
* @Description: 词典悬浮窗管理类
*/
class DictionaryFloatingWindowManager private constructor(){
companion object{
@JvmStatic
fun getInstance():DictionaryFloatingWindowManager {
return SingletonHolder.mInstance
}
}
private object SingletonHolder{
val mInstance = DictionaryFloatingWindowManager()
}
private var mWindowManager : WindowManager? = null
private var windowParams : WindowManager.LayoutParams? = null
private var layoutBinding : DictionaryFloatingLayoutBinding? = null
private var isShowing = false
var courseId = 0
set(value) {
field = value
}
fun show() {
if (!checkOverlayerPermission()) return
windowParams?.let {
layoutBinding?.root?.visibility = View.VISIBLE
} ?: let {
initLayout()
}
isShowing = true
}
fun hide() {
isShowing = false
layoutBinding?.root?.visibility = View.INVISIBLE
}
fun backToFront(){
if (isShowing){
show()
}
}
fun frontToBack(){
if (isShowing){
layoutBinding?.root?.visibility = View.INVISIBLE
}
}
/**
* 检查是否有悬浮窗权限
*/
fun checkOverlayerPermission() : Boolean {
if (VersionUtil.versionMorLater()) {
return Settings.canDrawOverlays(XKLApplication.instance())
}
return true
}
private fun initLayout() {
windowParams = WindowManager.LayoutParams().apply {
flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL.or (WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE)
type = if (VersionUtil.versionOorLater()) WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY else WindowManager.LayoutParams.TYPE_PHONE
format = PixelFormat.RGBA_8888
gravity = Gravity.LEFT.or (Gravity.TOP)
width = WindowManager.LayoutParams.WRAP_CONTENT
height = WindowManager.LayoutParams.WRAP_CONTENT
x = ScreenUtil.getScreenWidth() - ScreenUtil.dp2px(70f).toInt()
y = ScreenUtil.getScreenHeight() - ScreenUtil.dp2px(150f).toInt()
layoutBinding = DataBindingUtil.inflate(LayoutInflater.from(XKLApplication.instance()), R.layout.dictionary_floating_layout,null,false)
layoutBinding?.let {
it.root.isFocusable = true
initEvent(it)
}
mWindowManager = XKLApplication.instance().applicationContext.getSystemService(Context.WINDOW_SERVICE) as WindowManager?
mWindowManager?.addView(layoutBinding?.root,this)
}
}
private fun initEvent(binding : DictionaryFloatingLayoutBinding) {
binding.root.let {
// it.click {
//
// }
it.setOnTouchListener(object:View.OnTouchListener{
private var mLastX = 0f
private var mLastY = 0f
private var mDownX = 0f
private var mDownY = 0f
private val scaledTouchSlop = ViewConfiguration.get(XKLApplication.instance()).scaledTouchSlop
private var isDrag = false
override fun onTouch(p0 : View?, p1 : MotionEvent) : Boolean {
var x = p1.rawX
var y = p1.rawY
when(p1.action){
MotionEvent.ACTION_DOWN -> {
isDrag = false
mDownX = x
mDownY = y
mLastX = x
mLastY = y
}
MotionEvent.ACTION_MOVE -> {
val moveX = x - mLastX
val moveY = y - mLastY
windowParams?.let {
it.x = it.x + moveX.toInt()
it.y = it.y + moveY.toInt()
mWindowManager?.updateViewLayout(binding.root,it)
}
mLastX = x
mLastY = y
}
MotionEvent.ACTION_UP -> {
isDrag = abs(x - mDownX) > scaledTouchSlop || abs(y - mDownY) > scaledTouchSlop
if (!isDrag){
ActivityStackManager.topActivity()?.let{
DictionaryFloatingSearchActivity.instance(it)
}
}
}
}
return isDrag
}
})
}
}
/**
* 跳转打开悬浮窗权限设置界面
* @param activity Activity
*/
fun applyOverLayer(activity: Activity) {
if (VersionUtil.versionMorLater()) {
val intent = Intent()
intent.action = Settings.ACTION_MANAGE_OVERLAY_PERMISSION
intent.data = Uri.parse("package:" + activity.packageName)
activity.startActivityForResult(intent, 0)
} else {
val intent = Intent()
intent.action = Settings.ACTION_MANAGE_OVERLAY_PERMISSION
intent.data = Uri.fromParts("package", activity.packageName, null)
activity.startActivityForResult(intent, 0)
}
}
}

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

import com.suliang.common.extension.diskIo2Main import com.suliang.common.extension.diskIo2Main
import com.suliang.common.util.DateUtil import com.suliang.common.util.DateUtil
import com.suliang.common.util.LogUtil import com.suliang.common.util.LogUtil
import com.suliang.common.util.media.MPManager
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.SpellItemBean import com.xkl.cdl.data.bean.SpellItemBean
import com.xkl.cdl.data.manager.db.DbControlBase import com.xkl.cdl.data.manager.db.DbControlBase
import com.xkl.cdl.data.repository.DataRepository import com.xkl.cdl.data.repository.DataRepository
import com.xkl.cdl.databinding.IncludTestOptionItemBinding import com.xkl.cdl.databinding.IncludTestOptionItemBinding
import com.xkl.cdl.module.floating.DictionaryFloatingWindowManager
import io.reactivex.rxjava3.core.Observable import io.reactivex.rxjava3.core.Observable
import mqComsumerV1.Struct.* import mqComsumerV1.Struct.*
import org.json.JSONArray import org.json.JSONArray
} }
} }
} }
/** onResume /** onResume
* isAllOver = true 结束了,不处理了 * isAllOver = true 结束了,不处理了
* 开启总计时 * 开启总计时
super.onResume(owner) super.onResume(owner)
if (isAllOver) return if (isAllOver) return
startTotalCounting() startTotalCounting()
isShowBackDialog = false
when{ when{
//弹窗未显示,可直接走弹窗关闭的流程 //弹窗未显示,可直接走弹窗关闭的流程
!isShowBackDialog -> showOrDismissBackDialogForTime(isShowBackDialog) !isShowBackDialog -> showOrDismissBackDialogForTime(isShowBackDialog)
} }
//不是在上传,且为英语类型,可显示词典浮窗
if (!isShowLoading && dbBaseControl.subjectId == AppConstants.SUBJECT_ENGLISH) {
DictionaryFloatingWindowManager.getInstance().show()
}
} }
/** onPause时,停止总计时 标记进入后台 如果弹窗显示,就只需要关闭总计时就可以了,否则关闭所有计时 */ /** onPause时,停止总计时 标记进入后台 如果弹窗显示,就只需要关闭总计时就可以了,否则关闭所有计时 */
mHandler.removeCallbacks(currentCountingTimeRunnable) mHandler.removeCallbacks(currentCountingTimeRunnable)
} }
} }
DictionaryFloatingWindowManager.getInstance().hide()
}
override fun onDestroy(owner : LifecycleOwner) {
super.onDestroy(owner)
MPManager.removePlayListener()
} }
/** 停止获取下一题 */ /** 停止获取下一题 */
/** 保存处理数据 */ /** 保存处理数据 */
private fun saveData() { private fun saveData() {
DictionaryFloatingWindowManager.getInstance().hide()
showHideLoading(true) showHideLoading(true)
Observable.create<Boolean> { Observable.create<Boolean> {
val saveRecord = DataRepository.saveRecord(record) val saveRecord = DataRepository.saveRecord(record)
it.onComplete() it.onComplete()
}.compose(diskIo2Main()).subscribe({ }.compose(diskIo2Main()).subscribe({
showHideLoading(false) showHideLoading(false)
DictionaryFloatingWindowManager.getInstance().show()
sendEventBus() //返回发送数据 sendEventBus() //返回发送数据
//数据保存完成后,通过数据为空进行通知,测试完成 //数据保存完成后,通过数据为空进行通知,测试完成
currentExamBean.value = null currentExamBean.value = null
}, { }, {
showHideLoading(false) showHideLoading(false)
DictionaryFloatingWindowManager.getInstance().show()
it.printStackTrace() it.printStackTrace()
}) })
} }

+ 9
- 0
app/src/main/java/com/xkl/cdl/module/learn/LearnWordViewModel.kt View File

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.repository.DataRepository import com.xkl.cdl.data.repository.DataRepository
import com.xkl.cdl.module.floating.DictionaryFloatingWindowManager
import com.xkl.cdl.util.LearnRuleUtil import com.xkl.cdl.util.LearnRuleUtil
import io.reactivex.rxjava3.core.Observable import io.reactivex.rxjava3.core.Observable
import mqComsumerV1.Struct import mqComsumerV1.Struct
/** 封装保存数据,保存完后后,通过currentLearnWord为空通知activity显示完成界面*/ /** 封装保存数据,保存完后后,通过currentLearnWord为空通知activity显示完成界面*/
fun saveData() { fun saveData() {
DictionaryFloatingWindowManager.getInstance().hide()
showHideLoading(true) showHideLoading(true)
Observable.create<Boolean> { Observable.create<Boolean> {
// record 已经实例化并已经将数据保存 // record 已经实例化并已经将数据保存
it.onComplete() it.onComplete()
}.compose(diskIo2Main()).subscribe({ }.compose(diskIo2Main()).subscribe({
showHideLoading(false) showHideLoading(false)
DictionaryFloatingWindowManager.getInstance().show()
sendEventBus() //返回发送数据 sendEventBus() //返回发送数据
//数据保存完成后,通过数据为空进行通知,完成 //数据保存完成后,通过数据为空进行通知,完成
saveDataLiveData.value = isAllOver saveDataLiveData.value = isAllOver
}, { }, {
showHideLoading(false) showHideLoading(false)
it.printStackTrace() it.printStackTrace()
DictionaryFloatingWindowManager.getInstance().show()
}) })
} }
} }
startTotalCounting() startTotalCounting()
} }
//不是在上传,且为英语类型,可显示词典浮窗
if (!isShowLoading && dbControlBase.subjectId == AppConstants.SUBJECT_ENGLISH) {
DictionaryFloatingWindowManager.getInstance().show()
}
} }
override fun onPause(owner : LifecycleOwner) { override fun onPause(owner : LifecycleOwner) {
super.onPause(owner) super.onPause(owner)
stopTotalCountTing() stopTotalCountTing()
DictionaryFloatingWindowManager.getInstance().hide()
} }
/** /**

+ 37
- 36
app/src/main/java/com/xkl/cdl/module/m_memo/MemoFragmentViewModel.kt View File

val coursePackInResultIndex = mutableMapOf<Long, Int>() val coursePackInResultIndex = mutableMapOf<Long, Int>()
val calendar = Calendar.getInstance() val calendar = Calendar.getInstance()
val currentTimeMillis = System.currentTimeMillis() val currentTimeMillis = System.currentTimeMillis()
AppApi.GetWordListResponse.parseFrom(wordList).wrongList?.forEach { item ->
item.split("_").let { splitValue ->
val projectId = splitValue[0].toInt()
val coursePackId = splitValue[1].toLong()
val courseId = splitValue[2].toLong()
//生成 MemoCoursePack
var memoCoursePack : MemoCoursePack? = null
coursePackInResultIndex[coursePackId]?.let { index ->
memoCoursePack = resultMemoCoursePack[index]
} ?: let {
CourseManager.getCoursePackWithCoursePackId(projectId, coursePackId)?.let { coursePack ->
memoCoursePack = MemoCoursePack(coursePack).apply {
resultMemoCoursePack.add(this)
coursePackInResultIndex[coursePackId] = resultMemoCoursePack.lastIndex
}
wordList?.let {
AppApi.GetWordListResponse.parseFrom(wordList).wrongList?.forEach { item ->
item.split("_").let { splitValue ->
val projectId = splitValue[0].toInt()
val coursePackId = splitValue[1].toLong()
val courseId = splitValue[2].toLong()
//生成 MemoCoursePack
var memoCoursePack : MemoCoursePack? = null
coursePackInResultIndex[coursePackId]?.let { index ->
memoCoursePack = resultMemoCoursePack[index]
} ?: let {
CourseManager.getCoursePackWithCoursePackId(projectId, coursePackId)?.let { coursePack ->
memoCoursePack = MemoCoursePack(coursePack).apply {
resultMemoCoursePack.add(this)
coursePackInResultIndex[coursePackId] = resultMemoCoursePack.lastIndex
} }
}
memoCoursePack?.let {
it.coursePackChildrenMemo[courseId]?.add(item) ?: let { vm ->
val memoList = mutableListOf<String>()
memoList.add(item)
it.coursePackChildrenMemo[courseId] = memoList
}
} }
//复习数量
if (CourseManager.calculateIsNeedInReview(calendar, splitValue[6].toInt(), splitValue[7],
currentTimeMillis)) {
it.coursePackChildrenReview[courseId]?.let { valueNumber ->
it.coursePackChildrenReview[courseId] = valueNumber + 1
} ?: let { vm ->
it.coursePackChildrenReview[courseId] = 1
memoCoursePack?.let {
it.coursePackChildrenMemo[courseId]?.add(item) ?: let { vm ->
val memoList = mutableListOf<String>()
memoList.add(item)
it.coursePackChildrenMemo[courseId] = memoList
}
//复习数量
if (CourseManager.calculateIsNeedInReview(calendar, splitValue[6].toInt(), splitValue[7],
currentTimeMillis)) {
it.coursePackChildrenReview[courseId]?.let { valueNumber ->
it.coursePackChildrenReview[courseId] = valueNumber + 1
} ?: let { vm ->
it.coursePackChildrenReview[courseId] = 1
}
} }
} }
} }
} }
memoCoursePackList.clear()
//排序,根据课程id固定排序
resultMemoCoursePack.sortBy {
it.coursePack.coursePackId
}
memoCoursePackList.addAll(resultMemoCoursePack)
} }
memoCoursePackList.clear()
//排序,根据课程id固定排序
resultMemoCoursePack.sortBy {
it.coursePack.coursePackId
}
memoCoursePackList.addAll(resultMemoCoursePack)
return@fromCallable true return@fromCallable true
}.compose(diskIo2Main()).subscribe({ }.compose(diskIo2Main()).subscribe({
etSearchLiveData.value = etSearchLiveData.value ?: "" etSearchLiveData.value = etSearchLiveData.value ?: ""

+ 14
- 0
app/src/main/java/com/xkl/cdl/module/m_memo/MemoListDetailViewModel.kt View File

package com.xkl.cdl.module.m_memo package com.xkl.cdl.module.m_memo


import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import com.suliang.common.base.activity.ToastEvent import com.suliang.common.base.activity.ToastEvent
import com.suliang.common.base.viewmodel.BaseViewModel import com.suliang.common.base.viewmodel.BaseViewModel
import com.xkl.cdl.data.manager.CourseManager import com.xkl.cdl.data.manager.CourseManager
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.DictionaryManager
import com.xkl.cdl.module.floating.DictionaryFloatingWindowManager
import io.reactivex.rxjava3.core.Observable import io.reactivex.rxjava3.core.Observable
import java.util.* import java.util.*


} }
override fun onResume(owner : LifecycleOwner) {
super.onResume(owner)
if (dbControlBase.subjectId == AppConstants.SUBJECT_ENGLISH){
DictionaryFloatingWindowManager.getInstance().show()
}
}
override fun onPause(owner : LifecycleOwner) {
super.onPause(owner)
DictionaryFloatingWindowManager.getInstance().hide()
}
} }

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



import android.os.Handler import android.os.Handler
import android.os.Looper import android.os.Looper
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import com.suliang.common.base.viewmodel.BaseViewModel import com.suliang.common.base.viewmodel.BaseViewModel
import com.suliang.common.extension.io2Main import com.suliang.common.extension.io2Main
/** /**
* 查询中文item下的多个英文item集合 * 查询中文item下的多个英文item集合
* @param it DictionaryItem
* @param chineseItem DictionaryItem
* @return MutableList<DictionaryItem>? * @return MutableList<DictionaryItem>?
*/ */
fun queryChineseForEnglishList(chineseItem : DictionaryItem) { fun queryChineseForEnglishList(chineseItem : DictionaryItem) {
* @param position Int 搜索列表中的位置 * @param position Int 搜索列表中的位置
*/ */
fun insertAndUpdateHistory(item : DictionaryItem, position : Int) { fun insertAndUpdateHistory(item : DictionaryItem, position : Int) {
detailState = STATE_DETAIL
Observable.fromCallable { Observable.fromCallable {
item.queryTime = System.currentTimeMillis() item.queryTime = System.currentTimeMillis()
//添加到历史记录第一个 //添加到历史记录第一个
} }
//添加到历史记录第一个 //添加到历史记录第一个
historyList.add(0, item) historyList.add(0, item)
detailState = STATE_DETAIL
//重新赋值需要用于刷新的集合 //重新赋值需要用于刷新的集合
detailItemList = mutableListOf(item) detailItemList = mutableListOf(item)
}.subscribeOn(Schedulers.from(AppExecutors.io)).subscribe() }.subscribeOn(Schedulers.from(AppExecutors.io)).subscribe()
} }
override fun onDestroy(owner : LifecycleOwner) {
super.onDestroy(owner)
AppExecutors.io.execute {
AppDatabase.instance.dictionaryDao().clearMore(courseId)
}
}
} }

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

import com.xkl.cdl.adapter.AdapterTestScore import com.xkl.cdl.adapter.AdapterTestScore
import com.xkl.cdl.data.DataTransferHolder import com.xkl.cdl.data.DataTransferHolder
import com.xkl.cdl.data.exam_record.AppDatabase import com.xkl.cdl.data.exam_record.AppDatabase
import com.xkl.cdl.data.manager.CourseManager
import com.xkl.cdl.databinding.ActivityTestScoreBinding import com.xkl.cdl.databinding.ActivityTestScoreBinding
import com.xkl.cdl.widget.MyFlexboxLayoutManager import com.xkl.cdl.widget.MyFlexboxLayoutManager
import io.reactivex.rxjava3.core.Observable import io.reactivex.rxjava3.core.Observable
onItemClick = {_, _, item -> onItemClick = {_, _, item ->
Observable.fromCallable { Observable.fromCallable {
val queryDetail = AppDatabase.instance.examMiddleDao().queryDetail(item.id) val queryDetail = AppDatabase.instance.examMiddleDao().queryDetail(item.id)
AppDatabase.examWithDetailToExamBuild(queryDetail)
CourseManager.examWithDetailToExamBuild(queryDetail)
}.compose(diskIo2Main()).subscribe{ }.compose(diskIo2Main()).subscribe{
DataTransferHolder.instance.putData(value = it) DataTransferHolder.instance.putData(value = it)
startActivity(TestDetailActivity::class.java) startActivity(TestDetailActivity::class.java)

+ 4
- 1
app/src/main/java/com/xkl/cdl/module/m_statics/StaticsFragment.kt View File

//监听图标数据初始结果 //监听图标数据初始结果
vm.chartLineInitLiveData.observe(this) { vm.chartLineInitLiveData.observe(this) {
when { when {
!it -> binding.chart.setNoDataText("暂无数据")
!it -> binding.chart.run {
setNoDataText("暂无数据")
clear()
}
else -> { else -> {
setChartData() setChartData()
val lineData = LineData(vm.linDataSet_new, vm.linDataSet_review).apply { val lineData = LineData(vm.linDataSet_new, vm.linDataSet_review).apply {

+ 42
- 0
app/src/main/java/com/xkl/cdl/module/main/MainActivity.kt View File



import android.graphics.Color import android.graphics.Color
import android.os.Bundle import android.os.Bundle
import android.view.KeyEvent
import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelProvider
import com.suliang.common.base.activity.BaseActivityVM import com.suliang.common.base.activity.BaseActivityVM
import com.suliang.common.extension.loadFragment import com.suliang.common.extension.loadFragment
import com.suliang.common.extension.showHideFragment import com.suliang.common.extension.showHideFragment
import com.xkl.cdl.R import com.xkl.cdl.R
import com.xkl.cdl.databinding.ActivityMainBinding import com.xkl.cdl.databinding.ActivityMainBinding
import com.xkl.cdl.dialog.CommonDialog
import com.xkl.cdl.dialog.CommonDialogBean
import com.xkl.cdl.module.XKLApplication
import com.xkl.cdl.module.floating.DictionaryFloatingWindowManager
import com.xkl.cdl.module.m_center_learn.LearnCenterFragment import com.xkl.cdl.module.m_center_learn.LearnCenterFragment
import com.xkl.cdl.module.m_memo.MemoFragment import com.xkl.cdl.module.m_memo.MemoFragment
import com.xkl.cdl.module.m_my.MyFragment import com.xkl.cdl.module.m_my.MyFragment
//加载Fragment并显示 //加载Fragment并显示
loadFragment(R.id.layout_container, 2, mMemo, mStatistics, mLearnCenter, mServiceCenter, mMy) loadFragment(R.id.layout_container, 2, mMemo, mStatistics, mLearnCenter, mServiceCenter, mMy)
binding.layoutNavContainer.check(R.id.nav_learnCenter) binding.layoutNavContainer.check(R.id.nav_learnCenter)
showNotOpenFloatPermissionDialog()
} }


fun setStatusBar(isMyFragment : Boolean){ fun setStatusBar(isMyFragment : Boolean){
} }
} }
/** 词典悬浮窗权限 */
private fun showNotOpenFloatPermissionDialog() {
if (!DictionaryFloatingWindowManager.getInstance().checkOverlayerPermission()) {
val commonDialogBean = CommonDialogBean(titleText = R.string.floating_dictionary_tips,
contentText = R.string.floating_dictionary_content,
rightText = R.string.floating_dictionary_right_button,
rightColor = R.color.theme_color,
leftText = R.string.cancel)
CommonDialog.newInstance(commonDialogBean).apply {
onCommonDialogButtonClickListener = { dialog : CommonDialog, isRightClick : Boolean ->
if (isRightClick) {
DictionaryFloatingWindowManager.getInstance().applyOverLayer(this@MainActivity)
}
dialog.dismissAllowingStateLoss()
}
}.show(supportFragmentManager,"floating")
}
}
//按返回按键的时间,两次返回键间隔2秒即可推出程序
private var mExitTime : Long = 0
override fun onKeyDown(keyCode : Int, event : KeyEvent?) : Boolean {
if (keyCode == KeyEvent.KEYCODE_BACK) {
if (System.currentTimeMillis() - mExitTime > 2000) {
showToast("再按一次退出程序")
mExitTime = System.currentTimeMillis()
} else {
finish()
System.exit(0)
}
return true
}
return super.onKeyDown(keyCode, event)
}
} }

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

import com.xkl.cdl.data.manager.FilePathManager import com.xkl.cdl.data.manager.FilePathManager
import com.xkl.cdl.data.manager.db.DbCoursePackManager import com.xkl.cdl.data.manager.db.DbCoursePackManager
import com.xkl.cdl.databinding.ActivitySplashBinding import com.xkl.cdl.databinding.ActivitySplashBinding
import com.xkl.cdl.databinding.DictionaryFloatingLayoutBinding
import com.xkl.cdl.module.XKLApplication import com.xkl.cdl.module.XKLApplication
import com.xkl.cdl.module.floating.DictionaryFloatingWindowManager
import com.xkl.cdl.module.main.MainActivity import com.xkl.cdl.module.main.MainActivity
import io.reactivex.rxjava3.core.Observable import io.reactivex.rxjava3.core.Observable
import java.io.File import java.io.File
} }
// TODO: 2022/3/22 读取当前app绑定的课程数据, // TODO: 2022/3/22 读取当前app绑定的课程数据,
DbCoursePackManager().queryBindingCoursePack("262,261,264,136,547,615,516,411")
// DbCoursePackManager().queryBindingCoursePack("262,261,264,136,547,615,516,411")
//暂时不用口语课程
DbCoursePackManager().queryBindingCoursePack("262,261,264,136,547,516,411")
//复制课程的数据库到对应位置 //复制课程的数据库到对应位置
CourseManager.checkCourseDb() CourseManager.checkCourseDb()
//定时跳跃到住主界面 //定时跳跃到住主界面

+ 6
- 0
app/src/main/res/drawable/shape_rounder_bottomlr_16_solider_white.xml View File

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@color/white"/>
<corners android:bottomLeftRadius="16dp"
android:bottomRightRadius="16dp"/>
</shape>

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

android:paddingEnd="@dimen/global_spacing" android:paddingEnd="@dimen/global_spacing"
android:drawablePadding="4dp" android:drawablePadding="4dp"
android:textSize="@dimen/smallSize" android:textSize="@dimen/smallSize"
android:textColor="@color/main_text_color"
android:gravity="center_vertical" android:gravity="center_vertical"
android:singleLine="true" android:singleLine="true"
android:hint="输入你要搜索的内容…"/> android:hint="输入你要搜索的内容…"/>

+ 131
- 0
app/src/main/res/layout/activity_dictionary_floating_search.xml View File

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:context=".module.floating.DictionaryFloatingSearchActivity"
android:background="@drawable/shape_rounder_bottomlr_16_solider_white">

<com.suliang.common.widget.InputSearchEditText
android:id="@+id/et_search"
android:layout_width="0dp"
android:layout_height="40dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="@+id/tv_close"
app:layout_constraintBottom_toTopOf="@+id/guide_line"
android:layout_marginStart="@dimen/global_spacing"
android:layout_marginEnd="@dimen/global_spacing"
android:background="@drawable/et_search_bg"
android:imeOptions="actionDone"
android:paddingStart="@dimen/global_spacing"
android:paddingEnd="@dimen/global_spacing"
android:drawablePadding="4dp"
android:textSize="@dimen/smallSize"
android:textColor="@color/main_text_color"
android:gravity="center_vertical"
android:singleLine="true"
android:hint="输入你要搜索的内容…"/>

<TextView
android:id="@+id/tv_close"
android:layout_width="50dp"
android:layout_height="36dp"
android:layout_marginLeft="6dp"
android:layout_marginRight="6dp"
android:gravity="center"
android:text="关闭"
android:textColor="@color/gray_2"
android:textSize="@dimen/smallSize"
app:layout_constraintStart_toEndOf="@+id/et_search"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@+id/et_search"
app:layout_constraintBottom_toBottomOf="@+id/et_search"/>

<androidx.constraintlayout.widget.Guideline
android:id="@+id/guide_line"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_begin="76dp"/>

<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/guide_line"
app:layout_constraintVertical_bias="0"
android:layout_marginBottom="34dp"
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"
app:layout_constrainedHeight="true"
android:visibility="gone">

<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"
app:layout_constraintBottom_toTopOf="@+id/tv_see_more"
app:layout_constraintVertical_chainStyle="packed"
app:layout_constraintVertical_bias="0"
app:layout_constrainedHeight="true"
tools:itemCount="10"/>

<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"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintVertical_bias="0"
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>

+ 5
- 4
app/src/main/res/layout/activity_test_detail.xml View File

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" android:visibility="gone"
tools:visibility="visible"
tools:visibility="gone"
> >


<TextView <TextView
<androidx.core.widget.NestedScrollView <androidx.core.widget.NestedScrollView
android:id="@+id/layout_memo_test" android:id="@+id/layout_memo_test"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_height="match_parent"
android:layout_marginTop="@dimen/line_height" android:layout_marginTop="@dimen/line_height"
android:orientation="vertical" android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="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"
app:layout_constraintVertical_bias="0" app:layout_constraintVertical_bias="0"
app:layout_constrainedHeight="true"
android:visibility="gone" android:visibility="gone"
tools:visibility="gone">
tools:visibility="visible">


<androidx.constraintlayout.widget.ConstraintLayout <androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent" android:layout_width="match_parent"
<androidx.recyclerview.widget.RecyclerView <androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv" android:id="@+id/rv"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="1dp" android:layout_marginTop="1dp"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"

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



<TextView <TextView
android:id="@+id/tv_content" android:id="@+id/tv_content"
tools:text="删除后将不可再恢复标签中的内容"
tools:text="删除后将不可再恢复标签中的内容删除后将不可再恢复标签中的内容"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@+id/tv_title" app:layout_constraintTop_toBottomOf="@+id/tv_title"
android:layout_marginTop="10dp" android:layout_marginTop="10dp"
app:layout_goneMarginTop="24dp" app:layout_goneMarginTop="24dp"
android:paddingStart="16dp"
android:paddingEnd="16dp"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
android:textColor="#8A8A99" android:textColor="#8A8A99"

+ 39
- 0
app/src/main/res/layout/dictionary_floating_layout.xml View File

<?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">

<data>

</data>

<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">

<androidx.cardview.widget.CardView
android:id="@+id/float_view"
android:layout_width="50dp"
android:layout_height="50dp"
app:cardBackgroundColor="@color/white"
app:cardCornerRadius="25dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_margin="15dp"
app:cardMaxElevation="12dp"
app:cardElevation="8dp">

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawableTop="@drawable/ic_dictionary_floating"
android:gravity="center"
android:layout_gravity="center"
android:text="词典"
android:textColor="@color/main_text_color"
android:textSize="@dimen/smallerSize" />
</androidx.cardview.widget.CardView>

</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

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

<string name="setting">设置</string> <string name="setting">设置</string>
<string name="default_sound">单词默认发音</string> <string name="default_sound">单词默认发音</string>
<string name="clear_cache">清除缓存</string> <string name="clear_cache">清除缓存</string>
<string name="floating_dictionary_tips">词典使用提示</string>
<string name="floating_dictionary_content">为了在学习中可以使用词典功能,需要手动打开并同意悬浮窗权限!</string>
<string name="floating_dictionary_right_button">去打开</string>


</resources> </resources>

+ 14
- 1
app/src/main/res/values/styles.xml View File

<item name="android:backgroundDimEnabled">true</item> <!--模糊,背景透明是这个- 弹窗背景是否变暗 --> <item name="android:backgroundDimEnabled">true</item> <!--模糊,背景透明是这个- 弹窗背景是否变暗 -->
</style> </style>



<!--dialog activity-->
<style name="DialogActivityTheme" parent="Theme.AppCompat.Dialog">
<item name="android:windowTranslucentStatus">true</item><!--透明状态栏并占用状态栏位置 -->
<item name="android:windowIsTranslucent">true</item><!-- 半透明 -->
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:backgroundDimEnabled">true</item>
<item name="android:windowContentOverlay">@null</item>
<item name="android:windowCloseOnTouchOutside">false</item>
<item name="android:backgroundDimAmount">0.5</item><!-- 背景模糊的透明度 数值越小越透明-->
<item name="android:windowIsFloating">false</item><!-- 浮现在Activity之上 -->
<!-- <item name="android:windowAnimationStyle">@null</item>&lt;!&ndash; 进入和退出动画 &ndash;&gt;-->
<item name="windowNoTitle">true</item><!-- 无标题 -->
<item name="android:windowActionBar">false</item>
</style>


</resources> </resources>

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

<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M16.41,2.4L20.8,6.789L20.8,18.6C20.8,20.2569 19.4569,21.6 17.8,21.6L7.8,21.6C6.1431,21.6 4.8,20.2569 4.8,18.6L4.8,5.4C4.8,3.7431 6.1431,2.4 7.8,2.4L16.41,2.4ZM9.1341,8.3341C7.7034,9.7648 7.6155,12.0558 8.9322,13.5919C10.249,15.1281 12.5264,15.3915 14.1591,14.1964L16.582,16.6253C16.7327,16.776 16.9522,16.8348 17.158,16.7797C17.3638,16.7245 17.5245,16.5638 17.5797,16.358C17.6348,16.1522 17.576,15.9327 17.4253,15.782L14.9964,13.3591C16.1915,11.7264 15.9281,9.449 14.3919,8.1322C12.8558,6.8155 10.5648,6.9034 9.1341,8.3341ZM11.8846,8.4122C13.3605,8.4122 14.557,9.6086 14.557,11.0846C14.557,12.5605 13.3605,13.757 11.8846,13.757C10.4086,13.757 9.2122,12.5605 9.2122,11.0846C9.2122,9.6086 10.4086,8.4122 11.8846,8.4122Z"
android:strokeWidth="1"
android:fillColor="#5082E6"
android:fillType="evenOdd"
android:strokeColor="#00000000"/>
</vector>

+ 4
- 0
lib/common/src/main/java/com/suliang/common/base/viewmodel/BaseViewModel.kt View File

val toastEvent = MutableLiveData<ToastEvent>() val toastEvent = MutableLiveData<ToastEvent>()
val pageEvent = MutableLiveData<Class<*>>() val pageEvent = MutableLiveData<Class<*>>()
//记录是否在显示loading 弹窗
var isShowLoading = false
override fun showHideLoading(isShow : Boolean) { override fun showHideLoading(isShow : Boolean) {
isShowLoading = isShow
loadingEvent.postValue(isShow) loadingEvent.postValue(isShow)
} }

+ 23
- 0
lib/common/src/main/java/com/suliang/common/util/ActivityStackManager.kt View File

} }
} }
} }
/**
* 获取顶部Activity
*/
fun topActivity() : Activity? {
return if (activityStack.isNotEmpty()){
activityStack.peek()
} else null
}
fun isExistActivity(cls : Class<*>) : Boolean {
var result = false
run m@{
activityStack.forEach {
if (it.javaClass == cls){
result = true
return@m
}
}
}
return result
}
} }

+ 1
- 1
lib/common/src/main/java/com/suliang/common/util/os/FloatingWindowUtil.kt View File

* 跳转打开悬浮窗权限设置界面 * 跳转打开悬浮窗权限设置界面
* @param activity Activity * @param activity Activity
*/ */
fun applyOverLayerPermission(activity: Activity) {
fun c(activity: Activity) {
if (VersionUtil.versionMorLater()) { if (VersionUtil.versionMorLater()) {
val intent = Intent() val intent = Intent()
intent.action = Settings.ACTION_MANAGE_OVERLAY_PERMISSION intent.action = Settings.ACTION_MANAGE_OVERLAY_PERMISSION

+ 8
- 0
lib/common/src/main/java/com/suliang/common/util/os/IntentUtils.kt View File

package com.suliang.common.util.os package com.suliang.common.util.os


import android.app.Activity
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.net.Uri import android.net.Uri
val intent = Intent(Intent.ACTION_VIEW, uri) val intent = Intent(Intent.ACTION_VIEW, uri)
context.startActivity(intent) context.startActivity(intent)
} }
/**
* 打开悬浮窗设置
*/
fun applyOverLayer(activity: Activity){
}


// /** // /**
// * 发送广播让相册扫描文件进入相册 // * 发送广播让相册扫描文件进入相册

Loading…
Cancel
Save