Browse Source

main

master
suliang 2 years ago
parent
commit
8b177aebc7
83 changed files with 1804 additions and 282 deletions
  1. 1
    5
      .idea/codeStyles/Project.xml
  2. 33
    0
      .idea/misc.xml
  3. 6
    0
      .idea/sqlandroid.xml
  4. 22
    4
      ProjectErrors.md
  5. 17
    1
      README.md
  6. 8
    1
      app/build.gradle
  7. 8
    3
      app/src/main/AndroidManifest.xml
  8. 47
    0
      app/src/main/java/com/xkl/cdl/adapter/ViewPagerAdapter.kt
  9. 64
    0
      app/src/main/java/com/xkl/cdl/data/Constants.kt
  10. 11
    0
      app/src/main/java/com/xkl/cdl/data/course/CoursePack.kt
  11. 18
    0
      app/src/main/java/com/xkl/cdl/data/manager/CourseManager.kt
  12. 61
    0
      app/src/main/java/com/xkl/cdl/module/m_center_learn/CoursePackFragment.kt
  13. 9
    0
      app/src/main/java/com/xkl/cdl/module/m_center_learn/CoursePackFragmentViewModel.kt
  14. 90
    45
      app/src/main/java/com/xkl/cdl/module/m_center_learn/LearnCenterFragment.kt
  15. 39
    0
      app/src/main/java/com/xkl/cdl/module/m_center_learn/LearnCenterFragmentViewModel.kt
  16. 19
    8
      app/src/main/java/com/xkl/cdl/module/m_memo/MemoFragment.kt
  17. 25
    8
      app/src/main/java/com/xkl/cdl/module/m_my/MyFragment.kt
  18. 40
    0
      app/src/main/java/com/xkl/cdl/module/m_service_center/ServiceCenterFragment.kt
  19. 7
    0
      app/src/main/java/com/xkl/cdl/module/m_service_center/ServiceCenterViewModel.kt
  20. 20
    8
      app/src/main/java/com/xkl/cdl/module/m_statics/StaticsFragment.kt
  21. 56
    5
      app/src/main/java/com/xkl/cdl/module/main/MainActivity.kt
  22. 46
    0
      app/src/main/java/com/xkl/cdl/module/main/MainActivityViewModel.kt
  23. 16
    48
      app/src/main/java/com/xkl/cdl/module/splash/SplashActivity.kt
  24. 6
    0
      app/src/main/res/color/nav_check_color.xml
  25. 7
    0
      app/src/main/res/drawable/et_search_bg.xml
  26. 117
    6
      app/src/main/res/layout/activity_main.xml
  27. 0
    78
      app/src/main/res/layout/activity_splash.xml
  28. 14
    0
      app/src/main/res/layout/fragment_course_pack.xml
  29. 63
    10
      app/src/main/res/layout/fragment_learn_center.xml
  30. 14
    0
      app/src/main/res/layout/service_center_fragment.xml
  31. 10
    0
      app/src/main/res/layout/textview_only.xml
  32. 1
    4
      app/src/main/res/values/attrs.xml
  33. 10
    1
      app/src/main/res/values/colors.xml
  34. 14
    0
      app/src/main/res/values/dimens.xml
  35. 15
    4
      app/src/main/res/values/strings.xml
  36. 0
    1
      app/src/main/res/values/styles.xml
  37. 12
    0
      app/svg/drawable/ic_nav_learn_center.xml
  38. 12
    0
      app/svg/drawable/ic_nav_memo.xml
  39. 12
    0
      app/svg/drawable/ic_nav_my.xml
  40. 12
    0
      app/svg/drawable/ic_nav_service.xml
  41. 12
    0
      app/svg/drawable/ic_nav_statistics.xml
  42. 4
    2
      build.gradle
  43. 5
    1
      lib/common/build.gradle
  44. 13
    0
      lib/common/src/main/java/com/suliang/common/Config.kt
  45. 58
    0
      lib/common/src/main/java/com/suliang/common/base/BaseDialogFragment.kt
  46. 38
    0
      lib/common/src/main/java/com/suliang/common/base/LoadingDialog.kt
  47. 26
    0
      lib/common/src/main/java/com/suliang/common/base/ViewBehavior.kt
  48. 79
    2
      lib/common/src/main/java/com/suliang/common/base/activity/BaseActivity.kt
  49. 20
    9
      lib/common/src/main/java/com/suliang/common/base/activity/BaseActivityVM.kt
  50. 14
    0
      lib/common/src/main/java/com/suliang/common/base/activity/ToastEvent.kt
  51. 47
    6
      lib/common/src/main/java/com/suliang/common/base/fragment/BaseFragment.kt
  52. 8
    3
      lib/common/src/main/java/com/suliang/common/base/fragment/BaseFragmentVM.kt
  53. 4
    4
      lib/common/src/main/java/com/suliang/common/base/fragment/LifecycleLogFragment.kt
  54. 74
    0
      lib/common/src/main/java/com/suliang/common/base/viewmodel/BaseViewModel.kt
  55. 12
    0
      lib/common/src/main/java/com/suliang/common/base/viewmodel/ViewModelLifecycle.kt
  56. 79
    0
      lib/common/src/main/java/com/suliang/common/eventbus/LiveDataBus.kt
  57. 65
    0
      lib/common/src/main/java/com/suliang/common/eventbus/NonStickyMutableLiveData.kt
  58. 8
    0
      lib/common/src/main/java/com/suliang/common/extension/ActivityFragmentExtension.kt
  59. 4
    4
      lib/common/src/main/java/com/suliang/common/extension/BindingExtension.kt
  60. 28
    0
      lib/common/src/main/java/com/suliang/common/extension/ImageViewExtension.kt
  61. 5
    5
      lib/common/src/main/java/com/suliang/common/util/LogUtil.kt
  62. 3
    3
      lib/common/src/main/java/com/suliang/common/util/file/FileUtil.kt
  63. 1
    1
      lib/common/src/main/java/com/suliang/common/util/image/GlideLoaderStrategy.kt
  64. 8
    2
      lib/common/src/main/java/com/suliang/common/util/image/ImageLoader.kt
  65. 110
    0
      lib/common/src/main/java/com/suliang/common/widget/InputSearchEditText.kt
  66. 12
    0
      lib/common/src/main/res/drawable/ic_delete.xml
  67. 12
    0
      lib/common/src/main/res/drawable/ic_search.xml
  68. 16
    0
      lib/common/src/main/res/drawable/loading.xml
  69. BIN
      lib/common/src/main/res/drawable/loading00.png
  70. BIN
      lib/common/src/main/res/drawable/loading01.png
  71. BIN
      lib/common/src/main/res/drawable/loading02.png
  72. BIN
      lib/common/src/main/res/drawable/loading03.png
  73. BIN
      lib/common/src/main/res/drawable/loading04.png
  74. BIN
      lib/common/src/main/res/drawable/loading05.png
  75. BIN
      lib/common/src/main/res/drawable/loading06.png
  76. BIN
      lib/common/src/main/res/drawable/loading07.png
  77. BIN
      lib/common/src/main/res/drawable/loading08.png
  78. BIN
      lib/common/src/main/res/drawable/loading09.png
  79. BIN
      lib/common/src/main/res/drawable/loading10.png
  80. 6
    0
      lib/common/src/main/res/drawable/loading_bg.xml
  81. 35
    0
      lib/common/src/main/res/layout/loading_fragment.xml
  82. 12
    0
      lib/common/src/main/res/values/attrs.xml
  83. 4
    0
      lib/common/src/main/res/values/strings.xml

+ 1
- 5
.idea/codeStyles/Project.xml View File

</formatting-settings> </formatting-settings>
</DBN-SQL> </DBN-SQL>
<JetCodeStyleSettings> <JetCodeStyleSettings>
<option name="CONTINUATION_INDENT_FOR_CHAINED_CALLS" value="true" />
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" /> <option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
</JetCodeStyleSettings> </JetCodeStyleSettings>
<DBN-PSQL> <DBN-PSQL>
</formatting-settings> </formatting-settings>
</DBN-SQL> </DBN-SQL>
<codeStyleSettings language="XML"> <codeStyleSettings language="XML">
<option name="FORCE_REARRANGE_MODE" value="1" />
<indentOptions> <indentOptions>
<option name="CONTINUATION_INDENT_SIZE" value="4" /> <option name="CONTINUATION_INDENT_SIZE" value="4" />
</indentOptions> </indentOptions>
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" /> <option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
<option name="RIGHT_MARGIN" value="120" /> <option name="RIGHT_MARGIN" value="120" />
<option name="KEEP_LINE_BREAKS" value="false" /> <option name="KEEP_LINE_BREAKS" value="false" />
<option name="CALL_PARAMETERS_WRAP" value="0" />
<option name="METHOD_PARAMETERS_WRAP" value="1" />
<option name="METHOD_PARAMETERS_LPAREN_ON_NEXT_LINE" value="false" />
<option name="METHOD_PARAMETERS_RPAREN_ON_NEXT_LINE" value="false" />
</codeStyleSettings> </codeStyleSettings>
</code_scheme> </code_scheme>
</component> </component>

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

<component name="DesignSurface"> <component name="DesignSurface">
<option name="filePathToZoomLevelMap"> <option name="filePathToZoomLevelMap">
<map> <map>
<entry key="..\:/Work/XKL/XKL/XklLocal/app/drawable/svg/drawable/ic_delete.xml" value="0.3223958333333333" />
<entry key="..\:/Work/XKL/XKL/XklLocal/app/drawable/svg/drawable/ic_discern.xml" value="0.3223958333333333" />
<entry key="..\:/Work/XKL/XKL/XklLocal/app/drawable/svg/drawable/ic_nav_learn_center.xml" value="0.3223958333333333" />
<entry key="..\:/Work/XKL/XKL/XklLocal/app/drawable/svg/drawable/ic_nav_my.xml" value="0.3223958333333333" />
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/drawable/et_search_bg.xml" value="0.175" />
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/drawable/ic_delete.xml" value="0.30520833333333336" />
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/drawable/ic_discern.xml" value="0.30520833333333336" />
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/drawable/ic_launcher_background.xml" value="0.30520833333333336" />
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/drawable/ic_nav_my.xml" value="0.3223958333333333" />
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/drawable/ic_search.xml" value="0.30520833333333336" />
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/drawable/ic_spell.xml" value="0.30520833333333336" />
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/drawable/ic_voice.xml" value="0.30520833333333336" />
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/drawable/nav_learn_center.xml" value="0.30520833333333336" />
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/drawable/nav_memo.xml" value="0.30520833333333336" />
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/drawable/nav_my.xml" value="0.30520833333333336" />
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/drawable/nav_service.xml" value="0.30520833333333336" />
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/drawable/nav_statistics.xml" value="0.1" />
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/drawable/theme_splash_bg.xml" value="0.30520833333333336" />
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/activity_main.xml" value="0.5" />
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/activity_splash.xml" value="0.4921875" /> <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/activity_splash.xml" value="0.4921875" />
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/fragment_learn_center.xml" value="0.25" />
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/fragment_my.xml" value="0.28229166666666666" />
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/textview.xml" value="0.49773550724637683" />
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/textview_only.xml" value="0.49773550724637683" />
<entry key="..\:/Work/XKL/XKL/XklLocal/app/statedrawable/drawable/ic_nav_learn_center.xml" value="0.44166666666666665" />
<entry key="..\:/Work/XKL/XKL/XklLocal/app/svg/drawable/ic_nav_learn_center.xml" value="0.44166666666666665" />
<entry key="..\:/Work/XKL/XKL/XklLocal/app/svg/drawable/ic_nav_memo.xml" value="0.21574074074074073" />
<entry key="..\:/Work/XKL/XKL/XklLocal/app/svg/drawable/ic_nav_my.xml" value="0.44166666666666665" />
<entry key="..\:/Work/XKL/XKL/XklLocal/app/svg/drawable/ic_nav_service.xml" value="0.21574074074074073" />
<entry key="..\:/Work/XKL/XKL/XklLocal/app/svg/drawable/ic_nav_statistics.xml" value="0.44166666666666665" />
<entry key="..\:/Work/XKL/XKL/XklLocal/lib/common/src/main/res/drawable/ic_search.xml" value="0.19814814814814816" />
<entry key="..\:/Work/XKL/XKL/XklLocal/lib/common/src/main/res/drawable/loading_bg.xml" value="0.5061538461538462" />
<entry key="..\:/Work/XKL/XKL/XklLocal/lib/common/src/main/res/layout/loadding_fragment.xml" value="0.4817708333333333" />
<entry key="..\:/Work/XKL/XKL/XklLocal/lib/common/src/main/res/layout/loading_fragment.xml" value="0.4979166666666667" />
<entry key="..\:/Work/XKL/XklLocal/app/src/main/res/drawable/theme_splash_bg.xml" value="0.22" /> <entry key="..\:/Work/XKL/XklLocal/app/src/main/res/drawable/theme_splash_bg.xml" value="0.22" />
<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" />

+ 6
- 0
.idea/sqlandroid.xml View File

<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="SQLAndroidSettings">
<option name="storageVersion" value="2" />
</component>
</project>

+ 22
- 4
ProjectErrors.md View File

项目中遇到的错误:
使用jectPack时的依赖:
· androidx.appcompat: appcompat 依赖中已经带了livedata、viewmodel等,可以不用再依赖,再依赖时出现了异常编译错误,未解决
且 依赖版本不同,对应的livedata等版本也不同
项目中遇到的错误: 使用jectPack时的依赖: · androidx.appcompat: appcompat
依赖中已经带了livedata、viewmodel等,可以不用再依赖,再依赖时出现了异常编译错误,未解决 且 依赖版本不同,对应的livedata等版本也不同

kotlin 泛型 单例实现 扩展实现 导航实现

svg
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:name="triangle" //定义矢量图的名称
android:height="64dp" //drawable的固定高度,支持所有的尺寸单位,一般使用dp
android:width="64dp" //drawable的固定宽度,支持所有的尺寸单位,一般使用dp
android:viewportHeight="600"//视图的高度,可以理解为画布的高度
android:viewportWidth="600" > //视图的宽度,下面的pathData中的内容便会在600宽高的画布内操作
<group //定义一个组,可以包含path 及子group, 同时可以定义转换信息,如旋转,伸缩,位移
android:name="rotationGroup"//组名
android:pivotX="300.0" //X坐标中心点,默认为0
android:pivotY="300.0" //Y坐标中心点,默认为0
android:rotation="45.0" > //旋转角度,顺时针
<path android:name="v" //路径的名称
android:fillColor="#000000"//填充颜色
android:pathData="M300,70 l 0,-70 70,70 0,0 -70,70z" /> //路径的数据
</group>
</vector>

+ 17
- 1
README.md View File

common: common:
app: 获取application app: 获取application
base: 存放业务的基础类 base: 存放业务的基础类
activity、fragment、adapter的基类
eventbus: livedata的事件总线 eventbus: livedata的事件总线
util : 工具类,包含Kotlin的扩展属性
粘性事件: 不管先注册还是先发送消息,都能收到消息
非粘性事件: 必须先注册,再发送消息,如果先发送消息,再注册,则先发送的消息是监听不到
util : 工具类,包含Kotlin的扩展属性

media包: 实现音视频的播放封装
test音频: val source = listOf("http://ws.stream.qqmusic.qq.com/C4000017AcyB00D6Cr.m4a?guid=395745734&vkey=9CF75D8FDE45B1A7755C15F93C5F74CC18E444873F498DF3F5B9F0B41889778BE0EAC45305BD444F90D777C612BC5865DB0AF55A318854E1&uin=&fromtag=66"
,"http://ws.stream.qqmusic.qq.com/C400001lePVO36SNSo.m4a?guid=748677131&vkey=A6077E31CB4A1C8A4F3D5D2BEDE8D3E16AB69FF2FEE95D9D48288EAD048AB89DC53B6846D184F842257617AF9714D97C864FB183BE05CC66&uin=&fromtag=66"
,"http://ws.stream.qqmusic.qq.com/C400000ZFBf22vBvrf.m4a?guid=921100582&vkey=C9EA33972404E2AC1C80A479614AD44A9BF132A16F9B307D9515F595B41901AE53F6681E28BDA799FC047F30D624F8A19AE9C4856ADBEF4B&uin=&fromtag=66")


image包: 实现了图片加载的封装


Kotlin的单例模式: https://developer.aliyun.com/article/642618
饿汉式(直接获取实例)、懒汉式(一次判空获取实例)、双重校验锁
object 声明: 为饿汉式单例,即直接实例

+ 8
- 1
app/build.gradle View File

viewBinding true viewBinding true
dataBinding true dataBinding true
} }
sourceSets {
main {
res.srcDirs("svg")
}
}
} }


dependencies { dependencies {
implementation 'androidx.legacy:legacy-support-v4:1.0.0' implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation project(path: ':lib:common') implementation project(path: ':lib:common')
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.3.1'
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1'
rootProject.ext.dependencies_required.each{ k, v -> implementation v} rootProject.ext.dependencies_required.each{ k, v -> implementation v}
testImplementation rootProject.ext.dependencies_testImplementation.junit testImplementation rootProject.ext.dependencies_testImplementation.junit
rootProject.ext.dependencies_androidTestImplementation.each{ k,v -> androidTestImplementation v} rootProject.ext.dependencies_androidTestImplementation.each{ k,v -> androidTestImplementation v}
// // Lifecycles only (without ViewModel or LiveData) // // Lifecycles only (without ViewModel or LiveData)
// implementation "androidx.lifecycle:lifecycle-runtime-ktx:$lifecycle_version" // implementation "androidx.lifecycle:lifecycle-runtime-ktx:$lifecycle_version"
// //
// // Saved state module for ViewModel
// // Saved statedrawable module for ViewModel
// implementation "androidx.lifecycle:lifecycle-viewmodel-savedstate:$lifecycle_version" // implementation "androidx.lifecycle:lifecycle-viewmodel-savedstate:$lifecycle_version"
// //
// // Annotation processor // // Annotation processor

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

<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.xkl.cdl"> package="com.xkl.cdl">


<application <application
android:label="@string/app_name" android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round" android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true" android:supportsRtl="true"
android:theme="@style/Theme.XklLocal">
android:theme="@style/Theme.XklLocal"
tools:ignore="LockedOrientationActivity">
<activity <activity
android:name=".module.splash.SplashActivity" android:name=".module.splash.SplashActivity"
android:configChanges="orientation|keyboardHidden|screenSize" android:configChanges="orientation|keyboardHidden|screenSize"
android:screenOrientation="portrait"
android:exported="true" android:exported="true"
android:screenOrientation="portrait"
android:theme="@style/Theme.Splash"> android:theme="@style/Theme.Splash">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />
</activity> </activity>
<activity <activity
android:name=".module.main.MainActivity" android:name=".module.main.MainActivity"
android:configChanges="orientation|keyboardHidden|screenSize"/>
android:configChanges="layoutDirection|keyboard|screenSize|locale"
android:launchMode="singleTask"
android:screenOrientation="portrait"
android:windowSoftInputMode="adjustPan|adjustResize|stateHidden" />
</application> </application>


</manifest> </manifest>

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

package com.xkl.cdl.adapter

import android.annotation.SuppressLint
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.viewpager2.adapter.FragmentStateAdapter
import java.util.*

/**
* author suliang
* create 2022/3/18 10:41
* Describe: ViewPager适配器基类
*/
class ViewPagerAdapter : FragmentStateAdapter {

constructor(fragmentActivity: FragmentActivity) : super(fragmentActivity)

constructor(fragment: Fragment) : super(fragment)

constructor(fragmentActivity: FragmentActivity, fragments: MutableList<Fragment>) : super(fragmentActivity) {
mFragments.addAll(fragments)
}

constructor(fragment: Fragment, fragments: MutableList<Fragment>) : super(fragment) {
mFragments.addAll(fragments)
}

private var mFragments = mutableListOf<Fragment>()

override fun createFragment(position: Int): Fragment {
return mFragments[position]
}

override fun getItemCount(): Int {
return mFragments.size
}

fun getItem(position: Int): Fragment {
return mFragments[position]
}

@SuppressLint("NotifyDataSetChanged")
fun setData(fragments: MutableList<Fragment>) {
mFragments.clear()
mFragments.addAll(fragments)
}
}

+ 64
- 0
app/src/main/java/com/xkl/cdl/data/Constants.kt View File

package com.xkl.cdl.data

/**
* author suliang
* create 2022/3/18 9:34
* Describe:
*/
object Constants{
/** 项目: 英语 */
const val SUBJECT_ENGLISH = 3L
/** 项目: 语文*/
const val SUBJECT_CHINESE = 1L

/**课程包类型: categoryId -> 英语单词课程 */
const val COURSEPACK_TYPE_ENGLISH_WORD = 1
/**课程包类型: categoryId -> 英语音标课程 */
const val COURSEPACK_TYPE_ENGLISH_SOUNDMARK= 4
/**课程包类型: categoryId -> 英语口语 */
const val COURSEPACK_TYPE_ENGLISH_SPOKEN = 13
/**课程包类型: categoryId -> 语文作文 */
const val COURSEPACK_TYPE_CHINESE_COMPOSITION = 2
/**课程包类型: categoryId -> 语文识字 */
const val COURSEPACK_TYPE_CHINESE_LITERACY = 3
/**课程包类型: categoryId -> 语文拼音 */
const val COURSEPACK_TYPE_CHINESE_PINYIN = 1


/**课程类型: typeId 英语认读*/
const val COURSE_TYPE_ENGLISH_DISCERN = 1
/**课程类型: typeId 英语辨音*/
const val COURSE_TYPE_ENGLISH_VOICE= 2
/**课程类型: typeId 英语拼写*/
const val COURSE_TYPE_ENGLISH_SPELL = 3
/**课程类型: typeId 英语音标*/
const val COURSE_TYPE_ENGLISH_SOUNDMARK = 6
/**课程类型: typeId 英语口语*/
const val COURSE_TYPE_ENGLISH_SPOKEN = 8
/**课程类型: typeId 语文作文*/
const val COURSE_TYPE_CHINESE_COMPOSITION = 4
/**课程类型: typeId 语文识字*/
const val COURSE_TYPE_CHINESE_LITERACY = 5
/**课程类型: typeId 语文拼音*/
const val COURSE_TYPE_CHINESE_PINYIN = 7


/**课时类型: 作文视频*/
const val COMPOSITION_TYPE_VIDEO = 1 //视频
/**课时类型: 作文知识点学习*/
const val COMPOSITION_TYPE_KNOWLEDGE = 2 //知识点学习
/**课时类型: 作文知识点测试*/
const val COMPOSITION_TYPE_EXAM = 3 //知识点测试
/**课时类型: 作文课堂练习*/
const val COMPOSITION_TYPE_READING = 4 //课堂练习
/**课时类型: 作文课外练习*/
const val COMPOSITION_TYPE_TASK = 5 //课外练习

/**课时类型: 口语词汇*/
const val SPOKEN_LESSON_TYPE_WORD = 1
/**课时类型: 口语句型*/
const val SPOKEN_LESSON_TYPE_SENTENCE = 2
/**课时类型: 口语对话*/
const val SPOKEN_LESSON_TYPE_DIALOGUE = 3

}

+ 11
- 0
app/src/main/java/com/xkl/cdl/data/course/CoursePack.kt View File

package com.xkl.cdl.data.course

import androidx.databinding.BaseObservable
import androidx.databinding.Bindable

/**
* author suliang
* create 2022/3/17 18:12
* Describe:
*/
data class CoursePack(@Bindable var id : Long) : BaseObservable()

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

package com.xkl.cdl.data.manager

import com.xkl.cdl.data.course.CoursePack

/**
* author suliang
* create 2022/3/17 18:10
* Describe: 课程管理类
*/
object CourseManager {

//所有课程



private var allCoursePack : HashMap<Long, CoursePack> = HashMap()

}

+ 61
- 0
app/src/main/java/com/xkl/cdl/module/m_center_learn/CoursePackFragment.kt View File

package com.xkl.cdl.module.m_center_learn

import android.os.Bundle
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import com.suliang.common.Config
import com.suliang.common.base.fragment.BaseFragmentVM
import com.suliang.common.util.LogUtil
import com.xkl.cdl.databinding.FragmentCoursePackBinding
import com.xkl.cdl.module.main.MainActivityViewModel

/**
* 学习中心 子tab 下的详情课程
* @property mainViewModel MainActivityViewModel
*/
class CoursePackFragment : BaseFragmentVM<FragmentCoursePackBinding,CoursePackFragmentViewModel>() {



companion object {
@JvmStatic
fun newInstance(projectId: Long) = CoursePackFragment().apply {
arguments = Bundle().apply {
putLong(Config.INTENT_1,projectId)
}
}
}

override fun initViewModel(): CoursePackFragmentViewModel {
val projectId = requireArguments().getLong(Config.INTENT_1)
return ViewModelProvider(this,ViewModelFactory(projectId)).get(CoursePackFragmentViewModel::class.java).apply {
this.mainActivityViewModel = ViewModelProvider(requireActivity()).get(MainActivityViewModel::class.java)
this.learnCenterFragmentViewModel = ViewModelProvider(requireParentFragment()).get(LearnCenterFragmentViewModel::class.java)
}
}


override fun initFragment() {

vm.learnCenterFragmentViewModel.mCoursePackSearchLiveData.observe(this){
LogUtil.e("课程包列表监听到搜索内容改变: ${vm.projectId}")
}

}

override fun loadData() {

}




/** ViewModle 工厂类,提供传参 */
inner class ViewModelFactory(private val projectId:Long): ViewModelProvider.Factory{
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
return CoursePackFragmentViewModel(projectId) as T
}
}

}

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

package com.xkl.cdl.module.m_center_learn

import com.suliang.common.base.viewmodel.BaseViewModel
import com.xkl.cdl.module.main.MainActivityViewModel

class CoursePackFragmentViewModel(val projectId : Long) : BaseViewModel() {
lateinit var mainActivityViewModel: MainActivityViewModel
lateinit var learnCenterFragmentViewModel: LearnCenterFragmentViewModel
}

+ 90
- 45
app/src/main/java/com/xkl/cdl/module/m_center_learn/LearnCenterFragment.kt View File

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


import android.os.Bundle
import androidx.fragment.app.Fragment
import android.graphics.Typeface
import android.util.TypedValue
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.core.content.ContextCompat
import androidx.lifecycle.ViewModelProvider
import com.google.android.material.tabs.TabLayout
import com.google.android.material.tabs.TabLayoutMediator
import com.suliang.common.base.fragment.BaseFragmentVM
import com.suliang.common.util.LogUtil
import com.xkl.cdl.R import com.xkl.cdl.R

// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private const val ARG_PARAM1 = "param1"
private const val ARG_PARAM2 = "param2"
import com.xkl.cdl.adapter.ViewPagerAdapter
import com.xkl.cdl.databinding.FragmentLearnCenterBinding
import com.xkl.cdl.module.main.MainActivityViewModel


/** /**
* A simple [Fragment] subclass.
* Use the [LearnCenterFragment.newInstance] factory method to
* create an instance of this fragment.
* 学习中心Fragment: 包含 科目
*/ */
class LearnCenterFragment : Fragment() {
// TODO: Rename and change types of parameters
private var param1: String? = null
private var param2: String? = null

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
arguments?.let {
param1 = it.getString(ARG_PARAM1)
param2 = it.getString(ARG_PARAM2)
}
class LearnCenterFragment : BaseFragmentVM<FragmentLearnCenterBinding, LearnCenterFragmentViewModel>() {

companion object {
@JvmStatic
fun newInstance() = LearnCenterFragment()
} }


override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_learn_center, container, false)
override fun initViewModel(): LearnCenterFragmentViewModel {
return ViewModelProvider(this)[LearnCenterFragmentViewModel::class.java].apply {
this.mainActivityViewModel = ViewModelProvider(requireActivity())[MainActivityViewModel::class.java]
}
} }


companion object {
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* @param param1 Parameter 1.
* @param param2 Parameter 2.
* @return A new instance of fragment LearnCenterFragment.
*/
// TODO: Rename and change types and number of parameters
@JvmStatic
fun newInstance(param1: String, param2: String) =
LearnCenterFragment().apply {
arguments = Bundle().apply {
putString(ARG_PARAM1, param1)
putString(ARG_PARAM2, param2)
override fun initFragment() {
//初始化项目子tab和标题
vm.initLearnCenterFragment()

//必须先进行ViewPager2的适配器 设置
binding.viewPager2.adapter = ViewPagerAdapter(this, vm.mProjectFragments)

//注册 tabLayout 监听
binding.tabLayout.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {
/** 选项卡被选中 */
override fun onTabSelected(tab: TabLayout.Tab?) {
tab?.customView?.let {
(it as TextView).apply {
setTextSize(TypedValue.COMPLEX_UNIT_DIP, 22f)
typeface = Typeface.defaultFromStyle(Typeface.BOLD)
setTextColor(ContextCompat.getColor(context, R.color.main_text_color))
}
}
//选中项恢复搜索框的数据
tab?.run {


} }
LogUtil.e("选中tab ${tab?.position}")
} }
/** 当选项卡被取消选中 */
override fun onTabUnselected(tab: TabLayout.Tab?) {
LogUtil.e("未选中tab ${tab?.position}")
tab?.customView?.let {
(it as TextView).apply {
setTextSize(TypedValue.COMPLEX_UNIT_DIP, 16f)
typeface = Typeface.defaultFromStyle(Typeface.NORMAL)
setTextColor(ContextCompat.getColor(context, R.color.gray_2))
}
}
}
/**当用户再次选择 已选中的Tab */
override fun onTabReselected(tab: TabLayout.Tab?) {
}
})

//TabLayout 与 ViewPager2 进行关联, 并进行tab设值
TabLayoutMediator(binding.tabLayout, binding.viewPager2) { tab, position ->
tab.setCustomView(layoutInflater.inflate(R.layout.textview_only,binding.tabLayout,false))
tab.customView?.let {
(it as TextView).setText(vm.mProjectTitles[position])
}
}.attach()



// /** 搜索框 输入监听 */
// binding.editTextSearch.setOnEditorActionListener { v, actionId, event ->
// if (actionId == EditorInfo.IME_ACTION_SEARCH){
// //隐藏键盘
// KeyboardUtil.hideKeyboard(v)
// //赋值,通知 子 Fragment 进行更新
// v.text.toString()
//
// true
// }else {
// false
// }
// }

}

override fun loadData() {


} }
} }

+ 39
- 0
app/src/main/java/com/xkl/cdl/module/m_center_learn/LearnCenterFragmentViewModel.kt View File

package com.xkl.cdl.module.m_center_learn

import androidx.fragment.app.Fragment
import androidx.lifecycle.MutableLiveData
import com.suliang.common.base.viewmodel.BaseViewModel
import com.xkl.cdl.R
import com.xkl.cdl.data.Constants
import com.xkl.cdl.module.main.MainActivityViewModel

/**
* author suliang
* create 2022/3/17 11:01
* Describe: 学习中心ViewModel
*/
class LearnCenterFragmentViewModel : BaseViewModel() {

lateinit var mainActivityViewModel: MainActivityViewModel

/** 学习中心 子 tab fragment **/
var mProjectFragments = mutableListOf<Fragment>()
/** 学习中心 子 tab title **/
var mProjectTitles = mutableListOf<Int>()
/** 搜索框的双向数据 */
val mCoursePackSearchLiveData = MutableLiveData<String>()


/** 实例化项目课程包Fragment和显示Title */
fun initLearnCenterFragment(){
if (mProjectFragments.isEmpty()){
mProjectFragments.add(CoursePackFragment.newInstance(Constants.SUBJECT_ENGLISH))
mProjectFragments.add(CoursePackFragment.newInstance(Constants.SUBJECT_CHINESE))
}
if (mProjectTitles.isEmpty()){
mProjectTitles.add(R.string.project_english)
mProjectTitles.add(R.string.project_chinese)
}

}
}

+ 19
- 8
app/src/main/java/com/xkl/cdl/module/m_memo/MemoFragment.kt View File

import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.lifecycle.ViewModelProvider
import com.suliang.common.base.fragment.BaseFragmentVM
import com.xkl.cdl.R import com.xkl.cdl.R
import com.xkl.cdl.databinding.FragmentMemoBinding
import com.xkl.cdl.databinding.FragmentMyBinding
import com.xkl.cdl.module.main.MainActivityViewModel


// TODO: Rename parameter arguments, choose names that match // TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER // the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
* Use the [MemoFragment.newInstance] factory method to * Use the [MemoFragment.newInstance] factory method to
* create an instance of this fragment. * create an instance of this fragment.
*/ */
class MemoFragment : Fragment() {
class MemoFragment : BaseFragmentVM<FragmentMemoBinding, MainActivityViewModel>(){
// TODO: Rename and change types of parameters // TODO: Rename and change types of parameters
private var param1: String? = null private var param1: String? = null
private var param2: String? = null private var param2: String? = null
*/ */
// TODO: Rename and change types and number of parameters // TODO: Rename and change types and number of parameters
@JvmStatic @JvmStatic
fun newInstance(param1: String, param2: String) =
MemoFragment().apply {
arguments = Bundle().apply {
putString(ARG_PARAM1, param1)
putString(ARG_PARAM2, param2)
}
}
fun newInstance() = MemoFragment()
}

override fun initFragment() {

}

override fun loadData() {

}

override fun initViewModel(): MainActivityViewModel {
return ViewModelProvider(requireActivity())[MainActivityViewModel::class.java]
} }
} }

+ 25
- 8
app/src/main/java/com/xkl/cdl/module/m_my/MyFragment.kt View File

import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.lifecycle.ViewModelProvider
import com.suliang.common.base.activity.BaseActivityVM
import com.suliang.common.base.fragment.BaseFragmentVM
import com.xkl.cdl.R import com.xkl.cdl.R
import com.xkl.cdl.databinding.FragmentMyBinding
import com.xkl.cdl.module.main.MainActivityViewModel


// TODO: Rename parameter arguments, choose names that match // TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER // the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
* Use the [MyFragment.newInstance] factory method to * Use the [MyFragment.newInstance] factory method to
* create an instance of this fragment. * create an instance of this fragment.
*/ */
class MyFragment : Fragment() {
class MyFragment : BaseFragmentVM<FragmentMyBinding,MainActivityViewModel>() {
// TODO: Rename and change types of parameters // TODO: Rename and change types of parameters
private var param1: String? = null private var param1: String? = null
private var param2: String? = null private var param2: String? = null
*/ */
// TODO: Rename and change types and number of parameters // TODO: Rename and change types and number of parameters
@JvmStatic @JvmStatic
fun newInstance(param1: String, param2: String) =
MyFragment().apply {
arguments = Bundle().apply {
putString(ARG_PARAM1, param1)
putString(ARG_PARAM2, param2)
}
}
fun newInstance() = MyFragment()
// .apply {
// arguments = Bundle().apply {
// putString(ARG_PARAM1, param1)
// putString(ARG_PARAM2, param2)
// }
// }
}

override fun initFragment() {

}

override fun loadData() {

}

override fun initViewModel(): MainActivityViewModel {
return ViewModelProvider(requireActivity())[MainActivityViewModel::class.java]
} }
} }

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

package com.xkl.cdl.module.m_service_center

import androidx.lifecycle.ViewModelProvider
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.suliang.common.base.fragment.BaseFragmentVM
import com.xkl.cdl.R
import com.xkl.cdl.databinding.FragmentMyBinding
import com.xkl.cdl.databinding.ServiceCenterFragmentBinding
import com.xkl.cdl.module.main.MainActivityViewModel

class ServiceCenterFragment : BaseFragmentVM<ServiceCenterFragmentBinding, MainActivityViewModel>() {

companion object {
@JvmStatic
fun newInstance() = ServiceCenterFragment()
}

// override fun onActivityCreated(savedInstanceState: Bundle?) {
// super.onActivityCreated(savedInstanceState)
//// viewModel = ViewModelProvider(this).get(ServiceCenterViewModel::class.java)
// // TODO: Use the ViewModel
// }

override fun initFragment() {

}

override fun loadData() {

}

override fun initViewModel(): MainActivityViewModel {
return ViewModelProvider(requireActivity())[MainActivityViewModel::class.java]
}

}

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

package com.xkl.cdl.module.m_service_center

import androidx.lifecycle.ViewModel

class ServiceCenterViewModel : ViewModel() {

}

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

import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.lifecycle.ViewModelProvider
import com.suliang.common.base.fragment.BaseFragmentVM
import com.xkl.cdl.R import com.xkl.cdl.R
import com.xkl.cdl.databinding.FragmentMyBinding
import com.xkl.cdl.databinding.FragmentStaticsBinding
import com.xkl.cdl.module.main.MainActivityViewModel


// TODO: Rename parameter arguments, choose names that match // TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER // the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
* Use the [StaticsFragment.newInstance] factory method to * Use the [StaticsFragment.newInstance] factory method to
* create an instance of this fragment. * create an instance of this fragment.
*/ */
class StaticsFragment : Fragment() {
class StaticsFragment : BaseFragmentVM<FragmentStaticsBinding, MainActivityViewModel>() {
// TODO: Rename and change types of parameters // TODO: Rename and change types of parameters
private var param1: String? = null private var param1: String? = null
private var param2: String? = null private var param2: String? = null
*/ */
// TODO: Rename and change types and number of parameters // TODO: Rename and change types and number of parameters
@JvmStatic @JvmStatic
fun newInstance(param1: String, param2: String) =
StaticsFragment().apply {
arguments = Bundle().apply {
putString(ARG_PARAM1, param1)
putString(ARG_PARAM2, param2)
}
}
fun newInstance() = StaticsFragment()

}

override fun initFragment() {

}

override fun loadData() {

}

override fun initViewModel(): MainActivityViewModel {
return ViewModelProvider(requireActivity())[MainActivityViewModel::class.java]
} }
} }

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

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


import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle import android.os.Bundle
import androidx.lifecycle.ViewModelProvider
import com.suliang.common.base.activity.BaseActivityVM
import com.suliang.common.eventbus.LiveDataBus
import com.suliang.common.extension.loadFragment
import com.suliang.common.extension.showHideFragment
import com.suliang.common.util.LogUtil
import com.xkl.cdl.R import com.xkl.cdl.R
import com.xkl.cdl.databinding.ActivityMainBinding
import com.xkl.cdl.module.m_center_learn.LearnCenterFragment
import com.xkl.cdl.module.m_memo.MemoFragment
import com.xkl.cdl.module.m_my.MyFragment
import com.xkl.cdl.module.m_service_center.ServiceCenterFragment
import com.xkl.cdl.module.m_statics.StaticsFragment
import com.xkl.cdl.module.splash.SplashActivity


class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
/**
* 主界面、控制切换子Fragment
* ViewModle 进行初始化加载数据,只有等所有数据加载完全才进行页面的切换,子Fragment使用的是懒加载,不用担心生命周期、性能的问题
* @property mMemo MemoFragment
* @property mStatistics StaticsFragment
* @property mLearnCenter LearnCenterFragment
* @property mServiceCenter ServiceCenterFragment
* @property mMy MyFragment
*/
class MainActivity : BaseActivityVM<ActivityMainBinding, MainActivityViewModel>() {

private val mMemo by lazy { MemoFragment.newInstance() }
private val mStatistics by lazy { StaticsFragment.newInstance() }
private val mLearnCenter by lazy { LearnCenterFragment.newInstance() }
private val mServiceCenter by lazy { ServiceCenterFragment.newInstance() }
private val mMy by lazy { MyFragment.newInstance() }

override fun initViewModel(): MainActivityViewModel {
return ViewModelProvider(this)[MainActivityViewModel::class.java]
}


override fun initActivity(savedInstanceState: Bundle?) {
//加载Fragment并显示
loadFragment(R.id.layout_container, -1, mMemo, mStatistics, mLearnCenter, mServiceCenter, mMy)
//点击事件
binding.layoutNavContainer.setOnCheckedChangeListener { group, checkedId ->
when (checkedId) {
R.id.nav_memo -> showHideFragment(mMemo)
R.id.nav_statistics -> showHideFragment(mStatistics)
R.id.nav_learnCenter -> showHideFragment(mLearnCenter)
R.id.nav_serviceCenter -> showHideFragment(mServiceCenter)
R.id.nav_my -> showHideFragment(mMy)
}
}
}

override fun loadData() {
//加载初始化数据
vm.loadInit().observe(this){
binding.layoutNavContainer.check(R.id.nav_learnCenter)
}
} }

} }

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

package com.xkl.cdl.module.main

import androidx.fragment.app.Fragment
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import com.suliang.common.base.viewmodel.BaseViewModel
import com.suliang.common.util.LogUtil
import com.xkl.cdl.R
import com.xkl.cdl.module.m_center_learn.LearnCenterFragment
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch

/**
* author suliang
* create 2022/3/15 14:39
* Describe:
* 进行用户信息的判断,加载用户课程
*/
class MainActivityViewModel: BaseViewModel() {

/** 进入程序加载完毕监听 */
val mainInitLiveData = MutableLiveData<Boolean>()

/***
* 进行初始化加载
*/
fun loadInit(): MutableLiveData<Boolean> {
//1、查询用户的课程数据
//设置进入课程管理类中
// viewModelScope.launch {
// showHideLoading(true)
// delay(2000)
// LogUtil.e("launch delay")
// LogUtil.e("launch后")
// showHideLoading(false)
// //通知Activity 加载完成
// }
return MutableLiveData<Boolean>().apply { postValue(true) }
}

//2、计算用户的复习数据
//3、统计数据
//4、备忘本数据


}

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

import android.os.Bundle import android.os.Bundle
import android.os.Looper import android.os.Looper
import android.view.View import android.view.View
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import com.bumptech.glide.load.resource.bitmap.CircleCrop import com.bumptech.glide.load.resource.bitmap.CircleCrop
import com.suliang.common.base.activity.BaseActivity import com.suliang.common.base.activity.BaseActivity
import com.suliang.common.eventbus.LiveDataBus
import com.suliang.common.eventbus.NonStickyMutableLiveData
import com.suliang.common.util.LogUtil import com.suliang.common.util.LogUtil
import com.suliang.common.util.image.ImageLoader import com.suliang.common.util.image.ImageLoader
import com.suliang.common.util.image.ImageLoaderOption import com.suliang.common.util.image.ImageLoaderOption
import com.suliang.common.util.media.* import com.suliang.common.util.media.*
import com.suliang.common.util.thread.AppExecutors
import com.xkl.cdl.R import com.xkl.cdl.R
import com.xkl.cdl.databinding.ActivitySplashBinding import com.xkl.cdl.databinding.ActivitySplashBinding
import com.xkl.cdl.module.main.MainActivity
import com.xkl.cdl.module.main.MainActivityViewModel
import java.util.Calendar.SECOND
import java.util.concurrent.TimeUnit


@SuppressLint("CustomSplashScreen") @SuppressLint("CustomSplashScreen")
class SplashActivity : BaseActivity<ActivitySplashBinding>() { class SplashActivity : BaseActivity<ActivitySplashBinding>() {


} }



override fun loadData() { override fun loadData() {
ImageLoader.loadImage(ImageLoaderOption().apply {
targetView = binding.img
resourceId = R.drawable.illustration_splash
centerInsideEnable = true
circleEnable = true
})
}

val util:IMP = MPManager.apply {
addPlayListener(object :IMPListener{
override fun onMpState(state: EMediaState) {
LogUtil.e("SplashActivity 接收 ${Thread.currentThread() == Looper.getMainLooper().thread} ${Thread.currentThread()} --${state.name}")
//定时跳跃到住主界面
AppExecutors.scheduledExecutor.schedule({
AppExecutors.mainThread.execute {
startActivity(MainActivity::class.java)
finish()
} }
})
}, 2, TimeUnit.SECONDS)
} }
var position = 0
var seekToPosition = 1000
val source = listOf("http://ws.stream.qqmusic.qq.com/C4000017AcyB00D6Cr.m4a?guid=395745734&vkey=9CF75D8FDE45B1A7755C15F93C5F74CC18E444873F498DF3F5B9F0B41889778BE0EAC45305BD444F90D777C612BC5865DB0AF55A318854E1&uin=&fromtag=66"
,"http://ws.stream.qqmusic.qq.com/C400001lePVO36SNSo.m4a?guid=748677131&vkey=A6077E31CB4A1C8A4F3D5D2BEDE8D3E16AB69FF2FEE95D9D48288EAD048AB89DC53B6846D184F842257617AF9714D97C864FB183BE05CC66&uin=&fromtag=66"
,"http://ws.stream.qqmusic.qq.com/C400000ZFBf22vBvrf.m4a?guid=921100582&vkey=C9EA33972404E2AC1C80A479614AD44A9BF132A16F9B307D9515F595B41901AE53F6681E28BDA799FC047F30D624F8A19AE9C4856ADBEF4B&uin=&fromtag=66")




fun play(view: View) {
seekToPosition = 1000
util.play(source[0])
}
fun continuePlay(view: View) {
util.continuePlay()
}
fun stop(view: View) {
util.stopPlay()
}
fun pause(view: View) {
util.pausePlay()
}
fun seekTo(view: View) {
util.seekTo(seekToPosition)
seekToPosition += 30000
}
fun release(view: View) {
util.destroyPlay()
}

fun nextPlay(view: View) {
var i = position + 1
if (i > 3){
i = 0
}
position = i
util.play(source[position])
}
} }

+ 6
- 0
app/src/main/res/color/nav_check_color.xml View File

<?xml version="1.0" encoding="utf-8"?>
<!--主导韩颜色选择器-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@color/theme_color" android:state_checked="true"/>
<item android:color="#d0d0d0"/>
</selector>

+ 7
- 0
app/src/main/res/drawable/et_search_bg.xml View File

<?xml version="1.0" encoding="utf-8"?>
<!--学习中心:搜索框-->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/white_1"/>
<corners android:radius="18dp"/>
</shape>

+ 117
- 6
app/src/main/res/layout/activity_main.xml View File

<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".module.main.MainActivity">
xmlns:tools="http://schemas.android.com/tools">


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

</data>

<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white"
tools:context=".module.main.MainActivity">


<FrameLayout
android:id="@+id/layout_container"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toTopOf="@+id/layout_nav_container"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

<View
android:layout_width="0dp"
android:layout_height="@dimen/line_height"
android:background="@color/gray_1"
app:layout_constraintBottom_toTopOf="@+id/layout_nav_container"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />

<RadioGroup
android:id="@+id/layout_nav_container"
android:layout_width="0dp"
android:layout_height="@dimen/nav_bottom_height"
app:layout_constraintTop_toBottomOf="@+id/layout_container"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:orientation="horizontal">

<RadioButton
android:id="@+id/nav_memo"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="@string/memo"
app:drawableTopCompat="@drawable/ic_nav_memo"
android:layout_weight="1"
android:gravity="center"
android:textSize="@dimen/miniSize"
android:paddingTop="4dp"
app:drawableTint="@color/nav_check_color"
android:textColor="@color/nav_check_color"
android:button="@null"/>

<RadioButton
android:id="@+id/nav_statistics"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="@string/statistics"
android:drawableTop="@drawable/ic_nav_statistics"
android:layout_weight="1"
android:gravity="center"
android:textSize="@dimen/miniSize"
android:paddingTop="4dp"
android:button="@null"
app:drawableTint="@color/nav_check_color"
android:textColor="@color/nav_check_color"/>

<RadioButton
android:id="@+id/nav_learnCenter"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="@string/learnCenter"
app:drawableTopCompat="@drawable/ic_nav_learn_center"
android:layout_weight="1"
android:gravity="center"
android:textSize="@dimen/miniSize"
android:paddingTop="4dp"
android:button="@null"
app:drawableTint="@color/nav_check_color"
android:textColor="@color/nav_check_color"/>

<RadioButton
android:id="@+id/nav_serviceCenter"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="@string/memo"
app:drawableTopCompat="@drawable/ic_nav_memo"
android:layout_weight="1"
android:gravity="center"
android:textSize="@dimen/miniSize"
android:paddingTop="4dp"
android:button="@null"
app:drawableTint="@color/nav_check_color"
android:textColor="@color/nav_check_color"/>

<RadioButton
android:id="@+id/nav_my"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="@string/my"
app:drawableTopCompat="@drawable/ic_nav_my"
android:layout_weight="1"
android:gravity="center"
android:textSize="@dimen/miniSize"
android:paddingTop="4dp"
android:button="@null"
app:drawableTint="@color/nav_check_color"
android:textColor="@color/nav_check_color"/>

</RadioGroup>




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

+ 0
- 78
app/src/main/res/layout/activity_splash.xml View File

app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.6" /> app:layout_constraintVertical_bias="0.6" />


<Button
android:id="@+id/button5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="下一曲"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/button"
android:onClick="nextPlay"/>

<Button
android:id="@+id/button6"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="104dp"
android:layout_marginTop="8dp"
android:text="拖动"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/button"
android:onClick="seekTo"/>

<Button
android:id="@+id/button7"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="204dp"
android:layout_marginTop="8dp"
android:onClick="release"
android:text="释放"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/button" />

<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="24dp"
android:text="播放"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/img"
android:onClick="play"/>

<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:layout_marginTop="24dp"
android:text="暂停"
app:layout_constraintStart_toEndOf="@+id/button"
app:layout_constraintTop_toBottomOf="@+id/img"
android:onClick="pause"/>

<Button
android:id="@+id/button3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="24dp"
android:text="停止"
app:layout_constraintStart_toEndOf="@+id/button2"
app:layout_constraintTop_toBottomOf="@+id/img"
android:onClick="stop"/>

<Button
android:id="@+id/button4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:text="继续"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.555"
app:layout_constraintStart_toEndOf="@+id/button3"
app:layout_constraintTop_toBottomOf="@+id/img"
android:onClick="continuePlay"/>


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

+ 14
- 0
app/src/main/res/layout/fragment_course_pack.xml View File

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".module.m_center_learn.CoursePackFragment">

<!-- TODO: Update blank fragment layout -->
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="@string/hello_blank_fragment" />

</FrameLayout>

+ 63
- 10
app/src/main/res/layout/fragment_learn_center.xml View File

<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".module.m_center_learn.LearnCenterFragment">

<!-- TODO: Update blank fragment layout -->
<TextView
<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="viewmodel"
type="com.xkl.cdl.module.m_center_learn.LearnCenterFragmentViewModel" />
</data>

<LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:text="@string/hello_blank_fragment" />
android:background="@color/white"
android:orientation="vertical"
tools:context=".module.m_center_learn.LearnCenterFragment">

<com.google.android.material.tabs.TabLayout
android:id="@+id/tab_layout"
android:layout_width="match_parent"
android:layout_height="@dimen/title_bar_height"
android:layout_marginStart="16dp"
app:tabContentStart="4dp"
app:tabIndicatorHeight="0dp"
app:tabMode="scrollable"
app:tabRippleColor="@android:color/transparent"
app:tabMaxWidth="200dp"
app:tabMinWidth="10dp"
app:tabPaddingEnd="16dp"
app:tabPaddingStart="0dp"/>


<com.suliang.common.widget.InputSearchEditText
android:id="@+id/edit_text_search"
android:layout_width="match_parent"
android:layout_height="36dp"
android:layout_marginStart="16dp"
android:layout_marginTop="6dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="14dp"
android:background="@drawable/et_search_bg"
android:drawablePadding="4dp"
android:gravity="center_vertical"
android:hint="@string/search_hint_input_course_name"
android:maxLines="1"
android:singleLine="true"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:textColor="@color/main_text_color"
android:textSize="@dimen/normalSize"
android:focusable="true"
android:focusableInTouchMode="true"
/>



<androidx.viewpager2.widget.ViewPager2
android:id="@+id/view_pager_2"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white_1"
android:overScrollMode="never" />



</FrameLayout>
</LinearLayout>
</layout>

+ 14
- 0
app/src/main/res/layout/service_center_fragment.xml View File

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".module.m_service_center.ServiceCenterFragment">

<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="Hello" />

</FrameLayout>

+ 10
- 0
app/src/main/res/layout/textview_only.xml View File

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxLines="1"
android:gravity="bottom|center"
android:textSize="@dimen/normalSize"
android:textColor="@color/gray_2"
xmlns:tools="http://schemas.android.com/tools"
tools:text = "项目"/>

+ 1
- 4
app/src/main/res/values/attrs.xml View File

<resources> <resources>
<declare-styleable name="FullscreenAttrs">
<attr name="fullscreenBackgroundColor" format="color" />
<attr name="fullscreenTextColor" format="color" />
</declare-styleable>

</resources> </resources>

+ 10
- 1
app/src/main/res/values/colors.xml View File

<color name="teal_200">#FF03DAC5</color> <color name="teal_200">#FF03DAC5</color>
<color name="teal_700">#FF018786</color> <color name="teal_700">#FF018786</color>
<color name="black">#FF000000</color> <color name="black">#FF000000</color>
<color name="white">#FFFFFFFF</color>
<color name="light_blue_600">#FF039BE5</color> <color name="light_blue_600">#FF039BE5</color>
<color name="light_blue_900">#FF01579B</color> <color name="light_blue_900">#FF01579B</color>
<color name="light_blue_A200">#FF40C4FF</color> <color name="light_blue_A200">#FF40C4FF</color>
<color name="light_blue_A400">#FF00B0FF</color> <color name="light_blue_A400">#FF00B0FF</color>
<color name="black_overlay">#66000000</color> <color name="black_overlay">#66000000</color>


<color name="theme_color">#FF5082E6</color>
<color name="main_text_color">#323233</color>

<color name="gray_1">#FFE6E6E6</color>
<color name="gray_2">#8A8A99</color>
<color name="white">#FFFFFFFF</color>
<color name="white_1">#FFF5F5F5</color>
</resources> </resources>

+ 14
- 0
app/src/main/res/values/dimens.xml View File

<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="nav_bottom_height">50dp</dimen>
<dimen name="line_height">0.5dp</dimen>

<dimen name="miniSize">12dp</dimen>
<dimen name="smallSize">14dp</dimen>
<dimen name="normalSize">16dp</dimen>
<dimen name="bigSize">18dp</dimen>
<dimen name="biggerSize">20dp</dimen>
<dimen name="title_bar_height">48dp</dimen>


</resources>

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

<resources> <resources>
<string name="app_name">XklLocal</string>
<string name="dummy_button">Dummy Button</string>
<string name="dummy_content">DUMMY\nCONTENT</string>
<!-- TODO: Remove or change this placeholder text -->
<string name="app_name">学考乐本地版</string>

<string name="hello_blank_fragment">Hello blank fragment</string> <string name="hello_blank_fragment">Hello blank fragment</string>

<string name="memo">备忘本</string>
<string name="statistics">统计</string>
<string name="learnCenter">学习中心</string>
<string name="serviceCenter">服务中心</string>
<string name="my">我的</string>

<string name="project_english">英语</string>
<string name="project_chinese">语文</string>
<string name="search_hint_input_course_name">输入课程内容...</string>

</resources> </resources>

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

<resources> <resources>

</resources> </resources>

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

<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="23.272728dp"
android:viewportWidth="33"
android:viewportHeight="32">
<path
android:fillColor="#8A8A99"
android:fillType="evenOdd"
android:pathData="M18.1314,28.2353C18.5819,28.2353 18.9471,28.6005 18.9471,29.051C18.9471,29.5015 18.5819,29.8667 18.1314,29.8667L14.8686,29.8667C14.4181,29.8667 14.0529,29.5015 14.0529,29.051C14.0529,28.6005 14.4181,28.2353 14.8686,28.2353L18.1314,28.2353ZM20.5784,24.9725C21.0289,24.9725 21.3941,25.3377 21.3941,25.7882C21.3941,26.2387 21.0289,26.6039 20.5784,26.6039L12.4216,26.6039C11.9711,26.6039 11.6059,26.2387 11.6059,25.7882C11.6059,25.3377 11.9711,24.9725 12.4216,24.9725L20.5784,24.9725ZM16.5,7.0275C21.0049,7.0275 24.6569,10.6794 24.6569,15.1843C24.6569,19.6892 21.0049,23.3412 16.5,23.3412C11.9951,23.3412 8.3431,19.6892 8.3431,15.1843C8.3431,10.6794 11.9951,7.0275 16.5,7.0275ZM29.551,15.1843C30.0015,15.1843 30.3667,15.5495 30.3667,16C30.3667,16.4505 30.0015,16.8157 29.551,16.8157L27.9196,16.8157C27.4691,16.8157 27.1039,16.4505 27.1039,16C27.1039,15.5495 27.4691,15.1843 27.9196,15.1843L29.551,15.1843ZM5.0804,15.1843C5.5309,15.1843 5.8961,15.5495 5.8961,16C5.8961,16.4505 5.5309,16.8157 5.0804,16.8157L3.449,16.8157C2.9985,16.8157 2.6333,16.4505 2.6333,16C2.6333,15.5495 2.9985,15.1843 3.449,15.1843L5.0804,15.1843ZM26.3052,6.1948C26.6238,6.5133 26.6238,7.0298 26.3052,7.3483L25.1517,8.5019C24.8331,8.8204 24.3167,8.8204 23.9981,8.5019C23.6796,8.1833 23.6796,7.6669 23.9981,7.3483L25.1517,6.1948C25.4702,5.8762 25.9867,5.8762 26.3052,6.1948ZM7.8483,6.1948L9.0019,7.3483C9.3204,7.6669 9.3204,8.1833 9.0019,8.5019C8.6833,8.8204 8.1669,8.8204 7.8483,8.5019L6.6948,7.3483C6.3762,7.0298 6.3762,6.5133 6.6948,6.1948C7.0133,5.8762 7.5298,5.8762 7.8483,6.1948ZM16.5,2.1333C16.9505,2.1333 17.3157,2.4985 17.3157,2.949L17.3157,4.5804C17.3157,5.0309 16.9505,5.3961 16.5,5.3961C16.0495,5.3961 15.6843,5.0309 15.6843,4.5804L15.6843,2.949C15.6843,2.4985 16.0495,2.1333 16.5,2.1333Z"
android:strokeWidth="1"
android:strokeColor="#00000000" />
</vector>

+ 12
- 0
app/svg/drawable/ic_nav_memo.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="M6.3429,5.0857L6.3429,6.0286C6.3429,7.2436 7.3278,8.2286 8.5429,8.2286C9.7579,8.2286 10.7429,7.2436 10.7429,6.0286L10.7429,5.0857L13.2571,5.0857L13.2571,6.0286C13.2571,7.2436 14.2421,8.2286 15.4571,8.2286C16.6722,8.2286 17.6571,7.2436 17.6571,6.0286L17.6571,5.0857L19.5429,5.0857C20.2372,5.0857 20.8,5.6486 20.8,6.3429L20.8,18.9143C20.8,19.6086 20.2372,20.1714 19.5429,20.1714L4.4571,20.1714C3.7628,20.1714 3.2,19.6086 3.2,18.9143L3.2,6.3429C3.2,5.6486 3.7628,5.0857 4.4571,5.0857L6.3429,5.0857ZM16.7143,14.5143L7.2857,14.5143C6.765,14.5143 6.3429,14.9364 6.3429,15.4571C6.3429,15.9472 6.7168,16.35 7.1949,16.3957L7.2857,16.4L16.7143,16.4C17.235,16.4 17.6571,15.9779 17.6571,15.4571C17.6571,14.967 17.2832,14.5643 16.8051,14.5186L16.7143,14.5143ZM16.7143,10.6643L7.2857,10.6643C6.765,10.6643 6.3429,11.0864 6.3429,11.6071C6.3429,12.0972 6.7168,12.5 7.1949,12.5457L7.2857,12.55L16.7143,12.55C17.235,12.55 17.6571,12.1279 17.6571,11.6071C17.6571,11.117 17.2832,10.7143 16.8051,10.6686L16.7143,10.6643ZM8.5429,3.2C9.0636,3.2 9.4857,3.6221 9.4857,4.1429L9.4857,6.0286C9.4857,6.5121 9.1217,6.9106 8.6528,6.9651L8.5429,6.9714L8.5429,6.9714C8.0221,6.9714 7.6,6.5493 7.6,6.0286L7.6,4.1429C7.6,3.6221 8.0221,3.2 8.5429,3.2ZM14.5143,4.1429C14.5143,3.6221 14.9364,3.2 15.4571,3.2C15.9779,3.2 16.4,3.6221 16.4,4.1429L16.4,6.0286C16.4,6.5121 16.036,6.9106 15.5671,6.9651L15.4571,6.9714L15.4571,6.9714C14.9364,6.9714 14.5143,6.5493 14.5143,6.0286L14.5143,4.1429Z"
android:strokeWidth="1"
android:fillColor="#8A8A99"
android:fillType="evenOdd"
android:strokeColor="#00000000"/>
</vector>

+ 12
- 0
app/svg/drawable/ic_nav_my.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="M12,12C16.4183,12 20,15.5817 20,20C20,20.4418 19.6418,20.8 19.2,20.8L4.8,20.8C4.3922,20.8 4.0556,20.4948 4.0062,20.1003L4,20C4,15.5817 7.5817,12 12,12ZM12,3.2C14.2091,3.2 16,4.9909 16,7.2C16,9.4091 14.2091,11.2 12,11.2C9.7909,11.2 8,9.4091 8,7.2C8,4.9909 9.7909,3.2 12,3.2Z"
android:strokeWidth="1"
android:fillColor="#8A8A99"
android:fillType="evenOdd"
android:strokeColor="#00000000"/>
</vector>

+ 12
- 0
app/svg/drawable/ic_nav_service.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="M11.2,12.8L11.2,19.2C11.2,20.0837 10.4837,20.8 9.6,20.8L9.6,20.8L4.8,20.8C3.9163,20.8 3.2,20.0837 3.2,19.2L3.2,19.2L3.2,14.4C3.2,13.5163 3.9163,12.8 4.8,12.8L4.8,12.8L11.2,12.8ZM19.2,12.8C20.0837,12.8 20.8,13.5163 20.8,14.4L20.8,19.2C20.8,20.0837 20.0837,20.8 19.2,20.8L14.4,20.8C13.5163,20.8 12.8,20.0837 12.8,19.2L12.8,12.8L19.2,12.8ZM9.6,3.2C10.4837,3.2 11.2,3.9163 11.2,4.8L11.2,11.2L4.8,11.2C3.9163,11.2 3.2,10.4837 3.2,9.6L3.2,4.8C3.2,3.9163 3.9163,3.2 4.8,3.2L9.6,3.2ZM19.2,3.2C20.0837,3.2 20.8,3.9163 20.8,4.8L20.8,4.8L20.8,9.6C20.8,10.4837 20.0837,11.2 19.2,11.2L19.2,11.2L12.8,11.2L12.8,4.8C12.8,3.9163 13.5163,3.2 14.4,3.2L14.4,3.2Z"
android:strokeWidth="1"
android:fillColor="#8A8A99"
android:fillType="evenOdd"
android:strokeColor="#00000000"/>
</vector>

+ 12
- 0
app/svg/drawable/ic_nav_statistics.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="M21,19.2C21.6627,19.2 22.2,19.7373 22.2,20.4C22.2,21.0627 21.6627,21.6 21,21.6L3,21.6C2.3373,21.6 1.8,21.0627 1.8,20.4C1.8,19.7373 2.3373,19.2 3,19.2L21,19.2ZM7.2,9C7.8627,9 8.4,9.5373 8.4,10.2L8.4,16.8C8.4,17.4627 7.8627,18 7.2,18L4.8,18C4.1373,18 3.6,17.4627 3.6,16.8L3.6,10.2C3.6,9.5373 4.1373,9 4.8,9L7.2,9ZM13.2,2.4C13.8627,2.4 14.4,2.9373 14.4,3.6L14.4,16.8C14.4,17.4627 13.8627,18 13.2,18L10.8,18C10.1373,18 9.6,17.4627 9.6,16.8L9.6,3.6C9.6,2.9373 10.1373,2.4 10.8,2.4L13.2,2.4ZM19.2,7.2C19.8627,7.2 20.4,7.7373 20.4,8.4L20.4,16.8C20.4,17.4627 19.8627,18 19.2,18L16.8,18C16.1373,18 15.6,17.4627 15.6,16.8L15.6,8.4C15.6,7.7373 16.1373,7.2 16.8,7.2L19.2,7.2Z"
android:strokeWidth="1"
android:fillColor="#8A8A99"
android:fillType="evenOdd"
android:strokeColor="#00000000"/>
</vector>

+ 4
- 2
build.gradle View File

applicationId : "com.xkl.cdl" applicationId : "com.xkl.cdl"
] ]
versions = [ versions = [
core_ktx_version : "1.3.2",
core_ktx_version : "1.7.0",
appcompat_version: "1.4.1", appcompat_version: "1.4.1",
material_version : "1.3.0", material_version : "1.3.0",
lifecycle_version: "2.5.0-alpha02", lifecycle_version: "2.5.0-alpha02",
Glide : "com.github.bumptech.glide:glide:${versions.glide_version}", Glide : "com.github.bumptech.glide:glide:${versions.glide_version}",
GlideCompiler : "com.github.bumptech.glide:compiler:${versions.glide_version}", GlideCompiler : "com.github.bumptech.glide:compiler:${versions.glide_version}",
//Glide translation //Glide translation
GlideTranslation: "jp.wasabeef:glide-transformations:4.3.0"
GlideTranslation: "jp.wasabeef:glide-transformations:4.3.0",
//Activity_ktx Activity扩展
Activity_ktx : "androidx.activity:activity-ktx:1.4.0",
] ]





+ 5
- 1
lib/common/build.gradle View File

} }


dependencies { dependencies {
rootProject.ext.dependencies_required.each{ k,v -> implementation v}
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
rootProject.ext.dependencies_required.each{ k, v -> implementation v}
testImplementation rootProject.ext.dependencies_testImplementation.junit testImplementation rootProject.ext.dependencies_testImplementation.junit
rootProject.ext.dependencies_androidTestImplementation.each{ k,v -> androidTestImplementation v} rootProject.ext.dependencies_androidTestImplementation.each{ k,v -> androidTestImplementation v}


//glide translation //glide translation
api customDependencies.GlideTranslation api customDependencies.GlideTranslation


//Activity-ktx 扩展
api customDependencies.Activity_ktx





} }

+ 13
- 0
lib/common/src/main/java/com/suliang/common/Config.kt View File

package com.suliang.common

/**
* author suliang
* create 2022/3/17 17:04
* Describe:
*/
object Config {
const val INTENT_1 = "intent_1"
const val INTENT_2 = "intent_2"
const val INTENT_3 = "intent_3"
const val INTENT_4 = "intent_4"
}

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

package com.suliang.common.base

import android.graphics.Color
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.DialogFragment
import androidx.viewbinding.ViewBinding
import com.suliang.common.extension.initBinding
import android.graphics.drawable.ColorDrawable

import android.util.DisplayMetrics




/**
* author suliang
* create 2022/3/17 16:30
* Describe:
*/
abstract class BaseDialogFragment<VB : ViewBinding> : DialogFragment() {
private var _binding: VB? = null

val binding: VB
get() = _binding!!

override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
): View? {
_binding = initBinding(inflater, container)
return binding.root
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
requireDialog().apply {
setCanceledOnTouchOutside(false) // 点击屏幕不消失
setCancelable(false) //返回键不取消
}
initFragment()
}

override fun onStart() {
super.onStart()
if (isTransparent()){
//设置背景透明
dialog!!.window!!.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
}
}


abstract fun initFragment()

/** 是否布局背景透明 */
abstract fun isTransparent():Boolean
}

+ 38
- 0
lib/common/src/main/java/com/suliang/common/base/LoadingDialog.kt View File

package com.suliang.common.base

import android.graphics.drawable.AnimationDrawable
import com.suliang.common.Config
import com.suliang.common.databinding.LoadingFragmentBinding

/**
* author suliang
* create 2022/3/17 15:53
* Describe: 加载等待弹窗
*/
class LoadingDialog : BaseDialogFragment<LoadingFragmentBinding>() {

companion object{
@JvmStatic
fun newInstance(msg : String): LoadingDialog {
return LoadingDialog().apply {
arguments?.putString(Config.INTENT_1,msg)
}
}
}

override fun initFragment() {
//外部设置
arguments?.getString(Config.INTENT_1,null)?.let {
binding.loadText.text = it
}

//开始动画
(binding.loadImage.drawable as AnimationDrawable).start()
}

override fun isTransparent(): Boolean {
return true
}


}

+ 26
- 0
lib/common/src/main/java/com/suliang/common/base/ViewBehavior.kt View File

package com.suliang.common.base

import com.suliang.common.base.activity.ToastEvent

/**
* author suliang
* create 2022/3/17 11:41
* Describe: 页面常用操作行为
*/
interface ViewBehavior {
/** 是否显示视图 */
fun showHideLoading(isShow: Boolean)

/** 显示toast */
fun showToast(msg: ToastEvent)

/** 无参数跳转activity */
fun startActivity(clazz: Class<*>)


/** 返回键点击*/
// fun backPress(arg: Any?);
/** 关闭页面 */
// fun finishPage(arg: Any?)

}

+ 79
- 2
lib/common/src/main/java/com/suliang/common/base/activity/BaseActivity.kt View File

package com.suliang.common.base.activity package com.suliang.common.base.activity


import android.content.Intent
import android.graphics.Color import android.graphics.Color
import android.os.Bundle import android.os.Bundle
import android.widget.Toast
import androidx.annotation.StringRes
import androidx.viewbinding.ViewBinding import androidx.viewbinding.ViewBinding
import com.suliang.common.base.LoadingDialog
import com.suliang.common.extension.initBinding import com.suliang.common.extension.initBinding
import com.suliang.common.util.ActivityStackManager import com.suliang.common.util.ActivityStackManager
import com.zackratos.ultimatebarx.ultimatebarx.statusBarOnly import com.zackratos.ultimatebarx.ultimatebarx.statusBarOnly
import com.suliang.common.base.ViewBehavior
import com.suliang.common.util.LogUtil



/** /**
* 基类Activity * 基类Activity
*/ */
abstract class BaseActivity<VB : ViewBinding> : LifecycleLogActivity() {
abstract class BaseActivity<VB : ViewBinding> : LifecycleLogActivity(), ViewBehavior {


private var _binding: VB? = null private var _binding: VB? = null


val binding : VB
val binding: VB
get() = _binding!! get() = _binding!!


// val binding : VB by lazy {
// initViewBinding()
// }

override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
//入栈 //入栈
/** onCreate()最后实现的数据加载调用 */ /** onCreate()最后实现的数据加载调用 */
abstract fun loadData() abstract fun loadData()


private val loadingDialog by lazy {
LoadingDialog()
}

/** toast提示 */
override fun showToast(event: ToastEvent) {
val showTime = if (event.showLong) Toast.LENGTH_LONG else Toast.LENGTH_LONG
event.content?.let {
Toast.makeText(this, it, showTime).show()
} ?: let {
Toast.makeText(this, event.contentResId!!, showTime).show()
}
}

protected fun showToast(text: String, showLong: Boolean = false) {
showToast(ToastEvent(content = text, showLong = showLong))
}

protected fun showToast(@StringRes resId: Int, showLong: Boolean = false) {
showToast(ToastEvent(contentResId = resId, showLong = showLong))
}

override fun showHideLoading(isShow: Boolean) {
if (isShow) {
loadingDialog.show(supportFragmentManager, javaClass.name)
} else if (loadingDialog.activity != null){
loadingDialog.dismiss()
}
}

override fun startActivity(clazz: Class<*>) {
startActivity(Intent(this,clazz))
}


// 反射实现 ViewBinding // 反射实现 ViewBinding
// @SuppressWarnings("unchecked") // @SuppressWarnings("unchecked")
// fun initBinding(inflater: LayoutInflater): VB { // fun initBinding(inflater: LayoutInflater): VB {
// return inflate.invoke(null, inflater) as VB // return inflate.invoke(null, inflater) as VB
// } // }


// https://juejin.cn/post/6926007534188773384#heading-1
// private fun initViewBinding(): VB{
// return reflexViewBinding(this::class.java,layoutInflater)
// }
// private fun <V : ViewBinding?> reflexViewBinding(aClass: Class<*>, from: LayoutInflater?): V {
// return try {
// val genericSuperclass: Type = aClass.genericSuperclass
// if (genericSuperclass is ParameterizedType) {
// val actualTypeArguments: Array<Type> =
// (Objects.requireNonNull(genericSuperclass) as ParameterizedType).getActualTypeArguments()
// for (actualTypeArgument in actualTypeArguments) {
// var tClass: Class<*>
// tClass = try {
// actualTypeArgument as Class<*>
// } catch (e: Exception) {
// continue
// }
// if (ViewBinding::class.java.isAssignableFrom(tClass)) {
// val inflate: Method = tClass.getMethod("inflate", LayoutInflater::class.java)
// return inflate.invoke(null, from) as V
// }
// }
// }
// reflexViewBinding(aClass.superclass, from)
// } catch (e: Exception) {
// e.printStackTrace()
// throw RuntimeException(e.message, e)
// }
// }


} }

+ 20
- 9
lib/common/src/main/java/com/suliang/common/base/activity/BaseActivityVM.kt View File

package com.suliang.common.base.activity package com.suliang.common.base.activity


import android.os.Bundle
import androidx.databinding.ViewDataBinding
import androidx.lifecycle.ViewModel
import androidx.viewbinding.ViewBinding import androidx.viewbinding.ViewBinding
import com.suliang.common.base.viewmodel.BaseViewModel


/** /**
* Activity DataBinding 与 ViewModel基类,封装DataBinding和ViewModel * Activity DataBinding 与 ViewModel基类,封装DataBinding和ViewModel
* @property VB : ViewDataBinding * @property VB : ViewDataBinding
* @property VM: ViewModel * @property VM: ViewModel
*/ */
abstract class BaseActivityVM<VB : ViewDataBinding, VM:ViewModel> : BaseActivity<VB>() {
//abstract class BaseActivityVM<VB : ViewDataBinding, VM : AndroidViewModel> : BaseActivity<VB>() {
abstract class BaseActivityVM<VB : ViewBinding, VM : BaseViewModel> : BaseActivity<VB>() {


private lateinit var vm : VM
lateinit var vm: VM
private set


override fun initFirst() {

override fun setLayoutBefore() {
super.setLayoutBefore()
vm = initViewModel() vm = initViewModel()
super.initFirst()
binding.lifecycleOwner = this
} }


abstract fun initViewModel() : VM
override fun setLayoutAfter() {
super.setLayoutAfter()
lifecycle.addObserver(vm)

vm.pageEvent.observe(this) { startActivity(it) }
vm.toastEvent.observe(this){ showToast(it) }
vm.loadingEvent.observe(this) { showHideLoading(it)}

}

abstract fun initViewModel(): VM



} }

+ 14
- 0
lib/common/src/main/java/com/suliang/common/base/activity/ToastEvent.kt View File

package com.suliang.common.base.activity

import androidx.annotation.StringRes

/**
* author suliang
* create 2022/3/17 15:07
* Describe:
*/
data class ToastEvent(
var content: String? = null, //Toast字符串
@StringRes var contentResId: Int? = null, //Toast字符串
var showLong: Boolean = false //是否长时间显示,默认false)
)

+ 47
- 6
lib/common/src/main/java/com/suliang/common/base/fragment/BaseFragment.kt View File

package com.suliang.common.base.fragment package com.suliang.common.base.fragment


import android.content.Intent
import android.os.Bundle import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.Toast
import androidx.annotation.StringRes
import androidx.databinding.ViewDataBinding import androidx.databinding.ViewDataBinding
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.viewbinding.ViewBinding
import com.suliang.common.base.LoadingDialog
import com.suliang.common.base.ViewBehavior
import com.suliang.common.base.activity.ToastEvent
import com.suliang.common.extension.initBinding import com.suliang.common.extension.initBinding


/** /**
* *
* @property VB : ViewDataBinding * @property VB : ViewDataBinding
*/ */
abstract class BaseFragment<VB : ViewDataBinding> : Fragment() {
abstract class BaseFragment<VB : ViewBinding> : Fragment(),ViewBehavior {


private var _binding: VB? = null private var _binding: VB? = null


val binding : VB
val binding: VB
get() = _binding!! get() = _binding!!


//是否加载数据 //是否加载数据
private var isLoaded = false private var isLoaded = false


override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
): View? { ): View? {
_binding = initBinding(inflater, container) _binding = initBinding(inflater, container)
return super.onCreateView(inflater, container, savedInstanceState)
return binding.root
} }


override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
*/ */
abstract fun loadData() abstract fun loadData()




private val loadingDialog by lazy {
LoadingDialog()
}

/** toast提示 */
override fun showToast(event: ToastEvent) {
val showTime = if (event.showLong) Toast.LENGTH_LONG else Toast.LENGTH_LONG
event.content?.let {
Toast.makeText(requireContext(), it, showTime).show()
} ?: let {
Toast.makeText(requireContext(), event.contentResId!!, showTime).show()
}
}

protected fun showToast(text: String, showLong: Boolean = false) {
showToast(ToastEvent(content = text, showLong = showLong))
}

protected fun showToast(@StringRes resId: Int, showLong: Boolean = false) {
showToast(ToastEvent(contentResId = resId, showLong = showLong))
}

override fun showHideLoading(isShow: Boolean) {
if (isShow) {
loadingDialog.show(childFragmentManager, javaClass.name)
} else if (loadingDialog.activity != null){
loadingDialog.dismiss()
}
}

override fun startActivity(clazz: Class<*>) {
startActivity(Intent(requireActivity(),clazz))
}

} }

+ 8
- 3
lib/common/src/main/java/com/suliang/common/base/fragment/BaseFragmentVM.kt View File



import androidx.databinding.ViewDataBinding import androidx.databinding.ViewDataBinding
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.viewbinding.ViewBinding
import com.suliang.common.base.viewmodel.BaseViewModel


/** /**
* Fragment DataBinding 与 ViewModel基类,封装DataBinding和ViewModel 自带懒加载 * Fragment DataBinding 与 ViewModel基类,封装DataBinding和ViewModel 自带懒加载
* @property VB : ViewDataBinding * @property VB : ViewDataBinding
* @property VM: ViewModel * @property VM: ViewModel
*/ */
abstract class BaseFragmentVM<VB : ViewDataBinding, VM : ViewModel> : BaseFragment<VB>() {
lateinit var viewModel: VM
abstract class BaseFragmentVM<VB : ViewBinding, VM : BaseViewModel> : BaseFragment<VB>() {
lateinit var vm: VM


override fun initFirst() { override fun initFirst() {
viewModel = initViewModel()
vm = initViewModel()
vm.pageEvent.observe(this) { startActivity(it) }
vm.toastEvent.observe(this){ showToast(it) }
vm.loadingEvent.observe(this) { showHideLoading(it)}
} }


abstract fun initViewModel(): VM abstract fun initViewModel(): VM

+ 4
- 4
lib/common/src/main/java/com/suliang/common/base/fragment/LifecycleLogFragment.kt View File

LogUtil.d("onViewCreated") LogUtil.d("onViewCreated")
} }


override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
LogUtil.d("onActivityCreated")
}
// override fun onActivityCreated(savedInstanceState: Bundle?) {
// super.onActivityCreated(savedInstanceState)
// LogUtil.d("onActivityCreated")
// }


override fun onStart() { override fun onStart() {
super.onStart() super.onStart()

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

package com.suliang.common.base.viewmodel

import android.widget.Toast
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import com.suliang.common.base.ViewBehavior
import com.suliang.common.base.activity.ToastEvent
import com.suliang.common.util.LogUtil

/**
* author suliang
* create 2022/3/17 11:03
* Describe:
*/
open class BaseViewModel : ViewModel(), ViewModelLifecycle, ViewBehavior {
override fun onCreate(owner: LifecycleOwner) {
super.onCreate(owner)
LogUtil.i("${javaClass.name} onCreate() ")
}

override fun onStart(owner: LifecycleOwner) {
super.onStart(owner)
LogUtil.i("${javaClass.name} onStart() ")
}

override fun onResume(owner: LifecycleOwner) {
super.onResume(owner)
LogUtil.i("${javaClass.name} onResume() ")
}

override fun onPause(owner: LifecycleOwner) {
super.onPause(owner)
LogUtil.i("${javaClass.name} onPause() ")
}

override fun onStop(owner: LifecycleOwner) {
super.onStop(owner)
LogUtil.i("${javaClass.name} onStop() ")
}

override fun onDestroy(owner: LifecycleOwner) {
super.onDestroy(owner)
LogUtil.i("${javaClass.name} onDestroy() ")
}

override fun onCleared() {
super.onCleared()
LogUtil.i("${javaClass.name} onCleared() ")
}

var loadingEvent = MutableLiveData<Boolean>()
private set

var toastEvent = MutableLiveData<ToastEvent>()
private set

var pageEvent = MutableLiveData<Class<*>>()
private set

override fun showHideLoading(isShow: Boolean) {
loadingEvent.postValue(isShow)
}

override fun showToast(msg: ToastEvent) {
toastEvent.postValue(msg)
}

override fun startActivity(clazz: Class<*>) {
pageEvent.postValue(clazz)
}

}


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

package com.suliang.common.base.viewmodel

import androidx.lifecycle.DefaultLifecycleObserver

/**
* author suliang
* create 2022/3/17 11:22
* Describe: ViewModel生命周期 与 Activity/Fragment同步
*/
interface ViewModelLifecycle : DefaultLifecycleObserver {

}

+ 79
- 0
lib/common/src/main/java/com/suliang/common/eventbus/LiveDataBus.kt View File

package com.suliang.common.eventbus

import androidx.lifecycle.MutableLiveData

/**
* author suliang
* create 2022/3/15 10:01
* Describe: 事件总线,这条总线把任何类中的数据直接传递到activity 或是 fragment 上
*/
object LiveDataBus {

private val bus = mutableMapOf<String,MutableLiveData<Any>>()

// /**
// * 注册订阅者
// * @param key String key
// * @param type Class<T> 类型
// * @param sticky Boolean 是否需要粘性,true:需要 false:不需要
// * @return MutableLiveData<T>
// */
// @Synchronized
// fun <T> with(key: String, type: Class<T>, sticky: Boolean): MutableLiveData<T>{
// if (!bus.containsKey(key)) {
// bus[key] = if (sticky) MutableLiveData<Any>() else NonStickyMutableLiveData<Any>()
// }
// return bus[key] as MutableLiveData<T>
// }

//java使用传入泛型class, kotlin使用可直接传入泛型,不需要class类型

@SuppressWarnings("UNCHECKED_CAST")
@Synchronized
fun <T> with(key:String) : MutableLiveData<T>{
if (!bus.containsKey(key)){
bus[key] = MutableLiveData()
}
return bus[key] as MutableLiveData<T>
}
@SuppressWarnings("UNCHECKED_CAST")
@Synchronized
fun <T> withNonSticky(key:String) : MutableLiveData<T>{
if (!bus.containsKey(key)){
bus[key] = NonStickyMutableLiveData()
}
return bus[key] as MutableLiveData<T>
}



@SuppressWarnings("UNCHECKED_CAST")
@Synchronized
fun <T> with(key:String,type: Class<T>) : MutableLiveData<T>{
if (!bus.containsKey(key)){
bus[key] = MutableLiveData()
}
return bus[key] as MutableLiveData<T>
}
@SuppressWarnings("UNCHECKED_CAST")
@Synchronized
fun <T> withNonSticky(key:String,type: Class<T>) : MutableLiveData<T>{
if (!bus.containsKey(key)){
bus[key] = NonStickyMutableLiveData()
}
return bus[key] as MutableLiveData<T>
}

fun remove(key:String){
bus.remove(key)
}


fun clearAll(){
bus.clear()
}




}

+ 65
- 0
lib/common/src/main/java/com/suliang/common/eventbus/NonStickyMutableLiveData.kt View File

package com.suliang.common.eventbus

import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.Observer
import java.lang.Exception
import java.lang.NullPointerException
import java.lang.reflect.Method

/**
* author suliang
* create 2022/3/15 10:51
* Describe: 非粘性LiveData
*/
class NonStickyMutableLiveData<T> : MutableLiveData<T>() {

private var stickFlag : Boolean = false

override fun observe(owner: LifecycleOwner, observer: Observer<in T>) {
super.observe(owner, observer)
if (!stickFlag){
hook(observer)
stickFlag = true
}
}

private fun hook(observer: Observer<in T>) = try {
//得到 mLastVersion
//获取到LiveData的类中的mObserver对象
// SafeIterableMap<Observer<? super T> , ObserverWrapper> mObservers
val liveDataClass = LiveData::class.java
val declaredField = liveDataClass.getDeclaredField("mObservers")
declaredField.isAccessible = true
//获取到这个成员变量的对象
val mObserVersObject = declaredField.get(this)
//得到map对应的class对象
val mObserversClass = mObserVersObject.javaClass
//获取到mObservers对象的get方法
val get:Method = mObserversClass.getDeclaredMethod("get", Any::class.java)
get.isAccessible = true
//执行get方法,获取到对象
val invokeEntry = get.invoke(mObserVersObject, observer)
//定义一个空的对象
val observerWrapper = if (invokeEntry is Map.Entry<*, *>) {
invokeEntry.value
} else throw NullPointerException("observerWrapper is null")

//得到observerWrapper的对象,编译擦除问题会引起多态冲突,所以用getSupperClass
//getClass 返回对应的当前正在运行是的类所对应的
val mLastVersion = observerWrapper!!::class.java.superclass.getDeclaredField("mLastVersion")
mLastVersion.isAccessible = true
//得到mVersion
val mVersion = liveDataClass.getDeclaredField("mVersion")
mVersion.isAccessible = true
//把mVersion数据填入到mLastVersion中
val mVersionValue = mVersion.get(this)
mLastVersion.set(observerWrapper,mVersionValue)

}catch (e: Exception){
e.printStackTrace()
}


}

+ 8
- 0
lib/common/src/main/java/com/suliang/common/extension/ActivityFragmentExtension.kt View File

package com.suliang.common.extension package com.suliang.common.extension


import android.content.Intent
import androidx.annotation.IdRes import androidx.annotation.IdRes
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity import androidx.fragment.app.FragmentActivity
*/ */


/*----------------------------------Activity Start-------------------------------------*/ /*----------------------------------Activity Start-------------------------------------*/

fun <T> FragmentActivity.startActivity(newActivityClass:Class<T>){
this.startActivity(Intent(this,newActivityClass))
}



/** /**
* Activity 级别 加载Fragment集合进入容器,并显示 * Activity 级别 加载Fragment集合进入容器,并显示
* @receiver FragmentActivity * @receiver FragmentActivity

+ 4
- 4
lib/common/src/main/java/com/suliang/common/extension/BindingExtension.kt View File

* @param vbPosition Int 在超类泛型中的vb位置 * @param vbPosition Int 在超类泛型中的vb位置
* @return VB * @return VB
*/ */
@SuppressWarnings("unchecked")
@SuppressWarnings("UNCHECKED_CAST")
inline fun <VB : ViewBinding> Any.initBinding(inflater: LayoutInflater,vbPosition:Int = 0): VB { inline fun <VB : ViewBinding> Any.initBinding(inflater: LayoutInflater,vbPosition:Int = 0): VB {
val vbClass = val vbClass =
(javaClass.genericSuperclass as ParameterizedType).actualTypeArguments.filterIsInstance<Class<VB>>() (javaClass.genericSuperclass as ParameterizedType).actualTypeArguments.filterIsInstance<Class<VB>>()
* @param vbPosition Int * @param vbPosition Int
* @return VB * @return VB
*/ */
@SuppressWarnings("unchecked")
@SuppressWarnings("UNCHECKED_CAST")
inline fun <VB: ViewBinding> Any.initBinding(inflater: LayoutInflater, container:ViewGroup?,vbPosition:Int = 0):VB{ inline fun <VB: ViewBinding> Any.initBinding(inflater: LayoutInflater, container:ViewGroup?,vbPosition:Int = 0):VB{
val vbClass = (javaClass.genericSuperclass as ParameterizedType).actualTypeArguments.filterIsInstance<Class<VB>>() val vbClass = (javaClass.genericSuperclass as ParameterizedType).actualTypeArguments.filterIsInstance<Class<VB>>()
val inflater = vbClass[vbPosition].getDeclaredMethod("inflate",LayoutInflater::class.java,ViewGroup::class.java,Boolean::class.java)
return inflater.invoke(null,inflater,container,false) as VB
val inflate = vbClass[vbPosition].getDeclaredMethod("inflate",LayoutInflater::class.java,ViewGroup::class.java,Boolean::class.java)
return inflate.invoke(null,inflater,container,false) as VB
} }

+ 28
- 0
lib/common/src/main/java/com/suliang/common/extension/ImageViewExtension.kt View File

package com.suliang.common.extension

import android.net.Uri
import android.widget.ImageView
import com.suliang.common.util.image.ImageLoader
import com.suliang.common.util.image.ImageLoaderOption
import java.io.File

/**
* author suliang
* create 2022/3/15 9:48
* Describe: 图片加载扩展
*/
fun ImageView.loadImage(option:ImageLoaderOption){
ImageLoader.loadImage(option)
}
fun ImageView.loadImage(url: String){
ImageLoader.loadImage(this,url)
}
fun ImageView.loadImage(file: File){
ImageLoader.loadImage(this,file)
}
fun ImageView.loadImage(resourceId:Int){
ImageLoader.loadImage(this,resourceId)
}
fun ImageView.loadImage(uri: Uri){
ImageLoader.loadImage(this,uri)
}

+ 5
- 5
lib/common/src/main/java/com/suliang/common/util/LogUtil.kt View File

fun v(message: String) { fun v(message: String) {
if (!LogEnable) return if (!LogEnable) return
val stackTrace = Throwable().stackTrace[1] val stackTrace = Throwable().stackTrace[1]
Log.v(stackTrace.fileName,createLog(stackTrace,message))
Log.v(stackTrace.className,createLog(stackTrace,message))
} }


fun d(message: String) { fun d(message: String) {
if (!LogEnable) return if (!LogEnable) return
val stackTrace = Throwable().stackTrace[1] val stackTrace = Throwable().stackTrace[1]
Log.d(stackTrace.fileName,createLog(stackTrace,message))
Log.d(stackTrace.className,createLog(stackTrace,message))
} }


fun e(message: String) { fun e(message: String) {
if (!LogEnable) return if (!LogEnable) return
val stackTrace = Throwable().stackTrace[1] val stackTrace = Throwable().stackTrace[1]
Log.e(stackTrace.fileName,createLog(stackTrace,message))
Log.e(stackTrace.className,createLog(stackTrace,message))
} }


fun i(message: String) { fun i(message: String) {
if (!LogEnable) return if (!LogEnable) return
val stackTrace = Throwable().stackTrace[1] val stackTrace = Throwable().stackTrace[1]
Log.i(stackTrace.fileName,createLog(stackTrace,message))
Log.i(stackTrace.className,createLog(stackTrace,message))
} }


fun w(message: String) { fun w(message: String) {
if (!LogEnable) return if (!LogEnable) return
val stackTrace = Throwable().stackTrace[1] val stackTrace = Throwable().stackTrace[1]
Log.w(stackTrace.fileName,createLog(stackTrace,message))
Log.w(stackTrace.className,createLog(stackTrace,message))
} }
} }

+ 3
- 3
lib/common/src/main/java/com/suliang/common/util/file/FileUtil.kt View File

*/ */
private fun writeStream(inputStream: InputStream, outputStream: OutputStream) { private fun writeStream(inputStream: InputStream, outputStream: OutputStream) {
try { try {
var len = 0
var len: Int
val buffer: ByteArray = ByteArray(1024) val buffer: ByteArray = ByteArray(1024)
while ((inputStream.read(buffer).also { len = it }) != -1) { while ((inputStream.read(buffer).also { len = it }) != -1) {
outputStream.write(buffer, 0, len) outputStream.write(buffer, 0, len)
try { try {
val fileInputStream = FileInputStream(file) val fileInputStream = FileInputStream(file)
val outputStream = ByteArrayOutputStream() val outputStream = ByteArrayOutputStream()
var len = 0
var len: Int
var byteArray = ByteArray(1024) var byteArray = ByteArray(1024)
while (fileInputStream.read(byteArray).also { len = it } != -1) { while (fileInputStream.read(byteArray).also { len = it } != -1) {
outputStream.write(byteArray, 0, len) outputStream.write(byteArray, 0, len)
// 使用默认缓冲区大小创建新的输入流 // 使用默认缓冲区大小创建新的输入流
val gzip = GZIPInputStream(inputStream) val gzip = GZIPInputStream(inputStream)
val buffer = ByteArray(256) val buffer = ByteArray(256)
var n = 0
var n:Int
// 将未压缩数据读入字节数组 // 将未压缩数据读入字节数组
while (gzip.read(buffer).also { n = it } >= 0) { while (gzip.read(buffer).also { n = it } >= 0) {
out.write(buffer, 0, n) out.write(buffer, 0, n)

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

* Describe: Glide 加载的具体实现 * Describe: Glide 加载的具体实现
* https://juejin.cn/post/6844903463134953479#heading-3 * https://juejin.cn/post/6844903463134953479#heading-3
*/ */
class GlideLoaderStrategy : IBaseLoaderStrategy {
internal class GlideLoaderStrategy : IBaseLoaderStrategy {


override fun clearMemoryCache() { override fun clearMemoryCache() {
Glide.get(AppGlobals.application).clearMemory() Glide.get(AppGlobals.application).clearMemory()

+ 8
- 2
lib/common/src/main/java/com/suliang/common/util/image/ImageLoader.kt View File

* create 2022/3/11 16:10 * create 2022/3/11 16:10
* Describe: 外部调用,图片加载库 * Describe: 外部调用,图片加载库
* *
* 使用: ImageLoader.load(url).into(View)
*
* 顺序判断,自动限制,前面参数有值了,则后面的值无效,如果都没有值,则抛异常 * 顺序判断,自动限制,前面参数有值了,则后面的值无效,如果都没有值,则抛异常
* url > file > drawableRes > uri * url > file > drawableRes > uri
* *
* https://www.jianshu.com/p/19420b151507 * https://www.jianshu.com/p/19420b151507
* https://blog.csdn.net/EthanCo/article/details/102587193 * https://blog.csdn.net/EthanCo/article/details/102587193
* https://www.jianshu.com/p/e26130a93289 * https://www.jianshu.com/p/e26130a93289
*
* 使用:
* ImageLoader.loadImage(option)
* ImageLoader.loadImage(view,source)
* ImageLoaderOption : 为加载的参数配置,必须要有上下文或者targetView,暂时没有设置listener监听和目标target,如果后期有使用,再在此类中进行配置,并在对应的strategy中进行实现
*
*
*
*/ */
object ImageLoader { object ImageLoader {



+ 110
- 0
lib/common/src/main/java/com/suliang/common/widget/InputSearchEditText.kt View File

package com.suliang.common.widget

import android.annotation.SuppressLint
import android.content.Context
import android.graphics.Color
import android.graphics.Rect
import android.graphics.drawable.Drawable
import android.util.AttributeSet
import android.view.MotionEvent
import android.view.inputmethod.EditorInfo
import androidx.appcompat.widget.AppCompatEditText
import androidx.core.content.res.ResourcesCompat
import com.suliang.common.R
import com.suliang.common.util.os.KeyboardUtil

/**
* author suliang
* create 2022/3/16 18:07
* Describe: 带关闭按钮的输入框 : 左侧为搜索图标, 右侧为删除图标 ,需自动设置监听改变
*/

@SuppressLint("UseCompatLoadingForDrawables")
class InputSearchEditText @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null,
defStyleAttr: Int = 0) :
AppCompatEditText(context, attrs, defStyleAttr) {

private val clearRect by lazy { Rect() }
private var ic_delete_src: Int = 0
private var ic_delete_color: Int = 0
private var ic_search_src: Int = 0
private var ic_search_color: Int = 0

private var drawableStart: Drawable? = null
private var drawableEnd: Drawable? = null

init {
attrs?.let {
context.obtainStyledAttributes(attrs, R.styleable.InputSearchEditText, defStyleAttr, 0).let {
ic_search_src = it.getResourceId(R.styleable.InputSearchEditText_ic_search_src, R.drawable.ic_search)
ic_search_color =
it.getColor(R.styleable.InputSearchEditText_ic_search_color, Color.parseColor("#8A8A8A"))
ic_delete_color =
it.getColor(R.styleable.InputSearchEditText_ic_delete_color, Color.parseColor("#8A8A8A"))
ic_delete_src = it.getColor(R.styleable.InputSearchEditText_ic_delete_src, R.drawable.ic_delete)
it.recycle()
drawableStart = resources.getDrawable(ic_search_src, null).apply {
setTint(ic_search_color)
}
setCompoundDrawablesWithIntrinsicBounds(drawableStart, null, null, null)
drawableEnd = resources.getDrawable(ic_delete_src, null).apply {
setTint(ic_delete_color)
}
}
}
}

override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
super.onSizeChanged(w, h, oldw, oldh)
//计算删除按钮所在的矩形区域
clearRect.apply {
left = w - paddingRight - w.coerceAtMost(h)
top = paddingTop
right = w - paddingRight
bottom = w.coerceAtLeast(h)
}
}

override fun onFocusChanged(focused: Boolean, direction: Int, previouslyFocusedRect: Rect?) {
super.onFocusChanged(focused, direction, previouslyFocusedRect)
checkEditFocus(focused)
}

/** 根据焦点改变,显示对应的图标内容
* @param focused Boolean 有焦点为true 否则false
*/
@SuppressLint("UseCompatLoadingForDrawables")
private fun checkEditFocus(focused: Boolean) {
if (text.isNullOrEmpty() || !focused) { //如果没有内容 或者没有焦点,则设置搜索图标
setCompoundDrawablesWithIntrinsicBounds(drawableStart, null, null, null)
} else {
setCompoundDrawablesRelativeWithIntrinsicBounds(drawableStart, null, drawableEnd, null)
}
}

override fun onTextChanged(text: CharSequence?, start: Int, lengthBefore: Int, lengthAfter: Int) {
super.onTextChanged(text, start, lengthBefore, lengthAfter)
//时刻监听
checkEditFocus(true)
}

@SuppressLint("ClickableViewAccessibility")
override fun onTouchEvent(event: MotionEvent): Boolean {
if (event.action == MotionEvent.ACTION_DOWN && isFocused && clearRect.contains(event.x.toInt(),event.y.toInt()) && text.isNullOrEmpty()){
setText("")
return true
}
return super.onTouchEvent(event)
}

override fun onEditorAction(actionCode: Int) {
if (actionCode == EditorInfo.IME_ACTION_SEARCH){
KeyboardUtil.hideKeyboard(this)
}
super.onEditorAction(actionCode)
}




}

+ 12
- 0
lib/common/src/main/res/drawable/ic_delete.xml View File

<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="14dp"
android:height="14dp"
android:viewportWidth="14"
android:viewportHeight="14">
<path
android:pathData="M10.8631,3.3702C11.0324,3.5394 11.0445,3.8063 10.8994,3.9894L10.8631,4.0302L7.8933,7L10.8631,9.9698C11.0454,10.1521 11.0454,10.4476 10.8631,10.6298C10.6939,10.799 10.4271,10.8111 10.2439,10.6661L10.2032,10.6298L7.2333,7.66L4.2635,10.6298C4.0812,10.8121 3.7858,10.8121 3.6035,10.6298C3.4343,10.4606 3.4222,10.1937 3.5673,10.0106L3.6035,9.9698L6.5734,7L3.6035,4.0302C3.4213,3.8479 3.4213,3.5524 3.6035,3.3702C3.7727,3.201 4.0396,3.1889 4.2228,3.3339L4.2635,3.3702L7.2333,6.34L10.2032,3.3702C10.3854,3.1879 10.6809,3.1879 10.8631,3.3702Z"
android:strokeWidth="1"
android:fillColor="#8A8A99"
android:fillType="evenOdd"
android:strokeColor="#00000000"/>
</vector>

+ 12
- 0
lib/common/src/main/res/drawable/ic_search.xml View File

<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="18dp"
android:height="18dp"
android:viewportWidth="18"
android:viewportHeight="18">
<path
android:pathData="M7.8,1.8C11.1137,1.8 13.8,4.4863 13.8,7.8C13.8,9.2455 13.2888,10.5716 12.4374,11.6075C12.451,11.6139 12.4631,11.6227 12.4749,11.6321L12.5272,11.6787L15.9213,15.0728C16.1556,15.3071 16.1556,15.687 15.9213,15.9213C15.7037,16.1389 15.3606,16.1544 15.1251,15.9679L15.0728,15.9213L11.6787,12.5272C11.6509,12.4995 11.6265,12.4697 11.6053,12.4384C10.5708,13.2892 9.245,13.8 7.8,13.8C4.4863,13.8 1.8,11.1137 1.8,7.8C1.8,4.4863 4.4863,1.8 7.8,1.8ZM7.8,3C5.149,3 3,5.149 3,7.8C3,10.451 5.149,12.6 7.8,12.6C10.451,12.6 12.6,10.451 12.6,7.8C12.6,5.149 10.451,3 7.8,3Z"
android:strokeWidth="1"
android:fillColor="#8A8A99"
android:fillType="evenOdd"
android:strokeColor="#00000000"/>
</vector>

+ 16
- 0
lib/common/src/main/res/drawable/loading.xml View File

<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="false"> <!--是否只执行一次-->
<item android:drawable="@drawable/loading00" android:duration="100"/>
<item android:drawable="@drawable/loading01" android:duration="100"/>
<item android:drawable="@drawable/loading02" android:duration="100"/>
<item android:drawable="@drawable/loading03" android:duration="100"/>
<item android:drawable="@drawable/loading04" android:duration="100"/>
<item android:drawable="@drawable/loading05" android:duration="100"/>
<item android:drawable="@drawable/loading06" android:duration="100"/>
<item android:drawable="@drawable/loading07" android:duration="100"/>
<item android:drawable="@drawable/loading08" android:duration="100"/>
<item android:drawable="@drawable/loading09" android:duration="100"/>
<item android:drawable="@drawable/loading10" android:duration="100"/>

</animation-list>

BIN
lib/common/src/main/res/drawable/loading00.png View File


BIN
lib/common/src/main/res/drawable/loading01.png View File


BIN
lib/common/src/main/res/drawable/loading02.png View File


BIN
lib/common/src/main/res/drawable/loading03.png View File


BIN
lib/common/src/main/res/drawable/loading04.png View File


BIN
lib/common/src/main/res/drawable/loading05.png View File


BIN
lib/common/src/main/res/drawable/loading06.png View File


BIN
lib/common/src/main/res/drawable/loading07.png View File


BIN
lib/common/src/main/res/drawable/loading08.png View File


BIN
lib/common/src/main/res/drawable/loading09.png View File


BIN
lib/common/src/main/res/drawable/loading10.png View File


+ 6
- 0
lib/common/src/main/res/drawable/loading_bg.xml View File

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="#FFFFFF"/>
<size android:width="120dp" android:height="120dp"/>
</shape>

+ 35
- 0
lib/common/src/main/res/layout/loading_fragment.xml View File

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context=".base.LoadingDialog">

<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/loadImage"
android:layout_width="120dp"
android:layout_height="120dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="@+id/loadText"
android:src="@drawable/loading"
android:scaleType="centerInside"
android:foregroundGravity="center"
android:background="@drawable/loading_bg"/>

<TextView
android:id="@+id/loadText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@+id/loadImage"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginTop="24dp"
android:textStyle="bold"
android:textColor="#FFFFFF"
android:text="加载中..."/>

</androidx.constraintlayout.widget.ConstraintLayout>

+ 12
- 0
lib/common/src/main/res/values/attrs.xml View File

<?xml version="1.0" encoding="utf-8"?>
<resources>
<!--自定义的带搜索和删除按钮的EditTextView-->
<declare-styleable name="InputSearchEditText">
<!--搜索图标-->
<attr name="ic_search_src" format="reference"/>
<attr name="ic_search_color" format="color"/>
<!--删除图标-->
<attr name="ic_delete_src" format="reference"/>
<attr name="ic_delete_color" format="color"/>
</declare-styleable>
</resources>

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

<resources>
<!-- TODO: Remove or change this placeholder text -->
<string name="hello_blank_fragment">Hello blank fragment</string>
</resources>

Loading…
Cancel
Save