├── .gitignore
├── .idea
├── .gitignore
├── compiler.xml
├── gradle.xml
├── misc.xml
└── vcs.xml
├── README.md
├── build.gradle
├── demo
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── kt
│ │ └── ktmvvm
│ │ └── ExampleInstrumentedTest.kt
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── kt
│ │ │ └── ktmvvm
│ │ │ ├── BindingAdapter.kt
│ │ │ ├── Constants.kt
│ │ │ ├── MainActivity.kt
│ │ │ ├── MainViewModel.kt
│ │ │ ├── MyApp.kt
│ │ │ ├── decoration
│ │ │ └── StaggeredDividerItemDecoration.kt
│ │ │ ├── download
│ │ │ ├── DownloadActivity.kt
│ │ │ ├── DownloadViewModel.kt
│ │ │ └── manager
│ │ │ │ ├── DownloadInfo.kt
│ │ │ │ ├── DownloadManager.kt
│ │ │ │ ├── DownloaderCallBack.kt
│ │ │ │ └── ResponseProgressBody.kt
│ │ │ ├── entity
│ │ │ └── AlbumData.kt
│ │ │ ├── inner
│ │ │ ├── CameraExtensionModeType.kt
│ │ │ └── CameraRatioType.kt
│ │ │ ├── jetpack
│ │ │ ├── adapter
│ │ │ │ ├── RcvAdapter.kt
│ │ │ │ ├── ViewPagerAdapter.kt
│ │ │ │ └── ViewPagerVerticalAdapter.kt
│ │ │ ├── camerax
│ │ │ │ ├── CameraActivity.kt
│ │ │ │ ├── CameraCallBack.kt
│ │ │ │ ├── CameraParams.kt
│ │ │ │ ├── CameraViewModel.kt
│ │ │ │ └── controller
│ │ │ │ │ ├── CameraXController.kt
│ │ │ │ │ └── ICameraController.kt
│ │ │ ├── coordinatorlayout
│ │ │ │ ├── CoordinatorActivity.kt
│ │ │ │ └── CoordinatorViewModel.kt
│ │ │ ├── room
│ │ │ │ ├── RoomActivity.kt
│ │ │ │ ├── RoomViewModel.kt
│ │ │ │ └── db
│ │ │ │ │ ├── User.kt
│ │ │ │ │ ├── UserDao.kt
│ │ │ │ │ └── UserDataBase.kt
│ │ │ ├── shapeableimageview
│ │ │ │ ├── ShapeImageActivity.kt
│ │ │ │ └── ShapeImageViewMode.kt
│ │ │ └── viewpager
│ │ │ │ ├── ScaleInTransformer.kt
│ │ │ │ ├── ViewPager2Activity.kt
│ │ │ │ └── ViewPager2ViewModel.kt
│ │ │ ├── loader
│ │ │ ├── AlbumDataLoader.kt
│ │ │ └── MimeType.java
│ │ │ ├── net
│ │ │ └── DataService.kt
│ │ │ ├── ui
│ │ │ ├── KeyBordActivity.kt
│ │ │ ├── KeyBordAdapter.kt
│ │ │ ├── KeyBordViewModel.kt
│ │ │ ├── MosaicActivity.kt
│ │ │ └── MosaicViewModel.kt
│ │ │ ├── utils
│ │ │ ├── BannerUtils.kt
│ │ │ ├── DisplayUtils.kt
│ │ │ ├── KeyDataUtils.kt
│ │ │ ├── PrefsUtil.kt
│ │ │ └── StringUtils.kt
│ │ │ └── widget
│ │ │ ├── AutoTranslateView.kt
│ │ │ ├── CameraPreView.kt
│ │ │ ├── CameraTabView.java
│ │ │ ├── FocusView.kt
│ │ │ ├── GridView.kt
│ │ │ ├── MyBottomSheetBehavior.java
│ │ │ ├── PopWin.kt
│ │ │ ├── RatioPop.kt
│ │ │ ├── RecordButton.kt
│ │ │ ├── RecordCountDownView.java
│ │ │ ├── RingView.kt
│ │ │ ├── TakePhotoView.kt
│ │ │ ├── TimerHelper.kt
│ │ │ ├── TopView.kt
│ │ │ ├── TranslateView.kt
│ │ │ ├── VerticalSeekBar.java
│ │ │ ├── VerticalSeekBarWrapper.java
│ │ │ └── mosic
│ │ │ ├── DrawMosaicView.kt
│ │ │ ├── MosaicPath.kt
│ │ │ └── MosaicUtil.kt
│ └── res
│ │ ├── anim
│ │ └── anim_fade_in.xml
│ │ ├── color
│ │ ├── color_selector.xml
│ │ └── po_color_selector.xml
│ │ ├── drawable-v24
│ │ └── ic_launcher_foreground.xml
│ │ ├── drawable-xxhdpi
│ │ ├── bishua2.png
│ │ ├── bishua3.png
│ │ ├── bishua4.jpg
│ │ ├── gird_off.png
│ │ ├── gird_on.png
│ │ ├── hdr_off.png
│ │ ├── hdr_on.png
│ │ ├── icon_bg_space.png
│ │ ├── icon_bl.png
│ │ ├── icon_camera_close_normal.png
│ │ ├── icon_camera_close_pressed.png
│ │ ├── icon_case.png
│ │ ├── icon_delete.png
│ │ ├── icon_reset_camera.png
│ │ ├── icon_small_space.png
│ │ ├── icon_switch_camera_normal.png
│ │ ├── icon_switch_camera_pressed.png
│ │ ├── icon_take_picture_down.png
│ │ ├── icon_take_picture_normal.png
│ │ ├── icon_take_picture_sticker_normal.png
│ │ ├── icon_take_picture_sticker_pressed.png
│ │ ├── icon_top_setting.png
│ │ ├── light_check.png
│ │ ├── light_normal.png
│ │ ├── maoshua.jpg
│ │ ├── splash_close.png
│ │ ├── splash_open.png
│ │ ├── timer_off.png
│ │ └── timer_on.png
│ │ ├── drawable
│ │ ├── bg_black_shape.xml
│ │ ├── close_camera_selector.xml
│ │ ├── gray.xml
│ │ ├── grid_selector.xml
│ │ ├── hdr_selector.xml
│ │ ├── ic_launcher_background.xml
│ │ ├── light_selector.xml
│ │ ├── progress.xml
│ │ ├── selector_9_16.xml
│ │ ├── selector_keyboard.xml
│ │ ├── selector_text_color.xml
│ │ ├── shape_9_16.xml
│ │ ├── shape_9_16_fd87aa.xml
│ │ ├── shape_select_bg.xml
│ │ ├── shape_un_select_bg.xml
│ │ ├── splash_selector.xml
│ │ ├── switch_camera_selector.xml
│ │ ├── switch_selector.xml
│ │ ├── switch_thumb.xml
│ │ ├── timer_selector.xml
│ │ ├── white_c_15_shape.xml
│ │ └── yellow_switch.xml
│ │ ├── layout
│ │ ├── activity_camera_layout.xml
│ │ ├── activity_coordinator_layout.xml
│ │ ├── activity_download_layout.xml
│ │ ├── activity_main_new.xml
│ │ ├── activity_mosaic_layout.xml
│ │ ├── activity_shape_layout.xml
│ │ ├── bottom_sheet_layout.xml
│ │ ├── camera_preview.xml
│ │ ├── keybord_item_layout.xml
│ │ ├── keybord_layout.xml
│ │ ├── popu_layout.xml
│ │ ├── ratio_popu_layout.xml
│ │ ├── rcv_item_layout.xml
│ │ ├── room_activity.xml
│ │ ├── take_photo_view.xml
│ │ ├── top_factor_layout.xml
│ │ ├── tranlate_view_layout.xml
│ │ ├── viewpager2_layout.xml
│ │ ├── viewpager_item_layout.xml
│ │ └── viewpager_vertical_item_layout.xml
│ │ ├── mipmap-anydpi-v26
│ │ ├── ic_launcher.xml
│ │ └── ic_launcher_round.xml
│ │ ├── mipmap-hdpi
│ │ ├── ic_launcher.webp
│ │ └── ic_launcher_round.webp
│ │ ├── mipmap-mdpi
│ │ ├── ic_launcher.webp
│ │ └── ic_launcher_round.webp
│ │ ├── mipmap-xhdpi
│ │ ├── ic_launcher.webp
│ │ └── ic_launcher_round.webp
│ │ ├── mipmap-xxhdpi
│ │ ├── ic_launcher.webp
│ │ └── ic_launcher_round.webp
│ │ ├── mipmap-xxxhdpi
│ │ ├── ic_launcher.webp
│ │ └── ic_launcher_round.webp
│ │ ├── values-night
│ │ └── themes.xml
│ │ └── values
│ │ ├── arrays.xml
│ │ ├── attrs.xml
│ │ ├── colors.xml
│ │ ├── strings.xml
│ │ ├── styles.xml
│ │ └── themes.xml
│ └── test
│ └── java
│ └── com
│ └── kt
│ └── ktmvvm
│ └── ExampleUnitTest.kt
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── ktmvvm
├── .gitignore
├── build.gradle
├── consumer-rules.pro
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── kt
│ │ └── ktmvvm
│ │ └── ExampleInstrumentedTest.kt
│ ├── main
│ ├── AndroidManifest.xml
│ └── java
│ │ └── com
│ │ └── kt
│ │ └── ktmvvm
│ │ ├── basic
│ │ ├── BaseActivity.kt
│ │ ├── BaseFragment.kt
│ │ ├── BaseViewModel.kt
│ │ ├── IBaseView.kt
│ │ ├── IBaseViewModel.kt
│ │ └── SingleLiveEvent.kt
│ │ └── net
│ │ ├── ApiAddress.kt
│ │ ├── ApiException.kt
│ │ ├── ApiService.kt
│ │ ├── BaseResponse.kt
│ │ ├── BaseUrlConstants.kt
│ │ ├── ExceptionUtil.kt
│ │ ├── RetrofitClient.kt
│ │ ├── TrustAllCerts.kt
│ │ ├── dns
│ │ └── OkHttpDNS.kt
│ │ ├── event
│ │ ├── OkHttpEvent.kt
│ │ └── OkHttpEventListener.kt
│ │ └── interceptor
│ │ ├── HTTPDNSInterceptor.kt
│ │ └── NoNetworkInterceptor.kt
│ └── test
│ └── java
│ └── com
│ └── kt
│ └── ktmvvm
│ └── ExampleUnitTest.kt
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | .idea
4 | /local.properties
5 | /.idea/workspace.xml
6 | /.idea/vcs.xml
7 | /.idea/libraries
8 | .DS_Store
9 | /build
10 | /captures
11 | *.apk
--------------------------------------------------------------------------------
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 |
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
20 |
21 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # KTMVVM
2 |
3 | Android MVVM 设计模式、kotlin+mvvm+retrofit+room+jetpack
4 |
5 | ### 整体结构
6 | 架构整体设计模式:MVVM(databindin\viewmodel\lifecycle\livedata)
7 | 网络框架:okhttp3\retrofit\kotlin 协程
8 | 存储框架:room\kotlin协程\flow
9 | Demo演示:ViewPager2\Room\Coordinatorlayout折叠栏\CameraX\马赛克\Shapeableimageview
10 |
11 | ### 对应页面
12 |
13 | | 功能 | 对应Activity|
14 | | ---- | ---- |
15 | | ViewPager2 | ViewPager2Activity |
16 | | Room数据库 | RoomActivity |
17 | | Coordinatorlayout折叠栏 | CoordinatorActivity |
18 | | CameraX | CameraActivity |
19 | | 马赛克 | MosaicActivity |
20 | | Shapeableimageview | ShapeImageActivity |
21 |
22 |
23 | ### 对应展示效果
24 |
25 | * **ViewPager2:**
26 |
27 |
28 | 
29 |
30 |
31 | * **Room数据库:**
32 |
33 | 
34 |
35 |
36 |
37 | * **CameraX仿一甜相机:**
38 |
39 | 
40 | 
41 |
42 |
43 | * **马赛克:**
44 |
45 | 
46 |
47 | * **多进程下载器:**
48 |
49 | 
50 |
51 | * **Shapeableimageview:**
52 |
53 | 
54 |
55 |
56 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 | buildscript {
3 |
4 | ext.kotlin_version ='1.7.0'
5 | dependencies {
6 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.21"
7 |
8 | }
9 | }
10 |
11 | plugins {
12 | id 'com.android.application' version '7.1.3' apply false
13 | id 'com.android.library' version '7.1.3' apply false
14 | id 'org.jetbrains.kotlin.android' version '1.6.21' apply false
15 | // id 'org.jetbrains.kotlin:kotlin-gradle-plugin' version '1.7.0' apply false
16 | }
17 |
18 | task clean(type: Delete) {
19 | delete rootProject.buildDir
20 | }
--------------------------------------------------------------------------------
/demo/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/demo/build.gradle:
--------------------------------------------------------------------------------
1 |
2 |
3 | plugins {
4 | id 'com.android.application'
5 | id 'org.jetbrains.kotlin.android'
6 | }
7 |
8 | apply plugin: 'kotlin-android'
9 | apply plugin: 'kotlin-android-extensions'
10 | apply plugin: 'kotlin-kapt'
11 |
12 | kapt {
13 | generateStubs = true
14 | }
15 | android {
16 | compileSdk 32
17 |
18 | defaultConfig {
19 | applicationId "com.kt.ktmvvm"
20 | minSdk 21
21 | targetSdk 26
22 | versionCode 1
23 | versionName "1.0"
24 |
25 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
26 | }
27 |
28 | buildTypes {
29 | release {
30 | minifyEnabled false
31 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
32 | }
33 | }
34 | compileOptions {
35 | sourceCompatibility JavaVersion.VERSION_1_8
36 | targetCompatibility JavaVersion.VERSION_1_8
37 | }
38 | kotlinOptions {
39 | jvmTarget = '1.8'
40 | }
41 |
42 | buildFeatures{
43 | dataBinding = true
44 | }
45 | }
46 |
47 | dependencies {
48 |
49 | implementation 'androidx.core:core-ktx:1.8.0'
50 | implementation 'androidx.appcompat:appcompat:1.4.2'
51 | implementation 'com.google.android.material:material:1.6.1'
52 | implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
53 | implementation project(path: ':ktmvvm')
54 | testImplementation 'junit:junit:4.13.2'
55 | androidTestImplementation 'androidx.test.ext:junit:1.1.3'
56 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
57 | kapt "androidx.room:room-compiler:2.4.2" // Kotlin 使用 kapt
58 |
59 |
60 | //camerax
61 |
62 | def camerax_version = "1.2.0-alpha04"
63 | implementation "androidx.camera:camera-core:${camerax_version}"
64 | implementation "androidx.camera:camera-camera2:${camerax_version}"
65 | implementation "androidx.camera:camera-lifecycle:${camerax_version}"
66 | implementation "androidx.camera:camera-video:${camerax_version}"
67 | implementation "androidx.camera:camera-view:${camerax_version}"
68 | implementation "androidx.camera:camera-extensions:${camerax_version}"
69 | implementation "androidx.concurrent:concurrent-futures-ktx:1.1.0"
70 | api 'com.blankj:utilcodex:1.31.0' //工具类
71 |
72 | }
--------------------------------------------------------------------------------
/demo/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/demo/src/androidTest/java/com/kt/ktmvvm/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package com.kt.ktmvvm
2 |
3 | import androidx.test.platform.app.InstrumentationRegistry
4 | import androidx.test.ext.junit.runners.AndroidJUnit4
5 |
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | import org.junit.Assert.*
10 |
11 | /**
12 | * Instrumented test, which will execute on an Android device.
13 | *
14 | * See [testing documentation](http://d.android.com/tools/testing).
15 | */
16 | @RunWith(AndroidJUnit4::class)
17 | class ExampleInstrumentedTest {
18 | @Test
19 | fun useAppContext() {
20 | // Context of the app under test.
21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext
22 | assertEquals("com.kt.ktmvvm", appContext.packageName)
23 | }
24 | }
--------------------------------------------------------------------------------
/demo/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
28 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
41 |
42 |
45 |
46 |
49 |
50 |
53 |
54 |
57 |
58 |
61 |
62 |
66 |
67 |
70 |
71 |
72 |
--------------------------------------------------------------------------------
/demo/src/main/java/com/kt/ktmvvm/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.kt.ktmvvm
2 |
3 | import android.os.Bundle
4 | import android.os.Handler
5 | import android.view.LayoutInflater
6 | import androidx.databinding.DataBindingUtil
7 | import com.kt.ktmvvm.basic.BaseActivity
8 | import com.kt.ktmvvm.databinding.ActivityMainNewBinding
9 |
10 | class MainActivity : BaseActivity() {
11 |
12 |
13 | override fun initParam() {
14 | }
15 |
16 |
17 | override fun initVariableId(): Int {
18 | return BR.model
19 | }
20 |
21 |
22 | override fun initContentView(savedInstanceState: Bundle?): Int {
23 | return R.layout.activity_main_new
24 | }
25 | }
--------------------------------------------------------------------------------
/demo/src/main/java/com/kt/ktmvvm/MainViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.kt.ktmvvm
2 |
3 | import android.app.Application
4 | import android.util.Log
5 | import com.kt.ktmvvm.basic.BaseViewModel
6 | import com.kt.ktmvvm.download.DownloadActivity
7 | import com.kt.ktmvvm.jetpack.camerax.CameraActivity
8 | import com.kt.ktmvvm.jetpack.coordinatorlayout.CoordinatorActivity
9 | import com.kt.ktmvvm.jetpack.room.RoomActivity
10 | import com.kt.ktmvvm.jetpack.shapeableimageview.ShapeImageActivity
11 | import com.kt.ktmvvm.jetpack.viewpager.ViewPager2Activity
12 | import com.kt.ktmvvm.net.ApiException
13 | import com.kt.ktmvvm.net.DataService
14 | import com.kt.ktmvvm.ui.KeyBordActivity
15 | import com.kt.ktmvvm.ui.MosaicActivity
16 | import java.util.*
17 |
18 | open class MainViewModel(application: Application) : BaseViewModel(application) {
19 |
20 | companion object {
21 | val TAG: String? = MainViewModel::class.simpleName
22 | }
23 |
24 |
25 | /**
26 | * 登录测试
27 | */
28 | open fun getBookInfo() {
29 |
30 |
31 | launch({
32 | val login = DataService.getBookInfo(3)
33 |
34 | }, onError = {
35 |
36 | Log.d(TAG, "the error is" + it.message)
37 | })
38 |
39 | }
40 |
41 |
42 | /**
43 | * 历史上的今天
44 | */
45 | open fun getHistoryDate() {
46 |
47 | launch({
48 | val instance = Calendar.getInstance()
49 |
50 | val month = instance.get(Calendar.MONTH) + 1;
51 |
52 | val day = instance.get(Calendar.DATE);
53 |
54 | Log.d(TAG, "the date is$month/$day")
55 | val any = DataService.getHistoryDate(4, "$month/$day")
56 |
57 | any?.let {
58 |
59 | } ?: let {
60 | //数据为空
61 | }
62 |
63 | // if (login.getErrCode() == 200) {
64 | // var data = login.getData()
65 | // } else {
66 | // ApiException(-1, "返回结果出错")
67 | // }
68 | }, onError = {
69 |
70 | })
71 | }
72 |
73 | /**
74 | * 任意地方调用
75 | */
76 | open fun notViewModelLogin() {
77 | DataService.launch({
78 | val login = DataService.login(1, "admin", "admin")
79 |
80 | if (login.getErrCode() == 200) {
81 | var data = login.getData()
82 | } else {
83 | ApiException(-1, "返回结果出错")
84 | }
85 | }, onError = {
86 |
87 | Log.d(TAG, "the error is" + it.message)
88 | })
89 | }
90 |
91 |
92 | /**
93 | * 跳转viewpager2
94 | */
95 | open fun goViewPager2() {
96 | startActivity(ViewPager2Activity::class.java)
97 | }
98 |
99 |
100 | /**
101 | * 进入room数据库
102 | */
103 | open fun goRoom() {
104 | startActivity(RoomActivity::class.java)
105 | }
106 |
107 | /**
108 | * 进入coordinator
109 | */
110 | open fun goCoordinator() {
111 | startActivity(CoordinatorActivity::class.java)
112 | }
113 |
114 | /**
115 | * 进入下载器
116 | */
117 | open fun goDownloadManager() {
118 | startActivity(DownloadActivity::class.java)
119 | }
120 |
121 | /**
122 | * 马赛克
123 | */
124 | open fun goMosaic() {
125 | startActivity(MosaicActivity::class.java)
126 | }
127 |
128 |
129 | /**
130 | * shape view
131 | */
132 | open fun goShape() {
133 | startActivity(ShapeImageActivity::class.java)
134 | }
135 |
136 | /**
137 | * 进入相机
138 | */
139 |
140 | open fun goCamera() {
141 | startActivity(CameraActivity::class.java)
142 | }
143 |
144 | /**
145 | * 进入自定义键盘
146 | */
147 | open fun getKeyBord() {
148 | startActivity(KeyBordActivity::class.java)
149 | }
150 | }
--------------------------------------------------------------------------------
/demo/src/main/java/com/kt/ktmvvm/MyApp.kt:
--------------------------------------------------------------------------------
1 | package com.kt.ktmvvm
2 |
3 | import android.app.Application
4 | import android.content.Context
5 | import com.kt.ktmvvm.utils.PrefsUtil
6 |
7 | class MyApp : Application() {
8 |
9 |
10 | override fun onCreate() {
11 | super.onCreate()
12 | PrefsUtil.getInstance()?.init(this, "download_", Context.MODE_PRIVATE)
13 | instance = this
14 | }
15 |
16 | override fun attachBaseContext(base: Context?) {
17 | super.attachBaseContext(base)
18 | instance = this
19 | }
20 |
21 |
22 | companion object {
23 | private var instance: Application? = null
24 | fun get(): MyApp {
25 | return instance as MyApp
26 | }
27 |
28 | }
29 | }
--------------------------------------------------------------------------------
/demo/src/main/java/com/kt/ktmvvm/decoration/StaggeredDividerItemDecoration.kt:
--------------------------------------------------------------------------------
1 | package com.kt.ktmvvm.decoration
2 |
3 | import android.content.Context
4 | import android.graphics.Rect
5 | import android.view.View
6 | import androidx.recyclerview.widget.RecyclerView
7 | import androidx.recyclerview.widget.RecyclerView.ItemDecoration
8 | import androidx.recyclerview.widget.StaggeredGridLayoutManager
9 | import com.kt.ktmvvm.utils.DisplayUtils
10 |
11 | class StaggeredDividerItemDecoration(internal: Int, context: Context) : ItemDecoration() {
12 |
13 | private var mInternal: Int = internal
14 | private var mHeight: Int? = 0
15 | private var mContext: Context? = context
16 |
17 | constructor(internal: Int, height: Int, context: Context) : this(internal, context) {
18 | mInternal = internal
19 | mHeight = height
20 | mContext = context
21 | }
22 |
23 | override fun getItemOffsets(
24 | outRect: Rect,
25 | view: View,
26 | parent: RecyclerView,
27 | state: RecyclerView.State
28 | ) {
29 | super.getItemOffsets(outRect, view, parent, state)
30 |
31 | if (parent.layoutManager is StaggeredGridLayoutManager) {
32 | val params = view.layoutParams as StaggeredGridLayoutManager.LayoutParams
33 | val spanIndex = params.spanIndex
34 | val viewLayoutPosition = params.viewLayoutPosition
35 | val column = spanIndex % 2 // view 所在的列
36 | // 中间间隔
37 | if (column == 1) {
38 | outRect.left = ((mInternal / 2f).toInt())
39 | } else {
40 | outRect.right = ((mInternal / 2f).toInt())
41 | }
42 | // 下方间隔
43 | outRect.bottom =
44 | if (mHeight == 0) DisplayUtils.dip2px(mContext, 9f) else mHeight!!
45 |
46 | }
47 | }
48 | }
--------------------------------------------------------------------------------
/demo/src/main/java/com/kt/ktmvvm/download/DownloadActivity.kt:
--------------------------------------------------------------------------------
1 | package com.kt.ktmvvm.download
2 |
3 | import android.os.Bundle
4 | import com.kt.ktmvvm.BR
5 | import com.kt.ktmvvm.R
6 | import com.kt.ktmvvm.basic.BaseActivity
7 | import com.kt.ktmvvm.databinding.ActivityDownloadLayoutBinding
8 |
9 | class DownloadActivity : BaseActivity() {
10 | override fun initVariableId(): Int {
11 | return BR.model
12 | }
13 |
14 | override fun initContentView(savedInstanceState: Bundle?): Int {
15 | return R.layout.activity_download_layout
16 | }
17 |
18 | override fun initParam() {
19 |
20 | }
21 | }
--------------------------------------------------------------------------------
/demo/src/main/java/com/kt/ktmvvm/download/DownloadViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.kt.ktmvvm.download
2 |
3 | import android.app.Application
4 | import android.util.Log
5 |
6 | import androidx.databinding.ObservableField
7 | import com.kt.ktmvvm.Constants
8 | import com.kt.ktmvvm.basic.BaseViewModel
9 | import com.kt.ktmvvm.download.manager.DownloadInfo
10 | import com.kt.ktmvvm.download.manager.DownloadManager
11 | import com.kt.ktmvvm.download.manager.DownloaderCallBack
12 |
13 | import com.kt.ktmvvm.utils.BannerUtils
14 | import java.io.File
15 |
16 | class DownloadViewModel(application: Application) : BaseViewModel(application) {
17 |
18 | companion object {
19 | private val TAG: String? = DownloadViewModel::class.simpleName
20 | }
21 |
22 | var url1: ObservableField? = ObservableField(Constants.file1)
23 | var url2: ObservableField? = ObservableField(Constants.file2)
24 | var url3: ObservableField? = ObservableField(Constants.picture3)
25 |
26 | var process1: ObservableField? = ObservableField(0)
27 | var process2: ObservableField? = ObservableField(0)
28 | var process3: ObservableField? = ObservableField(0)
29 |
30 | private var downloadManager: DownloadManager? = null
31 |
32 | override fun onCreate() {
33 | super.onCreate()
34 | downloadManager = DownloadManager.get(getApplication()).setMaxRequests(3)
35 |
36 |
37 | }
38 |
39 | /**
40 | * 下载大文件
41 | */
42 | fun downloadBigFile(index: Int?) {
43 | val url: String?
44 | val tag: Int?
45 | val name: String?
46 | when (index) {
47 | 1 -> {
48 | url = url1?.get()
49 | tag = 1
50 | name = "origen.zip"
51 | }
52 | 2 -> {
53 | url = url2?.get()
54 | tag = 2
55 | name = "opencv.zip"
56 | }
57 | 3 -> {
58 | url = url3?.get()
59 | tag = 3
60 | name = "three.jpg"
61 | }
62 | else -> {
63 | url = url1?.get()
64 | tag = 1
65 | name = "three.jpg"
66 | }
67 | }
68 |
69 |
70 | downloadManager?.download(
71 | url,
72 | BannerUtils.getSdPath(getApplication(), name),
73 | CallBack(),
74 | tag
75 | )
76 |
77 | }
78 |
79 | /**
80 | *暂停某个任务
81 | */
82 | fun pauseDownload(index: Int?) {
83 |
84 | val url: String? = when (index) {
85 | 1 -> url1?.get()
86 | 2 -> url2?.get()
87 | 3 -> url3?.get()
88 | else -> url1?.get()
89 | }
90 | downloadManager?.pause(url)
91 | }
92 |
93 | /**
94 | * 暂停某个下载
95 | */
96 | fun cancelDownload(index: Int?) {
97 | val url: String? = when (index) {
98 | 1 -> url1?.get()
99 | 2 -> url2?.get()
100 | 3 -> url3?.get()
101 | else -> url1?.get()
102 | }
103 | downloadManager?.cancel(url)
104 | }
105 |
106 |
107 | inner class CallBack : DownloaderCallBack() {
108 | override fun onProgress(currentBytes: Long?, totalBytes: Long?, tag: Int?) {
109 | totalBytes?.let {
110 | val sum = currentBytes?.times(1f.div(totalBytes * 1f))
111 | val process = sum?.times(100) ?: 0
112 |
113 |
114 | when (tag) {
115 | 1 -> process1?.set(process.toInt())
116 | 2 -> process2?.set(process.toInt())
117 | 3 -> process3?.set(process.toInt())
118 | else -> process1?.set(process.toInt())
119 | }
120 |
121 | Log.e(TAG, "the tag ==$tag+ sum ==$process")
122 | }
123 |
124 |
125 | }
126 |
127 | override fun onFinish(download_file: File?, tag: Int?) {
128 | Log.e(TAG, "download finish file path=" + download_file?.path)
129 | }
130 |
131 | override fun onPause(downloadInfo: DownloadInfo?) {
132 | Log.e(TAG, "download status is pause" + Thread.currentThread())
133 | }
134 |
135 | override fun onCancel(downloadInfo: DownloadInfo?) {
136 | Log.e(TAG, "download status is cancel" + Thread.currentThread())
137 | when (downloadInfo?.getTag()) {
138 | 1 -> process1?.set(0)
139 | 2 -> process2?.set(0)
140 | 3 -> process3?.set(0)
141 | else -> process1?.set(0)
142 | }
143 |
144 | }
145 |
146 | override fun onFailure(error_msg: String?) {
147 | Log.e(TAG, "download status is failure" + Thread.currentThread())
148 | }
149 | }
150 | }
--------------------------------------------------------------------------------
/demo/src/main/java/com/kt/ktmvvm/download/manager/DownloadInfo.kt:
--------------------------------------------------------------------------------
1 | package com.kt.ktmvvm.download.manager
2 |
3 | import java.io.Serializable
4 |
5 | class DownloadInfo(//下载路径
6 | private var url: String?,// 下載標識
7 | private var tag: Int
8 | ) : Serializable {
9 | private var targetUrl: String? = null//存储路径
10 | private var total: Long? = 0//总大小
11 | private var progress: Long? = 0 //当前进度
12 |
13 | private var fileName: String? = null //名称
14 |
15 | private var downloadState: Int? = 0 //下载状态
16 |
17 |
18 | fun getTag(): Int {
19 | return tag
20 | }
21 |
22 | fun setTag(tag: Int) {
23 | this.tag = tag
24 | }
25 |
26 | fun getUrl(): String? {
27 | return url
28 | }
29 |
30 | fun getFileName(): String? {
31 | return fileName
32 | }
33 |
34 | fun setFileName(fileName: String?) {
35 | this.fileName = fileName
36 | }
37 |
38 | fun getTotal(): Long? {
39 | return total
40 | }
41 |
42 | fun setTotal(total: Long?) {
43 | this.total = total
44 | }
45 |
46 | fun getProgress(): Long? {
47 | return progress
48 | }
49 |
50 | fun setProgress(progress: Long?) {
51 | this.progress = progress
52 | }
53 |
54 | fun getTargetUrl(): String? {
55 | return targetUrl
56 | }
57 |
58 | fun setTargetUrl(targetUrl: String?) {
59 | this.targetUrl = targetUrl
60 | }
61 |
62 | fun setDownloadState(downloadState: Int?) {
63 | this.downloadState = downloadState
64 | }
65 |
66 | fun getDownloadState(): Int? {
67 | return downloadState
68 | }
69 |
70 | }
--------------------------------------------------------------------------------
/demo/src/main/java/com/kt/ktmvvm/download/manager/DownloaderCallBack.kt:
--------------------------------------------------------------------------------
1 | package com.kt.ktmvvm.download.manager
2 |
3 | import java.io.File
4 |
5 | abstract class DownloaderCallBack {
6 |
7 | abstract fun onProgress(currentBytes: Long?, totalBytes: Long?, tag: Int?)
8 | abstract fun onFinish(download_file: File?, tag: Int?)
9 | abstract fun onPause(downloadInfo: DownloadInfo?)
10 | abstract fun onCancel(downloadInfo: DownloadInfo?)
11 | abstract fun onFailure(error_msg: String?)
12 | }
13 |
14 |
--------------------------------------------------------------------------------
/demo/src/main/java/com/kt/ktmvvm/download/manager/ResponseProgressBody.kt:
--------------------------------------------------------------------------------
1 | package com.kt.ktmvvm.download.manager
2 |
3 | import android.content.Context
4 | import com.kt.ktmvvm.utils.PrefsUtil
5 | import kotlinx.coroutines.flow.flow
6 | import kotlinx.coroutines.runBlocking
7 | import okhttp3.MediaType
8 | import okhttp3.ResponseBody
9 | import okio.*
10 | import java.io.IOException
11 |
12 | class ResponseProgressBody(
13 | private var mContext: Context?,
14 | private var mResponseBody: ResponseBody?,
15 | private var callBack: DownloaderCallBack?,
16 | private var info: DownloadInfo?
17 | ) : ResponseBody() {
18 |
19 | private var bufferedSource: BufferedSource? = null
20 |
21 | private var progress: Long = 0//开始前已下载进度
22 |
23 | private var downloadInfo: MutableMap? = null
24 |
25 |
26 | init {
27 | progress = info?.getProgress()!!
28 | downloadInfo = PrefsUtil.getInstance()?.getMap(DownloadManager.DOWNLOAD_MAPS)
29 | if (info?.getTotal()!! <= 0) {
30 | info?.setTotal(mResponseBody?.contentLength())
31 | downloadInfo?.put(info?.getUrl(), info)
32 | PrefsUtil.getInstance()?.putMap(DownloadManager.DOWNLOAD_MAPS, downloadInfo)
33 |
34 | }
35 | }
36 |
37 | override fun contentType(): MediaType? {
38 | return mResponseBody?.contentType()
39 | }
40 |
41 | override fun contentLength(): Long {
42 | return mResponseBody?.contentLength()!!
43 | }
44 |
45 | override fun source(): BufferedSource {
46 | if (bufferedSource == null) {
47 | bufferedSource =
48 | mResponseBody?.source()?.let { source(it).let { it1 -> Okio.buffer(it1) } }
49 | }
50 | return bufferedSource!!
51 | }
52 |
53 | private fun source(source: Source): Source {
54 | return object : ForwardingSource(source) {
55 | var totalBytesRead: Long = 0
56 |
57 | @Throws(IOException::class)
58 | override fun read(sink: Buffer, byteCount: Long): Long {
59 | val bytesRead = super.read(sink, byteCount)
60 | totalBytesRead += if (bytesRead != -1L) bytesRead else 0
61 | info?.setProgress(totalBytesRead + progress)
62 |
63 | runBlocking {
64 | flow { emit(1) }
65 | .collect {
66 | callBack?.onProgress(
67 | info?.getProgress(),
68 | info?.getTotal(),
69 | info?.getTag()
70 | )
71 | }
72 | }
73 |
74 |
75 | info?.setDownloadState(DownloadManager.DOWNLOAD_STATE_DOWNLOADING)
76 | downloadInfo!![info?.getUrl()] = info
77 | PrefsUtil.getInstance()?.putMap(DownloadManager.DOWNLOAD_MAPS, downloadInfo)
78 |
79 | return bytesRead
80 | }
81 | }
82 | }
83 |
84 |
85 | }
--------------------------------------------------------------------------------
/demo/src/main/java/com/kt/ktmvvm/entity/AlbumData.kt:
--------------------------------------------------------------------------------
1 | package com.kt.ktmvvm.entity
2 |
3 | import android.annotation.SuppressLint
4 | import android.database.Cursor
5 | import android.net.Uri
6 | import android.os.Parcel
7 | import android.os.Parcelable
8 | import com.kt.ktmvvm.jetpack.camerax.CameraViewModel
9 | import java.io.Serializable
10 |
11 | class AlbumData : Serializable {
12 |
13 |
14 | companion object {
15 | val ALBUM_ID_ALL = "-1"
16 | val ALBUM_NAME_ALL = "All"
17 |
18 | private var mId: String? = null
19 | private var mCoverPath: Uri? = null
20 | private var mDisplayName: String? = null
21 | private var mCount: Long = 0
22 |
23 | @SuppressLint("Range")
24 | fun valueOf(cursor: Cursor): AlbumData {
25 | val index = cursor.getColumnIndex(CameraViewModel.COLUMN_URI)
26 | val count = cursor.getColumnIndex(CameraViewModel.COLUMN_COUNT)
27 | val uri = if (index >= 0) cursor.getString(index) else null
28 | return AlbumData(
29 | cursor.getString(cursor.getColumnIndex("bucket_id")),
30 | Uri.parse(uri ?: ""),
31 | cursor.getString(cursor.getColumnIndex("bucket_display_name")),
32 | if (count > 0) cursor.getLong(count) else 0
33 | )
34 | }
35 |
36 | }
37 |
38 |
39 | constructor(id: String?, coverUri: Uri?, displayName: String?, count: Long) {
40 | mId = id
41 | mCoverPath = coverUri
42 | mDisplayName = displayName
43 | mCount = count
44 | }
45 |
46 | constructor(source: Parcel) {
47 | mId = source.readString()
48 | mCoverPath = source.readParcelable(Uri::class.java.classLoader)
49 | mDisplayName = source.readString()
50 | mCount = source.readLong()
51 | }
52 |
53 |
54 | fun getId(): String? {
55 | return mId
56 | }
57 |
58 | /**
59 | * 获取封面路径
60 | * @return
61 | */
62 | fun getCoverUri(): Uri? {
63 | return mCoverPath
64 | }
65 |
66 | /**
67 | * 获取显示名称
68 | * @return
69 | */
70 | fun getDisplayName(): String? {
71 | return if (isAll()) {
72 | "所有照片"
73 | } else mDisplayName
74 | }
75 |
76 | /**
77 | * 获取相册数量
78 | * @return
79 | */
80 | fun getCount(): Long {
81 | return mCount
82 | }
83 |
84 | /**
85 | * 加入拍摄item
86 | */
87 | fun addCaptureCount() {
88 | mCount++
89 | }
90 |
91 | fun isAll(): Boolean {
92 | return ALBUM_ID_ALL == mId
93 | }
94 |
95 | fun isEmpty(): Boolean {
96 | return mCount == 0L
97 | }
98 |
99 | override fun toString(): String {
100 | return "AlbumData{" +
101 | "mId='" + mId + '\'' +
102 | ", mCoverPath='" + mCoverPath + '\'' +
103 | ", mDisplayName='" + mDisplayName + '\'' +
104 | ", mCount=" + mCount +
105 | '}'
106 | }
107 | }
--------------------------------------------------------------------------------
/demo/src/main/java/com/kt/ktmvvm/inner/CameraExtensionModeType.kt:
--------------------------------------------------------------------------------
1 | package com.kt.ktmvvm.inner
2 |
3 | import androidx.annotation.IntDef
4 |
5 | @IntDef(
6 | flag = true,
7 | value = [
8 | CameraExtensionModeType.NONE,
9 | CameraExtensionModeType.BOKEH,
10 | CameraExtensionModeType.HDR,
11 | CameraExtensionModeType.NIGHT,
12 | CameraExtensionModeType.FACE_RETOUCH,
13 | CameraExtensionModeType.AUTO]
14 | )
15 | annotation class CameraExtensionModeType {
16 |
17 | companion object {
18 | /**
19 | * 无
20 | */
21 | const val NONE = 0
22 |
23 | /**
24 | * 焦外成像
25 | */
26 | const val BOKEH = 1
27 |
28 | /**
29 | * HDR高清
30 | */
31 | const val HDR = 2
32 |
33 | /**
34 | * 夜景模式
35 | */
36 | const val NIGHT = 3
37 |
38 | /**
39 | * 脸部修复
40 | */
41 | const val FACE_RETOUCH = 4
42 |
43 | /**
44 | * 自动
45 | */
46 | const val AUTO = 5
47 | }
48 |
49 | }
--------------------------------------------------------------------------------
/demo/src/main/java/com/kt/ktmvvm/inner/CameraRatioType.kt:
--------------------------------------------------------------------------------
1 | package com.kt.ktmvvm.inner
2 |
3 | import androidx.annotation.IntDef
4 | import com.kt.ktmvvm.inner.CameraRatioType.Companion.RATIO_1_1
5 | import com.kt.ktmvvm.inner.CameraRatioType.Companion.RATIO_3_4
6 | import com.kt.ktmvvm.inner.CameraRatioType.Companion.RATIO_9_16
7 | import com.kt.ktmvvm.inner.CameraRatioType.Companion.RATIO_FULL
8 |
9 | @IntDef(flag = true, value = [RATIO_3_4, RATIO_9_16, RATIO_1_1, RATIO_FULL])
10 | annotation class CameraRatioType {
11 | companion object {
12 | const val RATIO_3_4: Int = 0
13 | const val RATIO_9_16: Int = 1
14 | const val RATIO_1_1: Int = 2
15 | const val RATIO_FULL: Int = 3
16 | }
17 | }
--------------------------------------------------------------------------------
/demo/src/main/java/com/kt/ktmvvm/jetpack/adapter/RcvAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.kt.ktmvvm.jetpack.adapter
2 |
3 | import android.view.Display
4 | import android.view.View
5 | import androidx.databinding.DataBindingUtil
6 | import androidx.databinding.ViewDataBinding
7 | import com.bumptech.glide.Glide
8 | import com.chad.library.adapter.base.BaseQuickAdapter
9 | import com.chad.library.adapter.base.viewholder.BaseViewHolder
10 | import com.kt.ktmvvm.R
11 | import com.kt.ktmvvm.databinding.RcvItemLayoutBinding
12 | import com.kt.ktmvvm.databinding.ViewpagerItemLayoutBinding
13 | import com.kt.ktmvvm.jetpack.coordinatorlayout.CoordinatorViewModel
14 | import com.kt.ktmvvm.jetpack.viewpager.ViewPager2ViewModel
15 | import com.kt.ktmvvm.utils.DisplayUtils
16 |
17 | class RcvAdapter(model: CoordinatorViewModel) :
18 | BaseQuickAdapter(R.layout.rcv_item_layout) {
19 | private var model: CoordinatorViewModel? = model
20 |
21 | override fun onBindViewHolder(holder: BaseViewHolder, position: Int) {
22 | super.onBindViewHolder(holder, position)
23 | //随机高度
24 | val height: Int = if (holder.adapterPosition % 2 == 0) {
25 | DisplayUtils.dip2px(context, 250f)
26 | } else {
27 | DisplayUtils.dip2px(context, 350f)
28 | }
29 |
30 |
31 | holder.getView(R.id.img).apply {
32 | layoutParams.height = height
33 | layoutParams.width
34 | }
35 | }
36 |
37 |
38 | override fun convert(holder: BaseViewHolder, item: String) {
39 | if (DataBindingUtil.getBinding(holder.itemView) == null) {
40 | RcvItemLayoutBinding.bind(holder.itemView)
41 | }
42 |
43 | val binding = holder.getBinding()
44 | binding?.model = model
45 |
46 |
47 | Glide.with(context).asBitmap().load(
48 | getItem(holder.adapterPosition)
49 | ).into(binding?.img!!)
50 |
51 | }
52 | }
--------------------------------------------------------------------------------
/demo/src/main/java/com/kt/ktmvvm/jetpack/adapter/ViewPagerAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.kt.ktmvvm.jetpack.adapter
2 |
3 | import androidx.databinding.DataBindingUtil
4 | import androidx.databinding.ViewDataBinding
5 | import com.bumptech.glide.Glide
6 | import com.chad.library.adapter.base.BaseQuickAdapter
7 | import com.chad.library.adapter.base.viewholder.BaseViewHolder
8 | import com.kt.ktmvvm.R
9 | import com.kt.ktmvvm.databinding.ViewpagerItemLayoutBinding
10 | import com.kt.ktmvvm.jetpack.viewpager.ViewPager2ViewModel
11 | import com.kt.ktmvvm.utils.BannerUtils
12 |
13 | class ViewPagerAdapter(model: ViewPager2ViewModel) :
14 | BaseQuickAdapter(R.layout.viewpager_item_layout) {
15 |
16 | private var model: ViewPager2ViewModel? = model
17 |
18 | override fun convert(holder: BaseViewHolder, item: String) {
19 | try {
20 | if (DataBindingUtil.getBinding(holder.itemView) == null) {
21 | ViewpagerItemLayoutBinding.bind(holder.itemView)
22 | }
23 |
24 | val binding = holder.getBinding()
25 | binding?.model = model
26 |
27 |
28 | Glide.with(context).asBitmap().load(
29 | getItem(holder.adapterPosition)
30 | ).into(binding?.img!!)
31 | } catch (e: Exception) {
32 | }
33 |
34 | }
35 |
36 |
37 | override fun getDefItemCount(): Int {
38 | return Int.MAX_VALUE
39 | }
40 |
41 | override fun getItem(position: Int): String {
42 | return data[position % data.size]
43 | }
44 |
45 | override fun getItemViewType(position: Int): Int {
46 | var count = headerLayoutCount + data.size
47 | if (count <= 0) {
48 | count = 1
49 | }
50 | return super.getItemViewType(position % count)
51 | }
52 | }
--------------------------------------------------------------------------------
/demo/src/main/java/com/kt/ktmvvm/jetpack/adapter/ViewPagerVerticalAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.kt.ktmvvm.jetpack.adapter
2 |
3 | import android.view.View
4 | import androidx.core.view.updateLayoutParams
5 | import androidx.databinding.DataBindingUtil
6 | import androidx.databinding.ViewDataBinding
7 | import com.bumptech.glide.Glide
8 | import com.chad.library.adapter.base.BaseQuickAdapter
9 | import com.chad.library.adapter.base.viewholder.BaseViewHolder
10 | import com.kt.ktmvvm.R
11 | import com.kt.ktmvvm.databinding.ViewpagerItemLayoutBinding
12 | import com.kt.ktmvvm.databinding.ViewpagerVerticalItemLayoutBinding
13 | import com.kt.ktmvvm.jetpack.viewpager.ViewPager2ViewModel
14 |
15 | class ViewPagerVerticalAdapter(model: ViewPager2ViewModel) :
16 | BaseQuickAdapter(R.layout.viewpager_vertical_item_layout) {
17 |
18 | private var model: ViewPager2ViewModel? = model
19 |
20 |
21 | override fun onBindViewHolder(holder: BaseViewHolder, position: Int) {
22 | super.onBindViewHolder(holder, position)
23 |
24 | }
25 | override fun convert(holder: BaseViewHolder, item: String) {
26 | try {
27 | if (DataBindingUtil.getBinding(holder.itemView) == null) {
28 | ViewpagerVerticalItemLayoutBinding.bind(holder.itemView)
29 | }
30 |
31 | val binding = holder.getBinding()
32 | binding?.model = model
33 |
34 | Glide.with(context).asBitmap().load(item
35 | ).into(binding?.img!!)
36 | } catch (e: Exception) {
37 | }
38 |
39 | }
40 |
41 |
42 | }
--------------------------------------------------------------------------------
/demo/src/main/java/com/kt/ktmvvm/jetpack/camerax/CameraCallBack.kt:
--------------------------------------------------------------------------------
1 | package com.kt.ktmvvm.jetpack.camerax
2 |
3 | interface CameraCallBack {
4 |
5 | fun ratioCallBack(ratio:Int?)
6 | fun takePictureStatus(success:Boolean,msg:String)
7 | }
--------------------------------------------------------------------------------
/demo/src/main/java/com/kt/ktmvvm/jetpack/camerax/CameraParams.kt:
--------------------------------------------------------------------------------
1 | package com.kt.ktmvvm.jetpack.camerax
2 |
3 | import android.annotation.SuppressLint
4 | import android.content.Context
5 | import androidx.camera.extensions.ExtensionMode
6 | import com.kt.ktmvvm.download.manager.DownloadManager
7 | import com.kt.ktmvvm.inner.CameraRatioType
8 |
9 | class CameraParams(context: Context?) {
10 |
11 | companion object {
12 | @SuppressLint("StaticFieldLeak")
13 | private var instance: CameraParams? = null
14 |
15 |
16 | fun get(context: Context?): CameraParams {
17 | if (instance == null) {
18 | synchronized(CameraParams::class.java) {
19 | if (instance == null) {
20 | instance = CameraParams(context)
21 | }
22 | }
23 | }
24 | return instance!!
25 | }
26 | }
27 |
28 | var mFacingFront: Boolean = false //是否是前置摄像头
29 | var mRatioType: Int = CameraRatioType.RATIO_3_4//分辨率尺寸
30 | var mSplashOn: Boolean = false//闪光灯
31 | var torchSwitch: Boolean = false//补光
32 | var timer: Boolean = false//倒计时
33 | var grid: Boolean = false//网格线
34 | var hdr: Boolean = false//hdr
35 | var extensionMode: Int?= ExtensionMode.NONE
36 |
37 | init {
38 | extensionMode = ExtensionMode.NONE
39 | hdr = false
40 | grid = false
41 | timer = false
42 | torchSwitch = false
43 | mFacingFront = false
44 | mRatioType = CameraRatioType.RATIO_3_4
45 | mSplashOn = false
46 | }
47 |
48 |
49 | }
--------------------------------------------------------------------------------
/demo/src/main/java/com/kt/ktmvvm/jetpack/camerax/controller/ICameraController.kt:
--------------------------------------------------------------------------------
1 | package com.kt.ktmvvm.jetpack.camerax.controller
2 |
3 | import com.kt.ktmvvm.inner.CameraRatioType
4 |
5 | interface ICameraController {
6 | /**
7 | * 打开相机
8 | */
9 | fun openCameraPreView()
10 |
11 | /**
12 | * 录像
13 | */
14 | fun takePhoto()
15 |
16 | /**
17 | * 拍照
18 | */
19 | fun takeVideo()
20 |
21 | /**
22 | * 聚焦
23 | */
24 | fun focus(x: Float, y: Float, auto: Boolean)
25 |
26 | /**
27 | * 切换镜头
28 | */
29 |
30 | fun switchCamera()
31 |
32 | /**
33 | * 缩放
34 | */
35 | fun zoom(out: Boolean): Float?
36 |
37 | /**
38 | * 设置分辨率
39 | */
40 | fun setResolution()
41 |
42 | /**
43 | * 照明、补光
44 | */
45 | fun torchSwitch()
46 |
47 | /**
48 | * 闪光灯
49 | */
50 | fun splash()
51 | }
--------------------------------------------------------------------------------
/demo/src/main/java/com/kt/ktmvvm/jetpack/coordinatorlayout/CoordinatorActivity.kt:
--------------------------------------------------------------------------------
1 | package com.kt.ktmvvm.jetpack.coordinatorlayout
2 |
3 | import android.os.Bundle
4 | import android.view.View
5 | import androidx.core.widget.NestedScrollView
6 | import com.google.android.material.bottomsheet.BottomSheetBehavior
7 | import com.kt.ktmvvm.BR
8 | import com.kt.ktmvvm.R
9 | import com.kt.ktmvvm.basic.BaseActivity
10 | import com.kt.ktmvvm.databinding.ActivityCoordinatorLayoutBinding
11 | import com.kt.ktmvvm.widget.MyBottomSheetBehavior
12 |
13 | class CoordinatorActivity : BaseActivity() {
14 | var bottomSheetBehavior: MyBottomSheetBehavior? = null
15 | var starDrawing: Boolean? = false
16 | override fun initVariableId(): Int {
17 | return BR.model
18 | }
19 |
20 | override fun initContentView(savedInstanceState: Bundle?): Int {
21 | return R.layout.activity_coordinator_layout
22 | }
23 |
24 | override fun initParam() {
25 |
26 | bottomSheetBehavior = MyBottomSheetBehavior.from(binding?.bottomSheelt?.nestedView!!)
27 |
28 | bottomSheetBehavior?.addBottomSheetCallback(object :
29 | MyBottomSheetBehavior.BottomSheetCallback() {
30 | override fun onStateChanged(bottomSheet: View, newState: Int) {
31 |
32 | if (newState == BottomSheetBehavior.STATE_EXPANDED) {
33 | bottomSheetBehavior?.isDraggable = false
34 | } else if (newState == BottomSheetBehavior.STATE_COLLAPSED) {
35 | bottomSheetBehavior?.isDraggable = true
36 | }
37 | if (newState == BottomSheetBehavior.STATE_COLLAPSED) {
38 | starDrawing = false
39 | }
40 | }
41 |
42 | override fun onSlide(bottomSheet: View, slideOffset: Float) {
43 | try {
44 |
45 | } catch (e: Exception) {
46 | e.printStackTrace()
47 | }
48 | }
49 | })
50 |
51 | }
52 |
53 | override fun initViewObservable() {
54 | super.initViewObservable()
55 | viewModel?.canVertically?.observe(this, observer = {
56 | if (it==1){
57 | if (bottomSheetBehavior != null && bottomSheetBehavior?.state == MyBottomSheetBehavior.STATE_EXPANDED
58 | && bottomSheetBehavior?.state != MyBottomSheetBehavior.STATE_DRAGGING
59 | && bottomSheetBehavior?.state != MyBottomSheetBehavior.STATE_COLLAPSED && !starDrawing!!
60 | ) {
61 | starDrawing = true
62 | bottomSheetBehavior?.state = MyBottomSheetBehavior.STATE_COLLAPSED
63 | }
64 | }else{
65 | if (bottomSheetBehavior?.state == BottomSheetBehavior.STATE_EXPANDED) {
66 | bottomSheetBehavior?.isDraggable = true
67 | }
68 | }
69 |
70 | })
71 | }
72 | }
--------------------------------------------------------------------------------
/demo/src/main/java/com/kt/ktmvvm/jetpack/coordinatorlayout/CoordinatorViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.kt.ktmvvm.jetpack.coordinatorlayout
2 |
3 | import android.annotation.SuppressLint
4 | import android.app.Application
5 | import android.view.MotionEvent
6 | import android.view.View
7 | import androidx.databinding.ObservableField
8 | import androidx.recyclerview.widget.RecyclerView
9 | import androidx.recyclerview.widget.StaggeredGridLayoutManager
10 | import com.kt.ktmvvm.Constants
11 | import com.kt.ktmvvm.R
12 | import com.kt.ktmvvm.basic.BaseViewModel
13 | import com.kt.ktmvvm.basic.SingleLiveEvent
14 | import com.kt.ktmvvm.decoration.StaggeredDividerItemDecoration
15 | import com.kt.ktmvvm.jetpack.adapter.RcvAdapter
16 | import com.kt.ktmvvm.utils.DisplayUtils
17 |
18 | class CoordinatorViewModel(application: Application) : BaseViewModel(application),
19 | View.OnTouchListener {
20 |
21 | var adapter: ObservableField? = ObservableField(RcvAdapter(this))
22 |
23 | var layoutManager: ObservableField? = ObservableField(
24 | StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL)
25 | )
26 |
27 | var itemDecoration: ObservableField? = ObservableField(
28 | StaggeredDividerItemDecoration(DisplayUtils.dip2px(getApplication(), 10f), getApplication())
29 | )
30 |
31 | var mListener: ObservableField? = ObservableField(OnListener())
32 |
33 | var canVertically: SingleLiveEvent = SingleLiveEvent()
34 |
35 | var touchListener: ObservableField? = ObservableField(this)
36 |
37 | override fun onCreate() {
38 | super.onCreate()
39 | layoutManager?.get()?.apply {
40 | gapStrategy = StaggeredGridLayoutManager.GAP_HANDLING_NONE
41 | isAutoMeasureEnabled = true
42 | }
43 |
44 | adapter?.get()?.setNewInstance(Constants.pictures2)
45 | }
46 |
47 |
48 | fun notifyScroller(newState: Int?, recyclerView: RecyclerView?) {
49 |
50 | if (newState != 0) {
51 | //通知scrolling
52 | //SCROLLING
53 | // canVertically.postValue(0)
54 | }
55 | recyclerView?.parent?.requestDisallowInterceptTouchEvent(true)
56 | val canScrollVertically = recyclerView?.canScrollVertically(-1)
57 | if (!canScrollVertically!! && newState == RecyclerView.SCROLL_STATE_IDLE) {
58 | canVertically.postValue(1)
59 | //CAN_SCROLLVERTICALLY
60 | }
61 | }
62 |
63 |
64 | inner class OnListener : RecyclerView.OnScrollListener() {
65 |
66 | override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
67 | super.onScrollStateChanged(recyclerView, newState)
68 | notifyScroller(newState, recyclerView)
69 | }
70 |
71 | override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
72 | super.onScrolled(recyclerView, dx, dy)
73 | }
74 | }
75 |
76 | @SuppressLint("ClickableViewAccessibility")
77 | override fun onTouch(p0: View?, p1: MotionEvent?): Boolean {
78 | if (p0?.id == R.id.view) {
79 | canVertically.postValue(0)
80 | return true
81 | }
82 | return false
83 | }
84 | }
--------------------------------------------------------------------------------
/demo/src/main/java/com/kt/ktmvvm/jetpack/room/RoomActivity.kt:
--------------------------------------------------------------------------------
1 | package com.kt.ktmvvm.jetpack.room
2 |
3 | import android.os.Bundle
4 | import com.kt.ktmvvm.BR
5 | import com.kt.ktmvvm.R
6 | import com.kt.ktmvvm.basic.BaseActivity
7 | import com.kt.ktmvvm.databinding.RoomActivityBinding
8 |
9 | class RoomActivity : BaseActivity() {
10 | override fun initVariableId(): Int {
11 | return BR.model
12 | }
13 |
14 | override fun initContentView(savedInstanceState: Bundle?): Int {
15 | return R.layout.room_activity
16 | }
17 |
18 | override fun initParam() {
19 |
20 | }
21 | }
--------------------------------------------------------------------------------
/demo/src/main/java/com/kt/ktmvvm/jetpack/room/RoomViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.kt.ktmvvm.jetpack.room
2 |
3 | import android.app.Application
4 | import android.util.Log
5 | import androidx.databinding.ObservableField
6 | import androidx.lifecycle.Observer
7 | import androidx.lifecycle.viewModelScope
8 | import com.kt.ktmvvm.basic.BaseViewModel
9 | import com.kt.ktmvvm.jetpack.room.db.User
10 | import com.kt.ktmvvm.jetpack.room.db.UserDataBase
11 | import com.kt.ktmvvm.jetpack.room.db.UserName
12 | import kotlinx.coroutines.Dispatchers
13 | import kotlinx.coroutines.launch
14 | import kotlin.random.Random
15 |
16 | class RoomViewModel(application: Application) : BaseViewModel(application) {
17 |
18 |
19 | var result: ObservableField? = ObservableField("")
20 |
21 | companion object {
22 | val TAG: String = RoomViewModel::class.java.simpleName
23 | }
24 |
25 | /**
26 | *
27 | */
28 | fun createTable() {
29 | viewModelScope.launch(Dispatchers.IO) {
30 | UserDataBase.get(getApplication())
31 | }
32 | }
33 |
34 |
35 | /**
36 | * 创建一张表
37 | */
38 | fun insertTable() {
39 |
40 | viewModelScope.launch {
41 | val random = (1..10).random()
42 | val hotDog = UserDataBase.get(getApplication()).userDao().findById(random)
43 |
44 | hotDog?.let {
45 | Log.d(TAG, "已经有一条相同的数据啦")
46 | result?.set("已经有一条相同的数据啦")
47 | } ?: randomInsert(random)
48 |
49 | //先查询,如果没这条数据 就插入,有的话打印数据
50 |
51 | }
52 | }
53 |
54 | /**
55 | * 随机更新某条User数据
56 | */
57 | fun updateRandomData() {
58 | //先查询
59 | val random = (1..10).random()
60 |
61 | viewModelScope.launch {
62 | val user = UserDataBase.get(getApplication()).userDao().findById(random)
63 | user?.let {
64 | //如果不为空,则更新
65 | UserDataBase.get(getApplication()).userDao()
66 | .updateUser(User(random, "我是更新整个user后的数据", "男"))
67 | Log.d(TAG, "更新整个user数据成功")
68 | result?.set("更新整个user数据成功")
69 | } ?: randomInsert(random)
70 | }
71 | }
72 |
73 |
74 | /**
75 | * 随机单独更新某个字段
76 | */
77 | fun updateSingleData() {
78 | //先查询
79 | val random = (1..10).random()
80 | viewModelScope.launch {
81 | val user = UserDataBase.get(getApplication()).userDao().findById(random)
82 | user?.let {
83 | UserDataBase.get(getApplication()).userDao()
84 | .updateSingleName(UserName(random, "我是单独更新后的数据"))
85 | Log.d(TAG, "更新单独数据成功")
86 | result?.set("更新单独数据成功")
87 | } ?: randomInsert(random)
88 | }
89 | }
90 |
91 |
92 | /**
93 | * 删除数据
94 | */
95 | fun deleteAllData() {
96 | viewModelScope.launch {
97 | val random = (1..10).random()
98 | val user = UserDataBase.get(getApplication()).userDao().findById(random)
99 | user?.let {
100 | UserDataBase.get(getApplication()).userDao().delete(user)
101 | Log.d(TAG, "删除某条数据成功")
102 | result?.set("删除某条数据成功")
103 | } ?: randomInsert(random)
104 | }
105 | }
106 |
107 |
108 | /**
109 | * 随机插入某条数据,方便测试
110 | */
111 | private fun randomInsert(random: Int) {
112 | val mD = User(random, "热狗先生$random", "女")
113 | UserDataBase.get(getApplication()).userDao().insertAll(mD)
114 | Log.d(TAG, "插入数据成功")
115 | result?.set("插入数据成功")
116 | }
117 | }
--------------------------------------------------------------------------------
/demo/src/main/java/com/kt/ktmvvm/jetpack/room/db/User.kt:
--------------------------------------------------------------------------------
1 | package com.kt.ktmvvm.jetpack.room.db
2 |
3 | import androidx.room.ColumnInfo
4 | import androidx.room.Entity
5 | import androidx.room.PrimaryKey
6 |
7 | @Entity(tableName = "User")
8 | data class User(
9 | @PrimaryKey val uid: Int,
10 | @ColumnInfo(name = "name") val name: String?,
11 | @ColumnInfo(name = "sex") val sex: String?,
12 | )
13 |
14 | data class UserName(val uid: Int, val name: String?)
--------------------------------------------------------------------------------
/demo/src/main/java/com/kt/ktmvvm/jetpack/room/db/UserDao.kt:
--------------------------------------------------------------------------------
1 | package com.kt.ktmvvm.jetpack.room.db
2 |
3 | import androidx.room.*
4 |
5 | @Dao
6 | interface UserDao {
7 |
8 | @Query("SELECT * FROM user")
9 | suspend fun getAll(): List?
10 |
11 | @Query("SELECT * FROM user WHERE uid IN (:userIds)")
12 | suspend fun loadAllByIds(userIds: IntArray): List?
13 |
14 | @Query("SELECT * FROM user WHERE name LIKE :name")
15 | suspend fun findByName(name: String): User?
16 |
17 | @Query("SELECT *FROM user WHERE uid LIKE:userId")
18 | suspend fun findById(userId: Int): User?
19 |
20 | @Update(entity = User::class)
21 | suspend fun updateSingleName(vararg name: UserName?)
22 |
23 | @Update
24 | suspend fun updateUser(vararg user: User)
25 |
26 | @Insert
27 | fun insertAll(vararg users: User)
28 |
29 | @Delete
30 | fun delete(user: User)
31 | }
--------------------------------------------------------------------------------
/demo/src/main/java/com/kt/ktmvvm/jetpack/room/db/UserDataBase.kt:
--------------------------------------------------------------------------------
1 | package com.kt.ktmvvm.jetpack.room.db
2 |
3 | import android.content.Context
4 | import android.util.Log
5 | import androidx.room.Database
6 | import androidx.room.Room
7 | import androidx.room.RoomDatabase
8 | import androidx.room.migration.Migration
9 | import androidx.sqlite.db.SupportSQLiteDatabase
10 |
11 | @Database(entities = [User::class], version = 1,exportSchema =false)
12 | abstract class UserDataBase : RoomDatabase() {
13 | abstract fun userDao(): UserDao
14 |
15 | companion object {
16 | private var instance: UserDataBase? = null
17 |
18 | private val TAG: String? = UserDataBase::class.simpleName
19 |
20 | fun get(context: Context): UserDataBase {
21 | if (instance == null) {
22 | instance = Room.databaseBuilder(context, UserDataBase::class.java, "user_.db")
23 | .fallbackToDestructiveMigration()
24 |
25 | //是否允许在主线程进行查询
26 | .allowMainThreadQueries()
27 | .fallbackToDestructiveMigration()
28 | // .addMigrations(ADD_FIELD_MIGRATION_1_2)
29 | .addCallback(object : Callback() {
30 | override fun onCreate(db: SupportSQLiteDatabase) {
31 | super.onCreate(db)
32 | Log.e(TAG, "onCreate db_name is=" + db.path)
33 | }
34 | })
35 | .build()
36 |
37 |
38 | }
39 | return instance!!
40 | }
41 |
42 |
43 | /**
44 | * 增加字段升级
45 | */
46 | private val ADD_FIELD_MIGRATION_1_2 = object : Migration(1, 2) {
47 | override fun migrate(database: SupportSQLiteDatabase) {
48 | database.execSQL("ALTER TABLE User ADD COLUMN sex Text")
49 |
50 | }
51 | }
52 |
53 | /**
54 | * 删除表升级
55 | */
56 |
57 | }
58 |
59 | }
--------------------------------------------------------------------------------
/demo/src/main/java/com/kt/ktmvvm/jetpack/shapeableimageview/ShapeImageActivity.kt:
--------------------------------------------------------------------------------
1 | package com.kt.ktmvvm.jetpack.shapeableimageview
2 |
3 | import android.os.Bundle
4 | import com.kt.ktmvvm.BR
5 | import com.kt.ktmvvm.R
6 | import com.kt.ktmvvm.basic.BaseActivity
7 | import com.kt.ktmvvm.databinding.ActivityShapeLayoutBinding
8 |
9 | class ShapeImageActivity: BaseActivity() {
10 | override fun initVariableId(): Int {
11 | return BR.model
12 | }
13 |
14 | override fun initContentView(savedInstanceState: Bundle?): Int {
15 | return R.layout.activity_shape_layout
16 | }
17 |
18 | override fun initParam() {
19 |
20 | }
21 | }
--------------------------------------------------------------------------------
/demo/src/main/java/com/kt/ktmvvm/jetpack/shapeableimageview/ShapeImageViewMode.kt:
--------------------------------------------------------------------------------
1 | package com.kt.ktmvvm.jetpack.shapeableimageview
2 |
3 | import android.app.Application
4 | import androidx.databinding.ObservableField
5 | import com.kt.ktmvvm.Constants
6 | import com.kt.ktmvvm.basic.BaseViewModel
7 |
8 | class ShapeImageViewMode(application: Application) :BaseViewModel(application) {
9 |
10 | var imgUrl:ObservableField?= ObservableField(Constants.picture12)
11 | }
--------------------------------------------------------------------------------
/demo/src/main/java/com/kt/ktmvvm/jetpack/viewpager/ScaleInTransformer.kt:
--------------------------------------------------------------------------------
1 | package com.kt.ktmvvm.jetpack.viewpager
2 |
3 | import android.view.View
4 | import androidx.viewpager2.widget.ViewPager2
5 | import java.lang.Math.abs
6 |
7 | class ScaleInTransformer: ViewPager2.PageTransformer {
8 | private val mMinScale = DEFAULT_MIN_SCALE
9 | override fun transformPage(view: View, position: Float) {
10 | view.elevation = -kotlin.math.abs(position)
11 | val pageWidth = view.width
12 | val pageHeight = view.height
13 |
14 | view.pivotY = (pageHeight / 2).toFloat()
15 | view.pivotX = (pageWidth / 2).toFloat()
16 | if (position < -1) {
17 | view.scaleX = mMinScale
18 | view.scaleY = mMinScale
19 | view.pivotX = pageWidth.toFloat()
20 | } else if (position <= 1) {
21 | if (position < 0) {
22 | val scaleFactor = (1 + position) * (1 - mMinScale) + mMinScale
23 | view.scaleX = scaleFactor
24 | view.scaleY = scaleFactor
25 | view.pivotX = pageWidth * (DEFAULT_CENTER + DEFAULT_CENTER * -position)
26 | } else {
27 | val scaleFactor = (1 - position) * (1 - mMinScale) + mMinScale
28 | view.scaleX = scaleFactor
29 | view.scaleY = scaleFactor
30 | view.pivotX = pageWidth * ((1 - position) * DEFAULT_CENTER)
31 | }
32 | } else {
33 | view.pivotX = 0f
34 | view.scaleX = mMinScale
35 | view.scaleY = mMinScale
36 | }
37 | }
38 |
39 | companion object {
40 |
41 | const val DEFAULT_MIN_SCALE = 0.85f
42 | const val DEFAULT_CENTER = 0.5f
43 | }
44 |
45 | }
--------------------------------------------------------------------------------
/demo/src/main/java/com/kt/ktmvvm/jetpack/viewpager/ViewPager2Activity.kt:
--------------------------------------------------------------------------------
1 | package com.kt.ktmvvm.jetpack.viewpager
2 |
3 | import android.os.Bundle
4 | import com.kt.ktmvvm.BR
5 | import com.kt.ktmvvm.R
6 | import com.kt.ktmvvm.basic.BaseActivity
7 | import com.kt.ktmvvm.databinding.Viewpager2LayoutBinding
8 |
9 | class ViewPager2Activity: BaseActivity() {
10 | override fun initVariableId(): Int {
11 | return BR.model
12 | }
13 |
14 | override fun initContentView(savedInstanceState: Bundle?): Int {
15 | return R.layout.viewpager2_layout
16 | }
17 |
18 | override fun initParam() {
19 |
20 | }
21 | }
--------------------------------------------------------------------------------
/demo/src/main/java/com/kt/ktmvvm/jetpack/viewpager/ViewPager2ViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.kt.ktmvvm.jetpack.viewpager
2 |
3 | import android.app.Application
4 | import android.util.Log
5 | import androidx.databinding.ObservableField
6 | import androidx.recyclerview.widget.LinearLayoutManager
7 | import androidx.viewpager2.widget.ViewPager2
8 | import com.kt.ktmvvm.Constants
9 | import com.kt.ktmvvm.basic.BaseViewModel
10 | import com.kt.ktmvvm.jetpack.adapter.ViewPagerAdapter
11 | import com.kt.ktmvvm.jetpack.adapter.ViewPagerVerticalAdapter
12 | import com.kt.ktmvvm.utils.BannerUtils
13 |
14 | class ViewPager2ViewModel(application: Application) : BaseViewModel(application) {
15 |
16 | var adapter: ObservableField? = ObservableField(ViewPagerAdapter(this))
17 | var verticalAdapter: ObservableField? =
18 | ObservableField(ViewPagerVerticalAdapter(this))
19 | var pageListener: ObservableField? =
20 | ObservableField(PageListener())
21 |
22 | var pageCurrentItem: ObservableField? = ObservableField(0)
23 |
24 |
25 |
26 |
27 | override fun onCreate() {
28 | super.onCreate()
29 |
30 | adapter?.get()?.setNewInstance(Constants.pictures)
31 | verticalAdapter?.get()?.setNewInstance(Constants.pictures)
32 | setCurrentItem(0)
33 | }
34 |
35 |
36 | inner class PageListener : ViewPager2.OnPageChangeCallback() {
37 |
38 | override fun onPageSelected(position: Int) {
39 | super.onPageSelected(position)
40 | val size: Int? = adapter?.get()?.data?.size
41 | var currentPosition = size?.let {
42 | BannerUtils.getRealPosition(
43 | isCanLoop(), position,
44 | it
45 | )
46 | }
47 | Log.e(TAG, "the size is$position")
48 | if (size!! > 0 && isCanLoop() && position == 0 || position == Int.MAX_VALUE - 1) {
49 | currentPosition?.let { setCurrentItem(it) }
50 | }
51 |
52 | }
53 |
54 |
55 | }
56 |
57 |
58 | /**
59 | * 是否可以滑动
60 | */
61 | fun isCanLoop(): Boolean {
62 | return true
63 | }
64 |
65 |
66 | private fun setCurrentItem(item: Int) {
67 | if (isCanLoop() && adapter?.get()?.data?.size!! > 1) {
68 | pageCurrentItem?.set(Int.MAX_VALUE / 2 - (Int.MAX_VALUE / 2 % adapter?.get()?.data?.size!!) )
69 | } else {
70 | pageCurrentItem?.set(item)
71 | }
72 | }
73 |
74 | companion object {
75 | val TAG: String? = ViewPager2ViewModel::class.simpleName
76 | }
77 | }
--------------------------------------------------------------------------------
/demo/src/main/java/com/kt/ktmvvm/loader/MimeType.java:
--------------------------------------------------------------------------------
1 | package com.kt.ktmvvm.loader;
2 |
3 | import androidx.collection.ArraySet;
4 |
5 | import java.util.Arrays;
6 | import java.util.EnumSet;
7 | import java.util.Set;
8 |
9 | /**
10 | * 项目支持的媒体类型
11 | */
12 | public enum MimeType {
13 |
14 | // 图片类型
15 | JPEG("image/jpeg", arraySetOf(
16 | "jpeg"
17 | )),
18 | JPG("image/jpg", arraySetOf(
19 | "jpg"
20 | )),
21 | BMP("image/bmp", arraySetOf(
22 | "bmp"
23 | )),
24 | PNG("image/png", arraySetOf(
25 | "png"
26 | )),
27 | GIF("image/gif", arraySetOf(
28 | "gif"
29 | )),
30 |
31 | // 视频类型
32 | MPEG("video/mpeg", arraySetOf(
33 | "mpeg",
34 | "mpg"
35 | )),
36 | MP4("video/mp4", arraySetOf(
37 | "mp4",
38 | "m4v"
39 | )),
40 | GPP("video/3gpp", arraySetOf(
41 | "3gpp"
42 | )),
43 | MKV("video/x-matroska", arraySetOf(
44 | "mkv"
45 | )),
46 | AVI("video/avi", arraySetOf(
47 | "avi"
48 | ));
49 |
50 | private final String mMimeType;
51 | private final Set mExtensions;
52 |
53 | MimeType(String mimeType, Set extensions) {
54 | mMimeType = mimeType;
55 | mExtensions = extensions;
56 | }
57 |
58 | public static Set ofAll() {
59 | return EnumSet.allOf(MimeType.class);
60 | }
61 |
62 | public static Set of(MimeType type, MimeType...rest) {
63 | return EnumSet.of(type, rest);
64 | }
65 |
66 | // 图片
67 | public static Set ofImage() {
68 | return EnumSet.of(JPEG, JPG, PNG, BMP, GIF);
69 | }
70 |
71 | // 视频
72 | public static Set ofVideo() {
73 | return EnumSet.of(MPEG, MP4, GPP, MKV, AVI);
74 | }
75 |
76 | public static boolean isImage(String mimeType) {
77 | if (mimeType == null) return false;
78 | return mimeType.startsWith("image");
79 | }
80 |
81 | public static boolean isVideo(String mimeType) {
82 | if (mimeType == null) return false;
83 | return mimeType.startsWith("video");
84 | }
85 |
86 | private static Set arraySetOf(String... suffixes) {
87 | return new ArraySet<>(Arrays.asList(suffixes));
88 | }
89 |
90 | public Set getExtensions() {
91 | return mExtensions;
92 | }
93 |
94 | public String getMimeType() {
95 | return mMimeType;
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/demo/src/main/java/com/kt/ktmvvm/net/DataService.kt:
--------------------------------------------------------------------------------
1 | @file:OptIn(DelicateCoroutinesApi::class)
2 |
3 | package com.kt.ktmvvm.net
4 |
5 | import com.kt.ktmvvm.MyApp
6 | import kotlinx.coroutines.*
7 |
8 | /**
9 | * 请求管理类
10 | */
11 | class DataService {
12 |
13 |
14 | companion object {
15 |
16 | /**
17 | * 测试登录样例
18 | */
19 | suspend fun login(host: Int, account: String, password: String): BaseResponse {
20 | return RetrofitClient.getInstance(MyApp.get()).getDefault(ApiService::class.java, host)
21 | .login(account, password)
22 | }
23 |
24 | /**
25 | * 获取图书馆信息
26 | */
27 | suspend fun getBookInfo(host: Int): Any? {
28 | return RetrofitClient.getInstance(MyApp.get()).getDefault(ApiService::class.java, host)
29 | .onePiece("","1ddc040748725331b8b841b27977fb82")
30 | }
31 |
32 |
33 | /**
34 | * 历史的今天
35 | */
36 | suspend fun getHistoryDate(host: Int,date:String): Any?{
37 | return RetrofitClient.getInstance(MyApp.get()).getDefault(ApiService::class.java, host)
38 | .history(date,"454fe2a1b8dcf7a0c185ba441de56509")
39 | }
40 |
41 |
42 | fun launch(
43 | block: suspend CoroutineScope.() -> Unit,
44 | onError: (e: Throwable) -> Unit = { _: Throwable -> },
45 | onComplete: () -> Unit = {}
46 | ) {
47 | GlobalScope.launch(
48 | CoroutineExceptionHandler { _, throwable ->
49 | run {
50 | // 这里统一处理错误
51 | ExceptionUtil.catchException(throwable)
52 | onError(throwable)
53 | }
54 | }
55 | ) {
56 | try {
57 | block.invoke(this)
58 | } finally {
59 | onComplete()
60 | }
61 | }
62 | }
63 | }
64 | }
--------------------------------------------------------------------------------
/demo/src/main/java/com/kt/ktmvvm/ui/KeyBordActivity.kt:
--------------------------------------------------------------------------------
1 | package com.kt.ktmvvm.ui
2 |
3 | import android.annotation.SuppressLint
4 | import android.os.Bundle
5 | import android.util.Log
6 | import android.view.MotionEvent
7 | import android.view.View
8 | import androidx.recyclerview.widget.RecyclerView
9 | import com.kt.ktmvvm.BR
10 | import com.kt.ktmvvm.R
11 | import com.kt.ktmvvm.basic.BaseActivity
12 | import com.kt.ktmvvm.databinding.KeybordLayoutBinding
13 | import kotlinx.android.synthetic.main.keybord_layout.*
14 |
15 | class KeyBordActivity : BaseActivity() {
16 | override fun initVariableId(): Int {
17 | return BR.model
18 | }
19 |
20 | override fun initContentView(savedInstanceState: Bundle?): Int {
21 | return R.layout.keybord_layout
22 | }
23 |
24 | @SuppressLint("ClickableViewAccessibility")
25 | override fun initParam() {
26 | recycler.setOnTouchListener(View.OnTouchListener { view, motionEvent ->
27 | if (motionEvent.action == MotionEvent.ACTION_UP) {
28 | val x = motionEvent.x
29 | val y = motionEvent.y
30 | val findItem = findItem(x, y, recycler)
31 | Log.i("KEYBORD=", "x="+x+"y="+y)
32 | Log.i("KEYBORD=", findItem.toString())
33 | }
34 | false
35 | })
36 | }
37 |
38 |
39 | private fun findItem(x: Float, y: Float, recyclerView: RecyclerView): Int {
40 | val findChildViewUnder = recyclerView.findChildViewUnder(x, y)
41 | findChildViewUnder?.let {
42 | val childViewHolder = recyclerView.getChildViewHolder(findChildViewUnder)
43 | childViewHolder?.let {
44 | return childViewHolder.adapterPosition
45 | }
46 | }
47 | return -1
48 | }
49 |
50 | }
--------------------------------------------------------------------------------
/demo/src/main/java/com/kt/ktmvvm/ui/KeyBordAdapter.kt:
--------------------------------------------------------------------------------
1 | package com.kt.ktmvvm.ui
2 |
3 | import android.view.View
4 | import android.view.ViewGroup
5 | import android.widget.ImageView
6 | import com.chad.library.adapter.base.BaseQuickAdapter
7 | import com.chad.library.adapter.base.viewholder.BaseViewHolder
8 | import com.kt.ktmvvm.R
9 |
10 | class KeyBordAdapter : BaseQuickAdapter(R.layout.keybord_item_layout) {
11 |
12 | override fun onBindViewHolder(holder: BaseViewHolder, position: Int) {
13 | super.onBindViewHolder(holder, position)
14 |
15 | val imgIcon = holder.getView(R.id.img_icon)
16 | val desView = holder.getView(R.id.tv_des)
17 | when (position) {
18 | 29 -> {
19 |
20 | //大小写
21 |
22 | imgIcon.apply {
23 | layoutParams.width = 85
24 | layoutParams.height = 65
25 | visibility = View.GONE
26 | // setImageResource(R.drawable.icon_case)
27 | }
28 |
29 | desView.visibility = View.VISIBLE
30 |
31 |
32 | // holder.getItemView()
33 | // .setBackgroundResource(if (isBig) R.drawable.shape_select_bg else R.drawable.shape_un_select_bg)
34 | }
35 | 30 -> {
36 |
37 | imgIcon.apply {
38 | visibility = View.VISIBLE
39 | setImageResource(R.drawable.icon_small_space)
40 | layoutParams.width = 100
41 | layoutParams.height = 50
42 | }
43 | desView.visibility = View.GONE
44 |
45 |
46 | }
47 | data.size - 1 -> {
48 | imgIcon.apply {
49 | visibility = View.VISIBLE
50 | setImageResource(R.drawable.icon_delete)
51 | layoutParams.width = 60
52 | layoutParams.height = 60
53 | }
54 |
55 | desView.visibility = View.GONE
56 |
57 | }
58 | else -> {
59 | imgIcon.visibility = View.GONE
60 | desView.visibility = View.VISIBLE
61 | }
62 | }
63 | }
64 |
65 | override fun convert(holder: BaseViewHolder, item: String) {
66 | holder.setText(R.id.tv_des, item)
67 | }
68 | }
--------------------------------------------------------------------------------
/demo/src/main/java/com/kt/ktmvvm/ui/KeyBordViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.kt.ktmvvm.ui
2 |
3 | import android.app.Application
4 | import androidx.databinding.ObservableField
5 | import androidx.recyclerview.widget.GridLayoutManager
6 | import androidx.recyclerview.widget.GridLayoutManager.SpanSizeLookup
7 | import com.kt.ktmvvm.basic.BaseViewModel
8 | import com.kt.ktmvvm.utils.KeyDataUtils
9 |
10 | class KeyBordViewModel(application: Application) : BaseViewModel(application) {
11 |
12 | var adapter: ObservableField? = ObservableField(KeyBordAdapter())
13 |
14 | var manager: ObservableField? =
15 | ObservableField(GridLayoutManager(getApplication(), 20))
16 |
17 | override fun onCreate() {
18 | super.onCreate()
19 | manager?.get()?.spanSizeLookup = object : SpanSizeLookup() {
20 | override fun getSpanSize(position: Int): Int {
21 | return when (position) {
22 | 20 -> {
23 | 2
24 | }
25 | 30 -> {
26 | 3
27 | }
28 | KeyDataUtils.getLetter().size - 1 -> {
29 | 3
30 | }
31 | else -> {
32 | 2
33 | }
34 | }
35 | }
36 | }
37 |
38 | adapter?.get()?.setNewInstance(KeyDataUtils.getLetter())
39 | }
40 | }
--------------------------------------------------------------------------------
/demo/src/main/java/com/kt/ktmvvm/ui/MosaicActivity.kt:
--------------------------------------------------------------------------------
1 | package com.kt.ktmvvm.ui
2 |
3 | import android.annotation.SuppressLint
4 | import android.graphics.Bitmap
5 | import android.os.Bundle
6 | import android.util.Log
7 | import androidx.lifecycle.Observer
8 | import androidx.lifecycle.lifecycleScope
9 | import com.bumptech.glide.Glide
10 | import com.bumptech.glide.request.target.SimpleTarget
11 | import com.bumptech.glide.request.transition.Transition
12 | import com.kt.ktmvvm.BR
13 | import com.kt.ktmvvm.Constants
14 | import com.kt.ktmvvm.R
15 | import com.kt.ktmvvm.basic.BaseActivity
16 | import com.kt.ktmvvm.databinding.ActivityMosaicLayoutBinding
17 | import com.kt.ktmvvm.utils.BannerUtils
18 | import com.kt.ktmvvm.utils.DisplayUtils
19 | import com.kt.ktmvvm.widget.mosic.DrawMosaicView
20 | import com.kt.ktmvvm.widget.mosic.MosaicUtil
21 | import kotlinx.android.synthetic.main.bottom_sheet_layout.*
22 | import kotlinx.coroutines.Dispatchers
23 | import kotlinx.coroutines.flow.collect
24 | import kotlinx.coroutines.launch
25 |
26 | class MosaicActivity : BaseActivity() {
27 | override fun initVariableId(): Int {
28 | return BR.model
29 | }
30 |
31 | override fun initContentView(savedInstanceState: Bundle?): Int {
32 | return R.layout.activity_mosaic_layout
33 | }
34 |
35 | @SuppressLint("CheckResult")
36 | override fun initParam() {
37 |
38 |
39 | viewModel?.bitmapValue?.observe(this, Observer {
40 | it?.let {
41 | binding?.mosaic?.apply {
42 |
43 | layoutParams.width = it.width
44 | layoutParams.height = it.height
45 | setMosaicBackgroundResource(it, true)
46 | val bit = MosaicUtil.getMosaic(it, MosaicUtil.MosaicFormType.RECT)
47 |
48 | if (bit?.isRecycled == false) {
49 | binding?.mosaic?.setMosaicResource(bit)
50 | binding?.mosaic?.setMosaicBrushWidth(50)
51 | binding?.mosaic?.setOnMosaicStateListener(viewModel!!)
52 | }
53 | }
54 | }
55 | })
56 |
57 |
58 | viewModel?.undo?.observe(this) {
59 | binding?.mosaic?.undoMosaic()
60 | }
61 |
62 |
63 | viewModel?.mosaicType?.observe(this) { it1 ->
64 | val backLayer = binding?.mosaic?.getBackLayer()
65 | var bit: Bitmap?
66 | backLayer?.let {
67 | bit = when (it1) {
68 | 0 -> {
69 | //方形马赛克
70 | MosaicUtil.getMosaic(backLayer, MosaicUtil.MosaicFormType.RECT)
71 | }
72 | 1 -> {
73 | MosaicUtil.getMosaic(backLayer, MosaicUtil.MosaicFormType.CIRCLE)
74 | }
75 | 2 -> {
76 | MosaicUtil.getMosaic(backLayer, MosaicUtil.MosaicFormType.HEXAGONS)
77 | }
78 | else -> {
79 | MosaicUtil.getMosaic(backLayer, MosaicUtil.MosaicFormType.RECT)
80 | }
81 |
82 | }
83 | bit?.let {
84 | if (bit?.isRecycled == false) {
85 | binding?.mosaic?.setMosaicResource(bit)
86 | }
87 | }
88 |
89 |
90 | }
91 |
92 | }
93 | }
94 |
95 |
96 | override fun onDestroy() {
97 | super.onDestroy()
98 | binding?.mosaic?.destroy()
99 | }
100 | }
--------------------------------------------------------------------------------
/demo/src/main/java/com/kt/ktmvvm/ui/MosaicViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.kt.ktmvvm.ui
2 |
3 | import android.app.Application
4 | import android.content.Context
5 | import android.graphics.Bitmap
6 | import android.util.Log
7 | import android.view.View
8 | import android.widget.AdapterView
9 | import androidx.databinding.ObservableField
10 | import androidx.lifecycle.viewModelScope
11 | import com.bumptech.glide.Glide
12 | import com.bumptech.glide.request.target.SimpleTarget
13 | import com.bumptech.glide.request.transition.Transition
14 | import com.kt.ktmvvm.Constants
15 | import com.kt.ktmvvm.basic.BaseViewModel
16 | import com.kt.ktmvvm.basic.SingleLiveEvent
17 | import com.kt.ktmvvm.utils.BannerUtils
18 | import com.kt.ktmvvm.utils.DisplayUtils
19 | import com.kt.ktmvvm.widget.mosic.DrawMosaicView
20 | import com.kt.ktmvvm.widget.mosic.MosaicUtil
21 | import kotlinx.coroutines.flow.*
22 | import kotlinx.coroutines.launch
23 |
24 | class MosaicViewModel(application: Application) : BaseViewModel(application),
25 | DrawMosaicView.OnMosaicStateListener, AdapterView.OnItemSelectedListener {
26 |
27 |
28 | var bitmapValue: SingleLiveEvent? = SingleLiveEvent()
29 | var undo: SingleLiveEvent? = SingleLiveEvent()
30 | var listener: ObservableField? = ObservableField(this)
31 | var mosaicType:SingleLiveEvent?= SingleLiveEvent()
32 |
33 | override fun onCreate() {
34 | super.onCreate()
35 |
36 | Glide.with(getApplication() as Context).asBitmap()
37 | .load(Constants.pic2)
38 | .into(object : SimpleTarget() {
39 | override fun onResourceReady(resource: Bitmap, transition: Transition?) {
40 | if (!resource.isRecycled){
41 | viewModelScope.launch {
42 | flow {
43 | emit(resource)
44 | }.map {
45 | BannerUtils.uniformScale(
46 | it,
47 | DisplayUtils.getScreenHeight(getApplication()),
48 | getApplication()
49 | )
50 | }.collect {
51 | bitmapValue?.postValue(it)
52 | }
53 | }
54 |
55 | }
56 |
57 |
58 | }
59 | })
60 | }
61 |
62 |
63 | /**
64 | * 撤销
65 | */
66 | fun undo() {
67 | undo?.postValue(true)
68 | }
69 |
70 |
71 | override fun mosaicAmount(amountSize: Int?) {
72 |
73 | }
74 |
75 |
76 | override fun onItemSelected(p0: AdapterView<*>?, p1: View?, p2: Int, p3: Long) {
77 | Log.e("TAG", "the po2 is$p2")
78 | mosaicType?.postValue(p2)
79 | }
80 |
81 | override fun onNothingSelected(p0: AdapterView<*>?) {
82 |
83 | }
84 | }
--------------------------------------------------------------------------------
/demo/src/main/java/com/kt/ktmvvm/utils/DisplayUtils.kt:
--------------------------------------------------------------------------------
1 | package com.kt.ktmvvm.utils
2 |
3 | import android.content.Context
4 | import android.util.DisplayMetrics
5 | import android.view.WindowManager
6 |
7 | object DisplayUtils {
8 |
9 | /**
10 | * 将px值转换为dip或dp值,保证尺寸大小不变
11 | *
12 | * @param pxValue (DisplayMetrics类中属性density)
13 | * @return
14 | */
15 | fun px2dip(context: Context, pxValue: Float): Int {
16 | val scale: Float = context.resources.displayMetrics.density
17 | return (pxValue / scale + 0.5f).toInt()
18 | }
19 |
20 | /**
21 | * 将dip或dp值转换为px值,保证尺寸大小不变
22 | *
23 | * @param dipValue (DisplayMetrics类中属性density)
24 | * @return
25 | */
26 | fun dip2px(context: Context?, dipValue: Float): Int {
27 | val scale = context?.resources?.displayMetrics?.density
28 | scale?.let {
29 |
30 | return (dipValue * scale + 0.5f).toInt()
31 | }
32 | return 0
33 | }
34 |
35 |
36 | fun getScreenWidth(context: Context?): Int {
37 | val wm = context?.getSystemService(Context.WINDOW_SERVICE) as WindowManager
38 | val dm = DisplayMetrics()
39 | wm.defaultDisplay.getMetrics(dm)
40 | return dm.widthPixels
41 | }
42 |
43 |
44 | fun getScreenHeight(context: Context?): Int {
45 | val wm = context?.getSystemService(Context.WINDOW_SERVICE) as WindowManager
46 | val dm = DisplayMetrics()
47 | wm.defaultDisplay.getMetrics(dm)
48 | return dm.heightPixels
49 | }
50 | }
--------------------------------------------------------------------------------
/demo/src/main/java/com/kt/ktmvvm/utils/KeyDataUtils.kt:
--------------------------------------------------------------------------------
1 | package com.kt.ktmvvm.utils
2 |
3 | object KeyDataUtils {
4 |
5 | /**
6 | * 获取小写字母按键
7 | * @return
8 | */
9 | fun getLetter(): MutableList {
10 | val list: MutableList = ArrayList()
11 | list.add("1")
12 | list.add("2")
13 | list.add("3")
14 | list.add("4")
15 | list.add("5")
16 | list.add("6")
17 | list.add("7")
18 | list.add("8")
19 | list.add("9")
20 | list.add("0")
21 | list.add("q")
22 | list.add("w")
23 | list.add("e")
24 | list.add("r")
25 | list.add("t")
26 | list.add("y")
27 | list.add("u")
28 | list.add("i")
29 | list.add("o")
30 | list.add("p")
31 | list.add("a")
32 | list.add("s")
33 | list.add("d")
34 | list.add("f")
35 | list.add("g")
36 | list.add("h")
37 | list.add("j")
38 | list.add("k")
39 | list.add("l")
40 | list.add("完成")
41 | list.add("空格")
42 | list.add("z")
43 | list.add("x")
44 | list.add("c")
45 | list.add("v")
46 | list.add("b")
47 | list.add("n")
48 | list.add("m")
49 | list.add("删除")
50 | return list
51 | }
52 | }
--------------------------------------------------------------------------------
/demo/src/main/java/com/kt/ktmvvm/widget/AutoTranslateView.kt:
--------------------------------------------------------------------------------
1 | package com.kt.ktmvvm.widget
2 |
3 | import android.animation.ValueAnimator
4 | import android.annotation.SuppressLint
5 | import android.content.Context
6 | import android.util.AttributeSet
7 | import android.util.Log
8 | import android.view.LayoutInflater
9 | import android.view.View
10 | import android.view.animation.AccelerateDecelerateInterpolator
11 | import android.widget.FrameLayout
12 | import androidx.constraintlayout.widget.Constraints.TAG
13 | import androidx.transition.AutoTransition
14 | import androidx.transition.TransitionManager
15 | import com.kt.ktmvvm.R
16 | import com.kt.ktmvvm.inner.CameraRatioType
17 | import kotlinx.android.synthetic.main.tranlate_view_layout.view.*
18 | import kotlin.math.roundToInt
19 |
20 | class AutoTranslateView : FrameLayout {
21 |
22 | private var isInit = true
23 |
24 |
25 | constructor(context: Context) : super(context) {
26 |
27 | }
28 |
29 | constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {
30 |
31 |
32 | }
33 |
34 | constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(
35 | context,
36 | attrs,
37 | defStyleAttr
38 | ) {
39 |
40 |
41 | }
42 |
43 | @SuppressLint("Recycle")
44 | fun startTranslate(height: Int, type: Int) {
45 | Log.d(TAG, "measuredHeight=" + this.height + "height" + height)
46 | val animator: ValueAnimator =
47 | if ((this.height > height)) {
48 | ValueAnimator.ofInt(this.height, height)
49 | } else if (height == 0 && this.height > 0) {
50 | ValueAnimator.ofInt(this.height, height)
51 | } else if (height > 0 && this.height == 0) {
52 | ValueAnimator.ofInt(this.height, height)
53 | } else if (this.height != 0 && this.height < height) {
54 | ValueAnimator.ofInt(this.height, height)
55 | } else {
56 | ValueAnimator.ofInt(height, this.height)
57 | }
58 |
59 |
60 |
61 |
62 |
63 | animator.addUpdateListener {
64 | val animatedValue = it.animatedValue as Int
65 | Log.d(TAG, "animatedValue=$animatedValue")
66 | this.layoutParams?.height = animatedValue
67 |
68 | requestLayout()
69 | }
70 |
71 |
72 | if (isInit) {
73 | isInit = false
74 | animator.duration = 0
75 | } else {
76 | animator.duration = 200
77 | }
78 | //开始动画
79 | animator.start()
80 | }
81 | }
--------------------------------------------------------------------------------
/demo/src/main/java/com/kt/ktmvvm/widget/FocusView.kt:
--------------------------------------------------------------------------------
1 | package com.kt.ktmvvm.widget
2 |
3 | import android.animation.ObjectAnimator
4 | import android.annotation.SuppressLint
5 | import android.content.Context
6 | import android.graphics.Canvas
7 | import android.graphics.Color
8 | import android.graphics.Paint
9 | import android.graphics.RectF
10 | import android.util.AttributeSet
11 | import android.view.MotionEvent
12 | import android.view.View
13 |
14 | class FocusView : View {
15 |
16 | private var paint: Paint? = null
17 | private val mRectF = RectF()
18 | private var mRectWidth: Float = 10f
19 |
20 | companion object {
21 | const val ANIMATION_SMALL = 500
22 | }
23 |
24 | constructor(context: Context) : super(context) {
25 | initView(context, null)
26 | }
27 |
28 | constructor(context: Context, attributeSet: AttributeSet) : super(context, attributeSet) {
29 | initView(context, attributeSet)
30 | }
31 |
32 |
33 | constructor(context: Context, attributeSet: AttributeSet, defStyleAttr: Int) : super(
34 | context,
35 | attributeSet,
36 | defStyleAttr
37 | ) {
38 |
39 |
40 | }
41 |
42 |
43 |
44 |
45 | private fun initView(context: Context, attributeSet: AttributeSet?) {
46 |
47 | paint = Paint()
48 | paint?.isAntiAlias = true
49 | paint?.color = Color.WHITE
50 | paint?.style = Paint.Style.STROKE
51 | paint?.strokeWidth = 3f
52 |
53 |
54 | }
55 |
56 | override fun onDraw(canvas: Canvas?) {
57 | super.onDraw(canvas)
58 | val width = measuredWidth
59 | val height = measuredHeight
60 |
61 | mRectF.set(
62 | 0f + mRectWidth,
63 | 0f + mRectWidth,
64 | width.toFloat() - mRectWidth,
65 | height.toFloat() - mRectWidth
66 | )
67 | mRectWidth = 10f
68 | canvas?.drawRoundRect(mRectF, 10f, 10f, paint!!)
69 | }
70 |
71 |
72 | /**
73 | * 聚焦动画
74 | */
75 |
76 | fun focusAnimate() {
77 | val lastRectWidth = mRectWidth + 80f
78 |
79 | val rectSizeAnimator = ObjectAnimator.ofFloat(
80 | this, "rectWidth",
81 | mRectWidth, lastRectWidth
82 | ).setDuration(ANIMATION_SMALL.toLong())
83 |
84 |
85 | rectSizeAnimator.start()
86 | }
87 |
88 | /**
89 | * 设置中心矩阵的宽度
90 | *
91 | * @param rectWidth
92 | */
93 | fun setRectWidth(rectWidth: Float) {
94 | mRectWidth = rectWidth
95 | invalidate()
96 | }
97 | }
--------------------------------------------------------------------------------
/demo/src/main/java/com/kt/ktmvvm/widget/GridView.kt:
--------------------------------------------------------------------------------
1 | package com.kt.ktmvvm.widget
2 |
3 | import android.content.Context
4 | import android.graphics.Canvas
5 | import android.graphics.Color
6 | import android.graphics.Paint
7 | import android.util.AttributeSet
8 | import android.view.View
9 | import com.kt.ktmvvm.R
10 |
11 | class GridView : View {
12 |
13 | constructor(context: Context) : super(context) {
14 |
15 | }
16 |
17 | constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {
18 |
19 | initView(context)
20 |
21 | }
22 |
23 |
24 | constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(
25 | context,
26 | attrs,
27 | defStyleAttr
28 | ) {
29 |
30 |
31 | }
32 |
33 | var paint: Paint? = null
34 |
35 |
36 | private fun initView(context: Context) {
37 | //初始化画笔
38 |
39 | paint = Paint()
40 | paint?.isAntiAlias = true
41 | paint?.style = Paint.Style.STROKE
42 | paint?.strokeWidth = 1f
43 | paint?.color =context.resources.getColor(R.color.color_c5c5c5)
44 |
45 | }
46 |
47 | override fun onDraw(canvas: Canvas?) {
48 | super.onDraw(canvas)
49 | val mHeight = height
50 | val mWidth = width
51 | var verLine = 1 / 3f
52 | var horLine = 1 / 3f
53 |
54 | for (i in 0 until 2) {
55 | //绘制横线 第一条在1/3 height上,
56 | canvas?.drawLine(0f, verLine * mHeight, mWidth * 1f, verLine * mHeight, paint!!)
57 | //绘制纵线
58 |
59 | canvas?.drawLine(mWidth * horLine, 0f, mWidth * horLine, mHeight * 1f, paint!!)
60 |
61 | horLine = 2 / 3f
62 | verLine = 2 / 3f
63 |
64 | }
65 | }
66 | }
--------------------------------------------------------------------------------
/demo/src/main/java/com/kt/ktmvvm/widget/PopWin.kt:
--------------------------------------------------------------------------------
1 | package com.kt.ktmvvm.widget
2 |
3 | import android.content.Context
4 | import android.graphics.drawable.ColorDrawable
5 | import android.view.LayoutInflater
6 | import android.view.View
7 | import android.view.ViewGroup
8 | import android.view.animation.DecelerateInterpolator
9 | import android.widget.CompoundButton
10 | import android.widget.PopupWindow
11 | import androidx.camera.extensions.ExtensionMode
12 | import androidx.databinding.DataBindingUtil
13 | import androidx.transition.AutoTransition
14 | import androidx.transition.TransitionManager
15 | import com.kt.ktmvvm.R
16 | import com.kt.ktmvvm.databinding.PopuLayoutBinding
17 | import com.kt.ktmvvm.jetpack.camerax.CameraParams
18 |
19 | class PopWin(context: Context?) : PopupWindow(context), View.OnClickListener {
20 |
21 |
22 | private var listener: OnPopCheckListener? = null
23 | private var mContext = context
24 | var binding: PopuLayoutBinding? = null
25 | var cameraParams: CameraParams? = null
26 |
27 | init {
28 | binding = DataBindingUtil.inflate(
29 | LayoutInflater.from(context),
30 | R.layout.popu_layout,
31 | null,
32 | false
33 |
34 | )
35 |
36 | cameraParams = CameraParams.get(context)
37 |
38 | isClippingEnabled = false
39 | contentView = binding?.root
40 | width = ViewGroup.LayoutParams.MATCH_PARENT
41 | height = ViewGroup.LayoutParams.WRAP_CONTENT
42 | isFocusable = false
43 | setBackgroundDrawable(ColorDrawable(0))
44 | }
45 |
46 |
47 | private fun dip2px(context: Context?, dipValue: Float): Int {
48 | val scale = context!!.resources.displayMetrics.density
49 | return (dipValue * scale + 0.5f).toInt()
50 | }
51 |
52 | fun hidePop() {
53 | if (isShowing) {
54 | dismiss()
55 | }
56 | }
57 |
58 | /**
59 | * 显示Pop
60 | */
61 | fun showPop(view: View?) {
62 | if (isShowing) {
63 | dismiss()
64 | } else {
65 | showAsDropDown(view)
66 | binding?.lightLayout?.setOnClickListener(this)
67 | binding?.timerLayout?.setOnClickListener(this)
68 | binding?.spashLayout?.setOnClickListener(this)
69 | binding?.gridLayou?.setOnClickListener(this)
70 | binding?.hdrLayout?.setOnClickListener(this)
71 |
72 | }
73 | }
74 |
75 | fun setOnPopCheckListener(listener: OnPopCheckListener?) {
76 | this.listener = listener
77 | }
78 |
79 |
80 | interface OnPopCheckListener {
81 | fun lightCheck()
82 | fun delay()
83 | fun splash()
84 | fun grid()
85 | fun hdr()
86 | }
87 |
88 |
89 | override fun onClick(p0: View?) {
90 |
91 | when (p0?.id) {
92 | R.id.light_layout -> {
93 | cameraParams?.torchSwitch = !cameraParams?.torchSwitch!!
94 | binding?.ivLight?.isSelected = cameraParams?.torchSwitch!!
95 | binding?.nightLight?.isSelected = cameraParams?.torchSwitch!!
96 | listener?.lightCheck()
97 | }
98 | R.id.timer_layout -> {
99 | cameraParams?.timer = !cameraParams?.timer!!
100 | binding?.ivTimer?.isSelected = cameraParams?.timer!!
101 | binding?.timer?.isSelected = cameraParams?.timer!!
102 | listener?.delay()
103 | }
104 | R.id.spash_layout -> {
105 | cameraParams?.mSplashOn = !cameraParams?.mSplashOn!!
106 | binding?.ivSplash?.isSelected=cameraParams?.mSplashOn!!
107 | binding?.splashLine?.isSelected=cameraParams?.mSplashOn!!
108 | listener?.splash()
109 | }
110 | R.id.grid_layou -> {
111 | cameraParams?.grid = !cameraParams?.grid!!
112 | binding?.ivGrid?.isSelected=cameraParams?.grid!!
113 | binding?.gridLine?.isSelected=cameraParams?.grid!!
114 | listener?.grid()
115 | }
116 | R.id.hdr_layout -> {
117 | cameraParams?.hdr = !cameraParams?.hdr!!
118 | binding?.ivHdr?.isSelected=cameraParams?.hdr!!
119 | binding?.hdr?.isSelected=cameraParams?.hdr!!
120 | if (cameraParams?.hdr==true){
121 | cameraParams?.extensionMode=ExtensionMode.HDR
122 | }else{
123 | cameraParams?.extensionMode=ExtensionMode.NONE
124 | }
125 | listener?.hdr()
126 | }
127 | }
128 | }
129 |
130 | }
--------------------------------------------------------------------------------
/demo/src/main/java/com/kt/ktmvvm/widget/RecordCountDownView.java:
--------------------------------------------------------------------------------
1 | package com.kt.ktmvvm.widget;
2 |
3 | import android.content.Context;
4 | import android.os.Handler;
5 | import android.os.Message;
6 | import android.util.AttributeSet;
7 | import android.view.Gravity;
8 | import android.view.animation.Animation;
9 | import android.view.animation.AnimationUtils;
10 |
11 | import androidx.annotation.NonNull;
12 | import androidx.annotation.Nullable;
13 | import androidx.appcompat.widget.AppCompatTextView;
14 |
15 |
16 | import com.kt.ktmvvm.R;
17 |
18 | import java.lang.ref.WeakReference;
19 |
20 | /**
21 | * 录制倒计时显示控件
22 | */
23 | public class RecordCountDownView extends AppCompatTextView {
24 |
25 | private static final int COUNT_DOWN = 0x001;
26 |
27 | private static final int COUNT_DURATION = 1000;
28 | private int mCountDown = 3;
29 |
30 | // 是否处于倒计时阶段
31 | private volatile boolean isCountDowning;
32 |
33 | private OnCountDownListener mListener;
34 | private final CountDownHandler mHandler;
35 |
36 | public RecordCountDownView(Context context) {
37 | this(context, null);
38 | }
39 |
40 | public RecordCountDownView(Context context, @Nullable AttributeSet attrs) {
41 | this(context, attrs, 0);
42 | }
43 |
44 | public RecordCountDownView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
45 | super(context, attrs, defStyleAttr);
46 | setGravity(Gravity.CENTER);
47 | mHandler = new CountDownHandler(this);
48 | }
49 |
50 | /**
51 | * 设置倒计时时长
52 | * @param countDown
53 | */
54 | public void setCountDown(int countDown) {
55 | mCountDown = countDown;
56 | }
57 |
58 | /**
59 | * 取消倒计时
60 | */
61 | public void cancel() {
62 | mHandler.removeCallbacksAndMessages(null);
63 | setText("");
64 | if (mListener != null) {
65 | mListener.onCountDownCancel();
66 | }
67 | isCountDowning = false;
68 | }
69 |
70 | /**
71 | * 开始倒计时
72 | */
73 | public void start() {
74 | isCountDowning = true;
75 | mHandler.sendMessage(mHandler.obtainMessage(COUNT_DOWN, mCountDown, 0));
76 | }
77 |
78 | /**
79 | * 判断是否正处于倒计时阶段
80 | * @return
81 | */
82 | public boolean isCountDowning() {
83 | return isCountDowning;
84 | }
85 |
86 | /**
87 | * 更新文字的动画
88 | */
89 | private void updateTextAnimate() {
90 | Animation enterAnimation = AnimationUtils.loadAnimation(getContext(), R.anim.anim_fade_in);
91 | startAnimation(enterAnimation);
92 | }
93 |
94 | public interface OnCountDownListener {
95 |
96 | void onCountDownEnd();
97 |
98 | void onCountDownCancel();
99 | }
100 |
101 | public void addOnCountDownListener(OnCountDownListener listener) {
102 | mListener = listener;
103 | }
104 |
105 | private static class CountDownHandler extends Handler {
106 |
107 | private final WeakReference mWeakCountDownView;
108 |
109 | public CountDownHandler(@NonNull RecordCountDownView countDownView) {
110 | mWeakCountDownView = new WeakReference<>(countDownView);
111 | }
112 |
113 | @Override
114 | public void handleMessage(Message msg) {
115 | if (mWeakCountDownView.get() == null) {
116 | return;
117 | }
118 | RecordCountDownView countDownView = mWeakCountDownView.get();
119 | switch (msg.what) {
120 | case COUNT_DOWN:
121 | if (msg.arg1 > 0) {
122 | countDownView.setText(String.valueOf(msg.arg1));
123 | countDownView.updateTextAnimate();
124 | sendMessageDelayed(obtainMessage(COUNT_DOWN, msg.arg1 - 1, 0), COUNT_DURATION);
125 | } else {
126 | countDownView.setText("");
127 | if (countDownView.mListener != null) {
128 | countDownView.mListener.onCountDownEnd();
129 | }
130 | countDownView.isCountDowning = false;
131 | }
132 | break;
133 | }
134 | }
135 | }
136 | }
137 |
--------------------------------------------------------------------------------
/demo/src/main/java/com/kt/ktmvvm/widget/TakePhotoView.kt:
--------------------------------------------------------------------------------
1 | package com.kt.ktmvvm.widget
2 |
3 | import android.animation.AnimatorSet
4 | import android.animation.ObjectAnimator
5 | import android.annotation.SuppressLint
6 | import android.content.Context
7 | import android.util.AttributeSet
8 | import android.view.LayoutInflater
9 | import android.view.MotionEvent
10 | import android.view.View
11 | import android.widget.RelativeLayout
12 | import androidx.databinding.DataBindingUtil
13 | import com.kt.ktmvvm.R
14 | import com.kt.ktmvvm.databinding.TakePhotoViewBinding
15 | import kotlin.math.abs
16 |
17 | class TakePhotoView : RelativeLayout {
18 |
19 | private var listener: OnBottomTabClick? = null
20 | private var binding: TakePhotoViewBinding? = null
21 | private var isDown = false
22 | constructor(context: Context) : super(context) {
23 |
24 | }
25 |
26 | constructor(context: Context, attributeSet: AttributeSet) : super(context, attributeSet) {
27 |
28 | initView(context, attributeSet)
29 | }
30 |
31 |
32 | constructor(context: Context, attributeSet: AttributeSet, defStyleAttr: Int) : super(
33 | context,
34 | attributeSet,
35 | defStyleAttr
36 | ) {
37 |
38 |
39 | }
40 |
41 | @SuppressLint("ClickableViewAccessibility")
42 | private fun initView(context: Context, attributeSet: AttributeSet) {
43 |
44 | binding = DataBindingUtil.inflate(
45 | LayoutInflater.from(context),
46 | R.layout.take_photo_view,
47 | this,
48 | true
49 | )
50 |
51 | // binding?.takePicture?.setOnTouchListener { v: View?, event: MotionEvent ->
52 | // when (event.action) {
53 | // MotionEvent.ACTION_DOWN -> {
54 | // if (!isDown) {
55 | // binding?.takePicture?.setBackgroundResource(R.drawable.icon_take_picture_down)
56 | // }
57 | // isDown = true
58 | // return@setOnTouchListener true
59 | // }
60 | // MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
61 | // binding?.takePicture?.setBackgroundResource(R.drawable.icon_take_picture_normal)
62 | // isDown = false
63 | // if (listener != null) {
64 | // listener?.takePicture()
65 | // }
66 | // return@setOnTouchListener true
67 | // }
68 | // }
69 | // false
70 | // }
71 | binding?.takePicture?.setOnClickListener {
72 | if (isFastClick()) {
73 | return@setOnClickListener
74 | }
75 | startTakePictureAnimation()
76 | listener?.takePicture()
77 | }
78 |
79 |
80 | }
81 |
82 |
83 | /**
84 | * 开启按钮动效
85 | */
86 | private fun startTakePictureAnimation() {
87 | binding?.takePicture?.let {
88 | val animatorX =
89 | ObjectAnimator.ofFloat(binding?.takePicture, "scaleX", 1.0f, 0.8f, 0.8f, 1.0f)
90 | val animatorY =
91 | ObjectAnimator.ofFloat(binding?.takePicture, "scaleY", 1.0f, 0.8f, 0.8f, 1.0f)
92 | val set = AnimatorSet()
93 | set.play(animatorX).with(animatorY)
94 | set.duration = 50
95 | set.start()
96 | }
97 |
98 | }
99 |
100 |
101 | companion object {
102 | private var CLEAN_DELAY_CLICK_FAST = 0L
103 |
104 | fun isFastClick(): Boolean {
105 | val curClickTime = System.currentTimeMillis()
106 | //500ms不让重复点击 避免用户先把时间跳到后几天在调回来时点不动按钮的问题
107 | val timeInterval: Long =
108 | abs(curClickTime - CLEAN_DELAY_CLICK_FAST)
109 | return if (timeInterval <= 800) {
110 | true
111 | } else {
112 | CLEAN_DELAY_CLICK_FAST = curClickTime
113 | false
114 | }
115 | }
116 | }
117 |
118 | fun setOnBottomTabClick(bottomTabClick: OnBottomTabClick) {
119 | this.listener = bottomTabClick
120 | }
121 |
122 | interface OnBottomTabClick {
123 | fun reset()
124 | fun takePicture()
125 | fun closeDown()
126 | }
127 |
128 | }
--------------------------------------------------------------------------------
/demo/src/main/java/com/kt/ktmvvm/widget/TimerHelper.kt:
--------------------------------------------------------------------------------
1 | package com.kt.ktmvvm.widget
2 |
3 | import android.animation.Animator
4 | import android.animation.AnimatorListenerAdapter
5 | import android.animation.ValueAnimator
6 | import android.view.animation.LinearInterpolator
7 | import com.blankj.utilcode.util.StringUtils
8 | import com.kt.ktmvvm.R
9 |
10 |
11 | /**
12 | * 计时器
13 | */
14 | class TimerHelper {
15 | private var animator: ValueAnimator? = null
16 | private var currentTime: Long = 0
17 | private var onTimerHelperListener: OnTimerHelperListener? = null
18 |
19 |
20 | fun startTimer(time: Long) {
21 | if (time <= 0) {
22 | return
23 | }
24 | stopTimer()
25 | currentTime = time
26 | if (animator == null) {
27 | animator = ValueAnimator.ofInt(60, 0)
28 | }
29 | if (animator?.isRunning == true) return
30 | animator?.interpolator = LinearInterpolator()
31 | animator?.duration = 1000
32 | animator?.repeatCount = ValueAnimator.INFINITE
33 | animator?.repeatMode = ValueAnimator.RESTART
34 | animator?.addUpdateListener { animation: ValueAnimator ->
35 | val progress = animation.animatedValue as Int
36 | val progressText = covertTime(currentTime, progress)
37 | if (onTimerHelperListener != null) {
38 | onTimerHelperListener?.onProgress(progressText)
39 | }
40 | }
41 | animator?.addListener(object : AnimatorListenerAdapter() {
42 | override fun onAnimationRepeat(animation: Animator) {
43 | currentTime -= 1000
44 | if (currentTime <= 0) {
45 | stopTimer()
46 | if (onTimerHelperListener != null) {
47 | onTimerHelperListener?.onOverTimer()
48 | }
49 | }
50 | }
51 | })
52 | animator?.start()
53 | }
54 |
55 |
56 | fun stopTimer() {
57 | if (animator != null) {
58 | animator?.cancel()
59 | animator = null
60 | }
61 | }
62 |
63 | fun setOnTimerHelperListener(listener: OnTimerHelperListener?) {
64 | onTimerHelperListener = listener
65 | }
66 |
67 | private fun covertTime(time: Long, suffix: Int): String {
68 | if (time <= 0) {
69 | return "00:00:00"
70 | }
71 | val total = (time / 1000).toInt()
72 | val minute = total / 60
73 | val second = total % 60
74 | return if (minute <= 0) {
75 | StringUtils.getString(R.string.second_format, second, suffix)
76 | } else {
77 | val len = minute.toString().length
78 | if (len < 3) {
79 | StringUtils.getString(R.string.minute_second_format, minute, second, suffix)
80 | } else {
81 | StringUtils.getString(R.string.minute_second_format1, minute, second, suffix)
82 | }
83 | }
84 | }
85 |
86 | interface OnTimerHelperListener {
87 | fun onProgress(progress: String?) {}
88 | fun onOverTimer()
89 | }
90 | }
--------------------------------------------------------------------------------
/demo/src/main/java/com/kt/ktmvvm/widget/TopView.kt:
--------------------------------------------------------------------------------
1 | package com.kt.ktmvvm.widget
2 |
3 | import android.annotation.SuppressLint
4 | import android.content.Context
5 | import android.util.AttributeSet
6 | import android.view.LayoutInflater
7 | import android.view.MotionEvent
8 | import android.view.View
9 | import android.widget.RelativeLayout
10 | import androidx.databinding.DataBindingUtil
11 | import com.kt.ktmvvm.R
12 | import com.kt.ktmvvm.databinding.TopFactorLayoutBinding
13 |
14 | class TopView : RelativeLayout {
15 |
16 |
17 | private var popWinListener: PopWin.OnPopCheckListener? = null
18 | private var ratioListener: RatioPop.OnRatioViewListener? = null
19 | private var listener: OnTopViewListener? = null
20 | private var popWin: PopWin? = null
21 | private var ratioPop: RatioPop? = null
22 |
23 | constructor(context: Context) : super(context) {
24 |
25 | }
26 |
27 | constructor(context: Context, attributeSet: AttributeSet) : super(context, attributeSet) {
28 |
29 | initView(context, attributeSet)
30 | }
31 |
32 |
33 | constructor(context: Context, attributeSet: AttributeSet, defStyleAttr: Int) : super(
34 | context,
35 | attributeSet,
36 | defStyleAttr
37 | ) {
38 |
39 |
40 | }
41 |
42 |
43 | private fun initView(context: Context, attributeSet: AttributeSet) {
44 |
45 | val binding = DataBindingUtil.inflate(
46 | LayoutInflater.from(context),
47 | R.layout.top_factor_layout,
48 | this,
49 | true
50 | )
51 |
52 |
53 | binding.flBackPage.setOnClickListener {
54 | addClickScale(binding.flBackPage)
55 | listener?.backCamera()
56 | }
57 |
58 | binding.flSetting.setOnClickListener {
59 | addClickScale(binding.flSetting)
60 | if (popWin == null) {
61 | popWin = PopWin(context)
62 | }
63 | popWin?.setOnPopCheckListener(popWinListener)
64 | ratioPop?.hidePop()
65 | popWin?.showPop(binding?.top)
66 | }
67 |
68 | binding.flBl.setOnClickListener {
69 | addClickScale(binding.flBl)
70 | if (ratioPop == null) {
71 | ratioPop = RatioPop(context)
72 | }
73 | ratioPop?.setOnRatioViewListener(ratioListener)
74 | popWin?.hidePop()
75 | ratioPop?.showPop(binding.top)
76 | }
77 |
78 | }
79 |
80 | fun hideSettingPop(){
81 | popWin?.hidePop()
82 | }
83 | fun hideRatioPop(){
84 | ratioPop?.hidePop()
85 | }
86 |
87 | fun setOnPopCheckListener(listener: PopWin.OnPopCheckListener) {
88 | this.popWinListener = listener
89 | }
90 |
91 | fun setOnRatioViewListener(listener: RatioPop.OnRatioViewListener) {
92 | this.ratioListener = listener
93 | }
94 |
95 | fun setOnTopViewListener(listener: OnTopViewListener) {
96 | this.listener = listener
97 | }
98 |
99 | interface OnTopViewListener {
100 | fun backCamera()
101 |
102 | }
103 |
104 | @SuppressLint("ClickableViewAccessibility")
105 | fun addClickScale(view: View, scale: Float = 0.8f, duration: Long = 100) {
106 | view.setOnTouchListener { _, event ->
107 | when (event.action) {
108 | MotionEvent.ACTION_DOWN -> {
109 | view.animate().scaleX(scale).scaleY(scale).setDuration(duration).start()
110 | }
111 | MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
112 | view.animate().scaleX(1f).scaleY(1f).setDuration(duration).start()
113 | }
114 | }
115 | // 点击事件处理,交给View自身
116 | view.onTouchEvent(event)
117 | }
118 | }
119 | }
--------------------------------------------------------------------------------
/demo/src/main/java/com/kt/ktmvvm/widget/TranslateView.kt:
--------------------------------------------------------------------------------
1 | package com.kt.ktmvvm.widget
2 |
3 | import android.content.Context
4 | import android.util.AttributeSet
5 | import android.view.MotionEvent
6 | import android.widget.RelativeLayout
7 |
8 | class TranslateView : RelativeLayout {
9 | private var listener: OnTranslateTouchListener? = null
10 |
11 | constructor(context: Context) : super(context) {
12 |
13 | }
14 |
15 | constructor(context: Context, attributeSet: AttributeSet) : super(context, attributeSet) {
16 |
17 |
18 | }
19 |
20 |
21 | constructor(context: Context, attributeSet: AttributeSet, defStyleAttr: Int) : super(
22 | context,
23 | attributeSet,
24 | defStyleAttr
25 | ) {
26 |
27 |
28 | }
29 |
30 | override fun onTouchEvent(event: MotionEvent?): Boolean {
31 | listener?.touchTrans()
32 | return super.onTouchEvent(event)
33 | }
34 |
35 | fun setOnTranslateTouchListener(listener: OnTranslateTouchListener) {
36 | this.listener = listener
37 | }
38 |
39 | interface OnTranslateTouchListener {
40 | fun touchTrans()
41 | }
42 | }
--------------------------------------------------------------------------------
/demo/src/main/java/com/kt/ktmvvm/widget/mosic/MosaicPath.kt:
--------------------------------------------------------------------------------
1 | package com.kt.ktmvvm.widget.mosic
2 |
3 | import android.graphics.Path
4 |
5 | class MosaicPath{
6 |
7 | /**
8 | * 绘画路径
9 | */
10 | var drawPath: Path? = null
11 |
12 | /**
13 | * 绘画粗细
14 | */
15 | var paintWidth = 0
16 | }
--------------------------------------------------------------------------------
/demo/src/main/res/anim/anim_fade_in.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
--------------------------------------------------------------------------------
/demo/src/main/res/color/color_selector.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/demo/src/main/res/color/po_color_selector.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/demo/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
15 |
18 |
21 |
22 |
23 |
24 |
30 |
--------------------------------------------------------------------------------
/demo/src/main/res/drawable-xxhdpi/bishua2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ljlstudio/KtMvvm/4081488f829810864922fe78557f1ebd587e3b11/demo/src/main/res/drawable-xxhdpi/bishua2.png
--------------------------------------------------------------------------------
/demo/src/main/res/drawable-xxhdpi/bishua3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ljlstudio/KtMvvm/4081488f829810864922fe78557f1ebd587e3b11/demo/src/main/res/drawable-xxhdpi/bishua3.png
--------------------------------------------------------------------------------
/demo/src/main/res/drawable-xxhdpi/bishua4.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ljlstudio/KtMvvm/4081488f829810864922fe78557f1ebd587e3b11/demo/src/main/res/drawable-xxhdpi/bishua4.jpg
--------------------------------------------------------------------------------
/demo/src/main/res/drawable-xxhdpi/gird_off.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ljlstudio/KtMvvm/4081488f829810864922fe78557f1ebd587e3b11/demo/src/main/res/drawable-xxhdpi/gird_off.png
--------------------------------------------------------------------------------
/demo/src/main/res/drawable-xxhdpi/gird_on.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ljlstudio/KtMvvm/4081488f829810864922fe78557f1ebd587e3b11/demo/src/main/res/drawable-xxhdpi/gird_on.png
--------------------------------------------------------------------------------
/demo/src/main/res/drawable-xxhdpi/hdr_off.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ljlstudio/KtMvvm/4081488f829810864922fe78557f1ebd587e3b11/demo/src/main/res/drawable-xxhdpi/hdr_off.png
--------------------------------------------------------------------------------
/demo/src/main/res/drawable-xxhdpi/hdr_on.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ljlstudio/KtMvvm/4081488f829810864922fe78557f1ebd587e3b11/demo/src/main/res/drawable-xxhdpi/hdr_on.png
--------------------------------------------------------------------------------
/demo/src/main/res/drawable-xxhdpi/icon_bg_space.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ljlstudio/KtMvvm/4081488f829810864922fe78557f1ebd587e3b11/demo/src/main/res/drawable-xxhdpi/icon_bg_space.png
--------------------------------------------------------------------------------
/demo/src/main/res/drawable-xxhdpi/icon_bl.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ljlstudio/KtMvvm/4081488f829810864922fe78557f1ebd587e3b11/demo/src/main/res/drawable-xxhdpi/icon_bl.png
--------------------------------------------------------------------------------
/demo/src/main/res/drawable-xxhdpi/icon_camera_close_normal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ljlstudio/KtMvvm/4081488f829810864922fe78557f1ebd587e3b11/demo/src/main/res/drawable-xxhdpi/icon_camera_close_normal.png
--------------------------------------------------------------------------------
/demo/src/main/res/drawable-xxhdpi/icon_camera_close_pressed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ljlstudio/KtMvvm/4081488f829810864922fe78557f1ebd587e3b11/demo/src/main/res/drawable-xxhdpi/icon_camera_close_pressed.png
--------------------------------------------------------------------------------
/demo/src/main/res/drawable-xxhdpi/icon_case.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ljlstudio/KtMvvm/4081488f829810864922fe78557f1ebd587e3b11/demo/src/main/res/drawable-xxhdpi/icon_case.png
--------------------------------------------------------------------------------
/demo/src/main/res/drawable-xxhdpi/icon_delete.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ljlstudio/KtMvvm/4081488f829810864922fe78557f1ebd587e3b11/demo/src/main/res/drawable-xxhdpi/icon_delete.png
--------------------------------------------------------------------------------
/demo/src/main/res/drawable-xxhdpi/icon_reset_camera.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ljlstudio/KtMvvm/4081488f829810864922fe78557f1ebd587e3b11/demo/src/main/res/drawable-xxhdpi/icon_reset_camera.png
--------------------------------------------------------------------------------
/demo/src/main/res/drawable-xxhdpi/icon_small_space.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ljlstudio/KtMvvm/4081488f829810864922fe78557f1ebd587e3b11/demo/src/main/res/drawable-xxhdpi/icon_small_space.png
--------------------------------------------------------------------------------
/demo/src/main/res/drawable-xxhdpi/icon_switch_camera_normal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ljlstudio/KtMvvm/4081488f829810864922fe78557f1ebd587e3b11/demo/src/main/res/drawable-xxhdpi/icon_switch_camera_normal.png
--------------------------------------------------------------------------------
/demo/src/main/res/drawable-xxhdpi/icon_switch_camera_pressed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ljlstudio/KtMvvm/4081488f829810864922fe78557f1ebd587e3b11/demo/src/main/res/drawable-xxhdpi/icon_switch_camera_pressed.png
--------------------------------------------------------------------------------
/demo/src/main/res/drawable-xxhdpi/icon_take_picture_down.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ljlstudio/KtMvvm/4081488f829810864922fe78557f1ebd587e3b11/demo/src/main/res/drawable-xxhdpi/icon_take_picture_down.png
--------------------------------------------------------------------------------
/demo/src/main/res/drawable-xxhdpi/icon_take_picture_normal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ljlstudio/KtMvvm/4081488f829810864922fe78557f1ebd587e3b11/demo/src/main/res/drawable-xxhdpi/icon_take_picture_normal.png
--------------------------------------------------------------------------------
/demo/src/main/res/drawable-xxhdpi/icon_take_picture_sticker_normal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ljlstudio/KtMvvm/4081488f829810864922fe78557f1ebd587e3b11/demo/src/main/res/drawable-xxhdpi/icon_take_picture_sticker_normal.png
--------------------------------------------------------------------------------
/demo/src/main/res/drawable-xxhdpi/icon_take_picture_sticker_pressed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ljlstudio/KtMvvm/4081488f829810864922fe78557f1ebd587e3b11/demo/src/main/res/drawable-xxhdpi/icon_take_picture_sticker_pressed.png
--------------------------------------------------------------------------------
/demo/src/main/res/drawable-xxhdpi/icon_top_setting.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ljlstudio/KtMvvm/4081488f829810864922fe78557f1ebd587e3b11/demo/src/main/res/drawable-xxhdpi/icon_top_setting.png
--------------------------------------------------------------------------------
/demo/src/main/res/drawable-xxhdpi/light_check.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ljlstudio/KtMvvm/4081488f829810864922fe78557f1ebd587e3b11/demo/src/main/res/drawable-xxhdpi/light_check.png
--------------------------------------------------------------------------------
/demo/src/main/res/drawable-xxhdpi/light_normal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ljlstudio/KtMvvm/4081488f829810864922fe78557f1ebd587e3b11/demo/src/main/res/drawable-xxhdpi/light_normal.png
--------------------------------------------------------------------------------
/demo/src/main/res/drawable-xxhdpi/maoshua.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ljlstudio/KtMvvm/4081488f829810864922fe78557f1ebd587e3b11/demo/src/main/res/drawable-xxhdpi/maoshua.jpg
--------------------------------------------------------------------------------
/demo/src/main/res/drawable-xxhdpi/splash_close.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ljlstudio/KtMvvm/4081488f829810864922fe78557f1ebd587e3b11/demo/src/main/res/drawable-xxhdpi/splash_close.png
--------------------------------------------------------------------------------
/demo/src/main/res/drawable-xxhdpi/splash_open.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ljlstudio/KtMvvm/4081488f829810864922fe78557f1ebd587e3b11/demo/src/main/res/drawable-xxhdpi/splash_open.png
--------------------------------------------------------------------------------
/demo/src/main/res/drawable-xxhdpi/timer_off.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ljlstudio/KtMvvm/4081488f829810864922fe78557f1ebd587e3b11/demo/src/main/res/drawable-xxhdpi/timer_off.png
--------------------------------------------------------------------------------
/demo/src/main/res/drawable-xxhdpi/timer_on.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ljlstudio/KtMvvm/4081488f829810864922fe78557f1ebd587e3b11/demo/src/main/res/drawable-xxhdpi/timer_on.png
--------------------------------------------------------------------------------
/demo/src/main/res/drawable/bg_black_shape.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/demo/src/main/res/drawable/close_camera_selector.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/demo/src/main/res/drawable/gray.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
7 |
8 |
--------------------------------------------------------------------------------
/demo/src/main/res/drawable/grid_selector.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/demo/src/main/res/drawable/hdr_selector.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/demo/src/main/res/drawable/light_selector.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/demo/src/main/res/drawable/progress.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | -
6 |
7 |
8 |
9 |
10 |
11 | -
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/demo/src/main/res/drawable/selector_9_16.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/demo/src/main/res/drawable/selector_keyboard.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/demo/src/main/res/drawable/selector_text_color.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/demo/src/main/res/drawable/shape_9_16.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
9 |
--------------------------------------------------------------------------------
/demo/src/main/res/drawable/shape_9_16_fd87aa.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
9 |
--------------------------------------------------------------------------------
/demo/src/main/res/drawable/shape_select_bg.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/demo/src/main/res/drawable/shape_un_select_bg.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/demo/src/main/res/drawable/splash_selector.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/demo/src/main/res/drawable/switch_camera_selector.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/demo/src/main/res/drawable/switch_selector.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/demo/src/main/res/drawable/switch_thumb.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/demo/src/main/res/drawable/timer_selector.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/demo/src/main/res/drawable/white_c_15_shape.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
8 |
9 |
--------------------------------------------------------------------------------
/demo/src/main/res/drawable/yellow_switch.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
7 |
8 |
--------------------------------------------------------------------------------
/demo/src/main/res/layout/activity_coordinator_layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
10 |
11 |
12 |
16 |
17 |
18 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/demo/src/main/res/layout/activity_main_new.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
9 |
10 |
11 |
18 |
19 |
20 |
26 |
27 |
28 |
33 |
34 |
35 |
40 |
41 |
46 |
47 |
52 |
53 |
58 |
59 |
64 |
65 |
70 |
71 |
76 |
77 |
78 |
79 |
--------------------------------------------------------------------------------
/demo/src/main/res/layout/activity_mosaic_layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 |
6 |
7 |
8 |
11 |
12 |
13 |
16 |
17 |
18 |
27 |
28 |
29 |
39 |
40 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/demo/src/main/res/layout/bottom_sheet_layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
9 |
10 |
11 |
14 |
15 |
18 |
19 |
29 |
30 |
31 |
36 |
37 |
38 |
44 |
45 |
53 |
54 |
59 |
60 |
61 |
66 |
67 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
--------------------------------------------------------------------------------
/demo/src/main/res/layout/camera_preview.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/demo/src/main/res/layout/keybord_item_layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
18 |
19 |
20 |
30 |
31 |
--------------------------------------------------------------------------------
/demo/src/main/res/layout/keybord_layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
9 |
12 |
13 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/demo/src/main/res/layout/rcv_item_layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
10 |
11 |
12 |
15 |
16 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/demo/src/main/res/layout/room_activity.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
9 |
10 |
11 |
16 |
17 |
18 |
24 |
25 |
31 |
32 |
38 |
39 |
40 |
46 |
47 |
48 |
54 |
55 |
60 |
61 |
62 |
71 |
72 |
73 |
74 |
75 |
--------------------------------------------------------------------------------
/demo/src/main/res/layout/take_photo_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
13 |
14 |
15 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/demo/src/main/res/layout/top_factor_layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
15 |
16 |
17 |
26 |
27 |
28 |
33 |
34 |
41 |
42 |
43 |
44 |
52 |
53 |
58 |
59 |
60 |
61 |
62 |
67 |
68 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
--------------------------------------------------------------------------------
/demo/src/main/res/layout/tranlate_view_layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
10 |
11 |
--------------------------------------------------------------------------------
/demo/src/main/res/layout/viewpager2_layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
10 |
11 |
12 |
13 |
14 |
17 |
18 |
19 |
30 |
31 |
32 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/demo/src/main/res/layout/viewpager_item_layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
10 |
11 |
12 |
15 |
16 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/demo/src/main/res/layout/viewpager_vertical_item_layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
10 |
11 |
12 |
16 |
17 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/demo/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/demo/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/demo/src/main/res/mipmap-hdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ljlstudio/KtMvvm/4081488f829810864922fe78557f1ebd587e3b11/demo/src/main/res/mipmap-hdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/demo/src/main/res/mipmap-hdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ljlstudio/KtMvvm/4081488f829810864922fe78557f1ebd587e3b11/demo/src/main/res/mipmap-hdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/demo/src/main/res/mipmap-mdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ljlstudio/KtMvvm/4081488f829810864922fe78557f1ebd587e3b11/demo/src/main/res/mipmap-mdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/demo/src/main/res/mipmap-mdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ljlstudio/KtMvvm/4081488f829810864922fe78557f1ebd587e3b11/demo/src/main/res/mipmap-mdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/demo/src/main/res/mipmap-xhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ljlstudio/KtMvvm/4081488f829810864922fe78557f1ebd587e3b11/demo/src/main/res/mipmap-xhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/demo/src/main/res/mipmap-xhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ljlstudio/KtMvvm/4081488f829810864922fe78557f1ebd587e3b11/demo/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/demo/src/main/res/mipmap-xxhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ljlstudio/KtMvvm/4081488f829810864922fe78557f1ebd587e3b11/demo/src/main/res/mipmap-xxhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/demo/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ljlstudio/KtMvvm/4081488f829810864922fe78557f1ebd587e3b11/demo/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/demo/src/main/res/mipmap-xxxhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ljlstudio/KtMvvm/4081488f829810864922fe78557f1ebd587e3b11/demo/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/demo/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ljlstudio/KtMvvm/4081488f829810864922fe78557f1ebd587e3b11/demo/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/demo/src/main/res/values-night/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
16 |
--------------------------------------------------------------------------------
/demo/src/main/res/values/arrays.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | - 方形马赛克
6 | - 圆形马赛克
7 | - 六边形马赛克
8 | - 模糊效果
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/demo/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/demo/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFBB86FC
4 | #FF6200EE
5 | #FF3700B3
6 | #FF03DAC5
7 | #FF018786
8 | #FF000000
9 | #FFFFFFFF
10 | #fd87aa
11 | #2c2c2c
12 | #707070
13 | #c5c5c5
14 |
--------------------------------------------------------------------------------
/demo/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | KtMvvm
3 |
4 | com.kt.ktmvvm.widget.MyBottomSheetBehavior
5 | 00:%1$02d:%2$02d
6 | %1$02d:%2$02d:%3$02d
7 | %1$03d:%2$02d:%3$02d
8 |
--------------------------------------------------------------------------------
/demo/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
9 |
10 |
11 |
12 |
16 |
17 |
18 |
19 |
23 |
24 |
25 |
29 |
30 |
31 |
36 |
37 |
38 |
42 |
43 |
44 |
50 |
51 |
52 |
62 |
63 |
64 |
68 |
69 |
70 |
74 |
75 |
85 |
--------------------------------------------------------------------------------
/demo/src/main/res/values/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
16 |
--------------------------------------------------------------------------------
/demo/src/test/java/com/kt/ktmvvm/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.kt.ktmvvm
2 |
3 | import org.junit.Test
4 |
5 | import org.junit.Assert.*
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * See [testing documentation](http://d.android.com/tools/testing).
11 | */
12 | class ExampleUnitTest {
13 | @Test
14 | fun addition_isCorrect() {
15 | assertEquals(4, 2 + 2)
16 | }
17 | }
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 | # AndroidX package structure to make it clearer which packages are bundled with the
15 | # Android operating system, and which are packaged with your app"s APK
16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
17 | android.useAndroidX=true
18 | # Kotlin code style for this project: "official" or "obsolete":
19 | kotlin.code.style=official
20 | # Enables namespacing of each library's R class so that its R class includes only the
21 | # resources declared in the library itself and none from the library's dependencies,
22 | # thereby reducing the size of the R class for that library
23 | android.nonTransitiveRClass=true
24 |
25 |
26 | android.enableJetifier=true
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ljlstudio/KtMvvm/4081488f829810864922fe78557f1ebd587e3b11/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Tue Jul 05 17:27:17 CST 2022
2 | distributionBase=GRADLE_USER_HOME
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip
4 | distributionPath=wrapper/dists
5 | zipStorePath=wrapper/dists
6 | zipStoreBase=GRADLE_USER_HOME
7 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/ktmvvm/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/ktmvvm/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.library'
3 | id 'org.jetbrains.kotlin.android'
4 | }
5 |
6 | apply plugin: 'kotlin-android'
7 | apply plugin: 'kotlin-android-extensions'
8 | apply plugin: 'kotlin-kapt'
9 |
10 | kapt {
11 | generateStubs = true
12 | }
13 |
14 | android {
15 | compileSdk 31
16 |
17 | defaultConfig {
18 | minSdk 21
19 | targetSdk 26
20 |
21 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
22 | consumerProguardFiles "consumer-rules.pro"
23 | }
24 |
25 | buildTypes {
26 | release {
27 | minifyEnabled false
28 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
29 | }
30 | }
31 | compileOptions {
32 | sourceCompatibility JavaVersion.VERSION_1_8
33 | targetCompatibility JavaVersion.VERSION_1_8
34 | }
35 | kotlinOptions {
36 | jvmTarget = '1.8'
37 | }
38 |
39 | buildFeatures{
40 | dataBinding = true
41 | }
42 |
43 |
44 | // dataBinding {
45 | // enabled = true
46 | // }
47 | }
48 |
49 | dependencies {
50 |
51 |
52 | api 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.0' //viewmodel
53 | api 'androidx.lifecycle:lifecycle-runtime-ktx:2.5.0'
54 | api 'androidx.appcompat:appcompat:1.6.0-alpha05'
55 | api 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.1' //协程
56 | api 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.1'
57 | api 'androidx.core:core-ktx:1.8.0' //kt
58 |
59 | api 'androidx.coordinatorlayout:coordinatorlayout:1.2.0'
60 | implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
61 | implementation 'com.google.android.material:material:1.6.1'
62 |
63 |
64 | //retrofit http
65 | api 'com.squareup.okhttp3:logging-interceptor:3.6.0'
66 | api 'com.squareup.retrofit2:adapter-rxjava2:2.6.0'
67 | api 'com.squareup.retrofit2:adapter-rxjava:2.6.0'
68 | api 'com.squareup.okhttp3:okhttp:3.12.0'
69 | api 'com.squareup.retrofit2:retrofit:2.6.0'
70 | api 'com.squareup.retrofit2:converter-gson:2.6.0'
71 | api 'com.squareup.retrofit2:adapter-rxjava2:2.6.0'
72 | api 'com.trello.rxlifecycle2:rxlifecycle-components:2.2.2'//rxlifecycler
73 |
74 | api 'com.github.CymChad:BaseRecyclerViewAdapterHelper:3.0.7'
75 | api 'com.github.bumptech.glide:glide:4.13.2'
76 |
77 |
78 |
79 | //room数据库
80 | api "androidx.room:room-runtime:2.4.2"
81 | kapt "androidx.room:room-compiler:2.4.2" // Kotlin 使用 kapt
82 | api "androidx.room:room-ktx:2.4.2"//Coroutines support for Room 协程操作库
83 |
84 |
85 |
86 | implementation 'org.jetbrains:annotations:15.0'
87 |
88 |
89 | //httpDns 优化
90 | implementation 'com.aliyun.ams:alicloud-android-httpdns:2.2.2'
91 |
92 |
93 | }
--------------------------------------------------------------------------------
/ktmvvm/consumer-rules.pro:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ljlstudio/KtMvvm/4081488f829810864922fe78557f1ebd587e3b11/ktmvvm/consumer-rules.pro
--------------------------------------------------------------------------------
/ktmvvm/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/ktmvvm/src/androidTest/java/com/kt/ktmvvm/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package com.kt.ktmvvm
2 |
3 | import androidx.test.platform.app.InstrumentationRegistry
4 | import androidx.test.ext.junit.runners.AndroidJUnit4
5 |
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | import org.junit.Assert.*
10 |
11 | /**
12 | * Instrumented test, which will execute on an Android device.
13 | *
14 | * See [testing documentation](http://d.android.com/tools/testing).
15 | */
16 | @RunWith(AndroidJUnit4::class)
17 | class ExampleInstrumentedTest {
18 | @Test
19 | fun useAppContext() {
20 | // Context of the app under test.
21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext
22 | assertEquals("com.kt.ktmvvm.test", appContext.packageName)
23 | }
24 | }
--------------------------------------------------------------------------------
/ktmvvm/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
--------------------------------------------------------------------------------
/ktmvvm/src/main/java/com/kt/ktmvvm/basic/IBaseView.kt:
--------------------------------------------------------------------------------
1 | package com.kt.ktmvvm.basic
2 |
3 | interface IBaseView {
4 |
5 | /**
6 | * 初始化界面传递参数
7 | */
8 | fun initParam()
9 |
10 |
11 | /**
12 | * 初始化界面观察者的监听
13 | */
14 | fun initViewObservable()
15 | }
--------------------------------------------------------------------------------
/ktmvvm/src/main/java/com/kt/ktmvvm/basic/IBaseViewModel.kt:
--------------------------------------------------------------------------------
1 | package com.kt.ktmvvm.basic
2 |
3 | import android.content.Intent
4 | import androidx.lifecycle.Lifecycle
5 | import androidx.lifecycle.LifecycleObserver
6 | import androidx.lifecycle.LifecycleOwner
7 | import androidx.lifecycle.OnLifecycleEvent
8 |
9 | interface IBaseViewModel: LifecycleObserver {
10 |
11 | @OnLifecycleEvent(Lifecycle.Event.ON_ANY)
12 | fun onAny(owner: LifecycleOwner?, event: Lifecycle.Event?)
13 |
14 | @OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
15 | fun onCreate()
16 |
17 | @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
18 | fun onDestroy()
19 |
20 | @OnLifecycleEvent(Lifecycle.Event.ON_START)
21 | fun onStart()
22 |
23 | @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
24 | fun onStop()
25 |
26 | @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
27 | fun onResume()
28 |
29 | @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
30 | fun onPause()
31 |
32 |
33 | fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?)
34 | }
--------------------------------------------------------------------------------
/ktmvvm/src/main/java/com/kt/ktmvvm/basic/SingleLiveEvent.kt:
--------------------------------------------------------------------------------
1 | package com.kt.ktmvvm.basic
2 |
3 | import android.util.Log
4 | import androidx.annotation.MainThread
5 | import androidx.lifecycle.LifecycleOwner
6 | import androidx.lifecycle.MutableLiveData
7 | import androidx.lifecycle.Observer
8 | import com.kt.ktmvvm.basic.SingleLiveEvent
9 | import java.util.concurrent.atomic.AtomicBoolean
10 |
11 | open class SingleLiveEvent : MutableLiveData() {
12 | private val mPending = AtomicBoolean(false)
13 |
14 | @MainThread
15 | override fun observe(owner: LifecycleOwner, observer: Observer) {
16 | if (hasActiveObservers()) {
17 | Log.w(TAG, "Multiple observers registered but only one will be notified of changes.")
18 | }
19 |
20 | // Observe the internal MutableLiveData
21 | super.observe(owner) { t ->
22 | if (mPending.compareAndSet(true, false)) {
23 | observer.onChanged(t)
24 | }
25 | }
26 | }
27 |
28 | @MainThread
29 | override fun setValue(t: T?) {
30 | mPending.set(true)
31 | super.setValue(t)
32 | }
33 |
34 | /**
35 | * Used for cases where T is Void, to make calls cleaner.
36 | */
37 | @MainThread
38 | fun call() {
39 | value = null
40 | }
41 |
42 | companion object {
43 | private const val TAG = "SingleLiveEvent"
44 | }
45 | }
--------------------------------------------------------------------------------
/ktmvvm/src/main/java/com/kt/ktmvvm/net/ApiAddress.kt:
--------------------------------------------------------------------------------
1 | package com.kt.ktmvvm.net
2 |
3 | class ApiAddress {
4 |
5 | companion object {
6 | /**
7 | * 登录
8 | */
9 | const val LOGIN = "api/login"
10 |
11 | /**
12 | * 海贼
13 | */
14 | const val ONE_PIECE = "goodbook/catalog"
15 |
16 | /**
17 | * 历史上的今天
18 | */
19 | const val HISTORY_DATE="todayOnhistory/queryEvent.php"
20 |
21 | }
22 | }
--------------------------------------------------------------------------------
/ktmvvm/src/main/java/com/kt/ktmvvm/net/ApiException.kt:
--------------------------------------------------------------------------------
1 | package com.kt.ktmvvm.net
2 |
3 | class ApiException : Throwable {
4 |
5 |
6 | private var code = 0
7 | private var displayMessage: String? = null
8 |
9 |
10 | constructor(code: Int, displayMessage: String?) {
11 | this.code = code
12 | this.displayMessage = displayMessage
13 | }
14 |
15 | constructor(code: Int, message: String?, displayMessage: String?) : super(message) {
16 | this.code = code
17 | this.displayMessage = displayMessage
18 | }
19 |
20 | fun getCode(): Int {
21 | return code
22 | }
23 |
24 | fun setCode(code: Int) {
25 | this.code = code
26 | }
27 |
28 | fun getDisplayMessage(): String? {
29 | return displayMessage
30 | }
31 |
32 | fun setDisplayMessage(displayMessage: String?) {
33 | this.displayMessage = displayMessage
34 | }
35 |
36 | fun getUMessage(): String? {
37 | return displayMessage
38 | }
39 | }
--------------------------------------------------------------------------------
/ktmvvm/src/main/java/com/kt/ktmvvm/net/ApiService.kt:
--------------------------------------------------------------------------------
1 | package com.kt.ktmvvm.net
2 |
3 | import okhttp3.RequestBody
4 | import retrofit2.http.Body
5 | import retrofit2.http.GET
6 | import retrofit2.http.POST
7 | import retrofit2.http.Query
8 |
9 | interface ApiService {
10 |
11 |
12 | /**
13 | * 图书馆数据
14 | */
15 | @GET(ApiAddress.ONE_PIECE)
16 | suspend fun onePiece(
17 | @Query("dtype") dtype: String,
18 | @Query("key") key: String
19 | ): Any?
20 |
21 |
22 | /**
23 | * 历史上的今天
24 | */
25 | @GET(ApiAddress.HISTORY_DATE)
26 | suspend fun history(
27 | @Query("date") dtype: String,
28 | @Query("key") key: String
29 | ): Any?
30 |
31 |
32 | /**
33 | * get
34 | */
35 | @GET(ApiAddress.LOGIN)
36 | suspend fun login(
37 | @Query("account") account: String,
38 | @Query("password") password: String
39 | ): BaseResponse
40 |
41 |
42 | /**
43 | * post body
44 | */
45 | @POST(ApiAddress.LOGIN)
46 | suspend fun loginBody(@Body requestBody: RequestBody): BaseResponse
47 | }
--------------------------------------------------------------------------------
/ktmvvm/src/main/java/com/kt/ktmvvm/net/BaseResponse.kt:
--------------------------------------------------------------------------------
1 | package com.kt.ktmvvm.net
2 |
3 | import java.io.Serializable
4 |
5 | class BaseResponse:Serializable {
6 |
7 | private var message: String? = null
8 | private var code: Int? = null
9 | private var data: T? = null
10 | private var result = false
11 |
12 |
13 | fun isResult(): Boolean {
14 | return result
15 | }
16 |
17 | fun setResult(result: Boolean) {
18 | this.result = result
19 | }
20 |
21 |
22 | fun getMessage(): String? {
23 | return message
24 | }
25 |
26 | fun setMessage(message: String?) {
27 | this.message = message
28 | }
29 |
30 | fun getData(): T? {
31 | return data
32 | }
33 |
34 | fun setData(data: T) {
35 | this.data = data
36 | }
37 |
38 | fun getErrCode(): Int? {
39 | return code
40 | }
41 |
42 | fun setErroCode(erroCode: Int?) {
43 | this.code = erroCode
44 | }
45 |
46 | override fun toString(): String {
47 | return "BaseResponse{" +
48 | ", message='" + message + '\'' +
49 | ", code=" + code +
50 | ", data=" + data +
51 | ", result=" + result +
52 | '}'
53 | }
54 | }
--------------------------------------------------------------------------------
/ktmvvm/src/main/java/com/kt/ktmvvm/net/BaseUrlConstants.kt:
--------------------------------------------------------------------------------
1 | package com.kt.ktmvvm.net
2 |
3 | class BaseUrlConstants {
4 |
5 |
6 | companion object {
7 | private const val baseUrl1: String = "http://test1/"
8 | private const val baseUrl2: String = "http://test2/"
9 | private const val video: String = "http://apis.juhe.cn/"
10 | private const val degree: String = "http://v.juhe.cn/"
11 |
12 |
13 | fun getHost(host: Int): String {
14 | when (host) {
15 | 1 -> return baseUrl1
16 | 2 -> return baseUrl2
17 | 3 -> return video
18 | 4 -> return degree
19 | }
20 | return baseUrl1;
21 | }
22 | }
23 | }
--------------------------------------------------------------------------------
/ktmvvm/src/main/java/com/kt/ktmvvm/net/ExceptionUtil.kt:
--------------------------------------------------------------------------------
1 | package com.kt.ktmvvm.net
2 |
3 | import android.accounts.NetworkErrorException
4 | import android.util.MalformedJsonException
5 | import androidx.annotation.StringRes
6 | import com.google.gson.JsonParseException
7 | import com.google.gson.JsonSyntaxException
8 | import org.json.JSONException
9 | import retrofit2.HttpException
10 | import java.io.InterruptedIOException
11 | import java.net.ConnectException
12 | import java.net.SocketTimeoutException
13 | import java.net.UnknownHostException
14 | import java.text.ParseException
15 |
16 | object ExceptionUtil {
17 | /**
18 | * 未知错误
19 | */
20 | const val UNKNOWN = 1000
21 |
22 | /**
23 | * 解析错误
24 | */
25 | const val PARSE_ERROR = 1001
26 |
27 | /**
28 | * 网络错误
29 | */
30 | const val NETWORK_ERROR = 1002
31 |
32 | /**
33 | * 协议错误
34 | */
35 | const val HTTP_ERROR = 1003
36 |
37 | /**
38 | * 处理异常,toast提示错误信息
39 | */
40 | fun catchException(e: Throwable) {
41 | e.printStackTrace()
42 |
43 |
44 |
45 | when (e) {
46 | is HttpException -> {
47 | catchHttpException(e.code())
48 | }
49 | is SocketTimeoutException -> {
50 | // showToast(R.string.common_error_net_time_out)
51 | }
52 | is UnknownHostException, is NetworkErrorException -> {
53 | // showToast(R.string.common_error_net)
54 | }
55 | is MalformedJsonException, is JsonSyntaxException -> {
56 | // showToast(R.string.common_error_server_json)
57 | }
58 | is InterruptedIOException -> {
59 | showToast("服务器连接失败,请稍后重试")
60 | }
61 | // 自定义接口异常
62 | is ApiException -> {
63 | showToast(e.message?:"", e.getCode())
64 | }
65 | is ConnectException -> {
66 | showToast( "连接服务器失败" )
67 | }
68 | else -> {
69 | // showToast("${MyApplication.instance.getString(
70 | // R.string.common_error_do_something_fail
71 | // )}:${e::class.java.name}")
72 | }
73 | }
74 | }
75 |
76 |
77 | /**
78 | * 服务器异常 或 网络通道异常
79 | *
80 | * @param e
81 | * @return
82 | */
83 | private fun handleException(e: Throwable): ApiException {
84 | val ex: ApiException
85 | return if (e is JsonParseException
86 | || e is JSONException
87 | || e is ParseException
88 | ) {
89 | //解析错误
90 | ex = ApiException(PARSE_ERROR, e.message)
91 | ex
92 | } else if (e is ConnectException) {
93 | //网络错误
94 | ex = ApiException(
95 | NETWORK_ERROR,
96 | e.message
97 | )
98 | ex
99 | } else if (e is UnknownHostException || e is SocketTimeoutException) {
100 | //连接错误
101 | ex = ApiException(
102 | NETWORK_ERROR,
103 | e.message
104 | )
105 | ex
106 | } else {
107 | //未知错误
108 | ex = ApiException(
109 | UNKNOWN,
110 | e.message
111 | )
112 | ex
113 | }
114 | }
115 |
116 | /**
117 | * 处理网络异常
118 | */
119 | private fun catchHttpException(errorCode: Int) {
120 | if (errorCode in 200 until 300) return// 成功code则不处理
121 | // showToast(
122 | // catchHttpExceptionCode(
123 | // errorCode
124 | // ), errorCode
125 | // )
126 | }
127 |
128 | /**
129 | * toast提示
130 | */
131 | private fun showToast(@StringRes errorMsg: Int, errorCode: Int = -1) {
132 | // showToast(MyApplication.instance.getString(
133 | // errorMsg
134 | // ), errorCode
135 | // )
136 | }
137 |
138 | /**
139 | * toast提示
140 | */
141 | private fun showToast(errorMsg: String, errorCode: Int = -1) {
142 | // if (errorCode == -1) {
143 | // ToastUtils.showShort(errorMsg)
144 | // } else {
145 | // ToastUtils.showShort("$errorCode:$errorMsg")
146 | // }
147 | }
148 |
149 | /**
150 | * 处理网络异常
151 | */
152 | // private fun catchHttpExceptionCode(errorCode: Int): Int = when (errorCode) {
153 | // in 500..600 -> R.string.common_error_server
154 | // in 400 until 500 -> R.string.common_error_request
155 | // else -> R.string.common_error_request
156 | // }
157 | }
--------------------------------------------------------------------------------
/ktmvvm/src/main/java/com/kt/ktmvvm/net/RetrofitClient.kt:
--------------------------------------------------------------------------------
1 | package com.kt.ktmvvm.net
2 |
3 | import android.annotation.SuppressLint
4 | import android.content.Context
5 | import com.kt.ktmvvm.net.dns.OkHttpDNS
6 | import com.kt.ktmvvm.net.event.OkHttpEventListener
7 | import com.kt.ktmvvm.net.interceptor.HTTPDNSInterceptor
8 | import com.kt.ktmvvm.net.interceptor.NoNetworkInterceptor
9 | import okhttp3.Cache
10 | import okhttp3.ConnectionPool
11 | import okhttp3.OkHttpClient
12 | import okhttp3.logging.HttpLoggingInterceptor
13 | import retrofit2.Retrofit
14 | import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory
15 | import retrofit2.converter.gson.GsonConverterFactory
16 | import java.util.concurrent.TimeUnit
17 | import kotlin.collections.HashMap
18 |
19 | class RetrofitClient
20 | /**
21 | * retrofit 初始化build
22 | */(var context: Context?) {
23 |
24 |
25 | companion object {
26 |
27 | @SuppressLint("StaticFieldLeak")
28 | private var retrofitClient: RetrofitClient? = null
29 | private const val DEFAULT_TIME_OUT = 15
30 | private val sRetrofitManager: MutableMap = HashMap()
31 | fun getInstance(context: Context?): RetrofitClient {
32 |
33 | if (retrofitClient == null) {
34 | synchronized(RetrofitClient::class.java) {
35 | retrofitClient = RetrofitClient(context)
36 | return retrofitClient as RetrofitClient
37 | }
38 | }
39 | return retrofitClient as RetrofitClient
40 | }
41 | }
42 |
43 |
44 | /**
45 | * 创建连接客户端
46 | */
47 | private fun createOkHttpClient(optimization: Boolean): OkHttpClient {
48 |
49 | //设置请求头拦截器
50 |
51 | val httpLoggingInterceptor = HttpLoggingInterceptor(HttpLoggingInterceptor.Logger.DEFAULT)
52 | httpLoggingInterceptor.level = HttpLoggingInterceptor.Level.BODY
53 |
54 |
55 | //根据需求添加不同的拦截器
56 |
57 | if (optimization) {
58 | //DNS 优化以及 开启缓存、无网拦截
59 | return OkHttpClient.Builder()
60 | .connectTimeout(DEFAULT_TIME_OUT.toLong(), TimeUnit.SECONDS)
61 | .writeTimeout(DEFAULT_TIME_OUT.toLong(), TimeUnit.SECONDS)
62 | .readTimeout(DEFAULT_TIME_OUT.toLong(), TimeUnit.SECONDS)
63 | .connectionPool(ConnectionPool(8, 10, TimeUnit.SECONDS)) //添加这两行代码
64 | .sslSocketFactory(TrustAllCerts.createSSLSocketFactory()!!, TrustAllCerts())
65 | .hostnameVerifier(TrustAllCerts.TrustAllHostnameVerifier())
66 | // .protocols(Collections.unmodifiableList(listOf(Protocol.HTTP_1_1)))
67 | //alibaba dns优化
68 | .dns(OkHttpDNS.get(context))
69 | .addInterceptor(HTTPDNSInterceptor(context)) //不建议用这种方式,因为大型APP 域名会比较多,假设HTTPS 的话,证书会认证失败
70 | .cache(context?.cacheDir?.let { Cache(it, 50 * 1024 * 1024L) })//缓存目录
71 | .addInterceptor(NoNetworkInterceptor(context))//无网拦截器
72 | .addInterceptor(httpLoggingInterceptor)
73 | .eventListenerFactory(OkHttpEventListener.FACTORY)
74 | .build()
75 | } else {
76 | //无优化版本
77 | return OkHttpClient.Builder()
78 | .connectTimeout(DEFAULT_TIME_OUT.toLong(), TimeUnit.SECONDS)
79 | .writeTimeout(DEFAULT_TIME_OUT.toLong(), TimeUnit.SECONDS)
80 | .readTimeout(DEFAULT_TIME_OUT.toLong(), TimeUnit.SECONDS)
81 | .connectionPool(ConnectionPool(8, 10, TimeUnit.SECONDS)) //添加这两行代码
82 | .sslSocketFactory(TrustAllCerts.createSSLSocketFactory()!!, TrustAllCerts())
83 | .hostnameVerifier(TrustAllCerts.TrustAllHostnameVerifier())
84 | .addInterceptor(httpLoggingInterceptor)
85 | .eventListenerFactory(OkHttpEventListener.FACTORY)
86 | .build()
87 | }
88 |
89 | }
90 |
91 |
92 | /**
93 | * 根据host 类型判断是否需要重新创建Client,因为一个app 有不同的BaseUrl,切换BaseUrl 就需要重新创建Client
94 | * 所以,就根据类型来从map中取出对应的client
95 | */
96 | fun getDefault(interfaceServer: Class?, hostType: Int): T {
97 | val retrofitManager = sRetrofitManager[hostType]
98 | return if (retrofitManager == null) {
99 | create(interfaceServer, hostType)
100 | } else retrofitManager.create(interfaceServer!!)
101 | }
102 |
103 |
104 | /**
105 | *
106 | */
107 | private fun create(interfaceServer: Class?, hostType: Int): T {
108 | val retrofit: Retrofit = Retrofit.Builder()
109 | .baseUrl(BaseUrlConstants.getHost(hostType))
110 | .addConverterFactory(GsonConverterFactory.create())
111 | .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
112 | .client(createOkHttpClient(true))
113 | .build()
114 | sRetrofitManager[hostType] = retrofit
115 | if (interfaceServer == null) {
116 | throw RuntimeException("The Api InterfaceServer is null!")
117 | }
118 | return retrofit.create(interfaceServer)
119 | }
120 |
121 | }
--------------------------------------------------------------------------------
/ktmvvm/src/main/java/com/kt/ktmvvm/net/TrustAllCerts.kt:
--------------------------------------------------------------------------------
1 | package com.kt.ktmvvm.net
2 |
3 | import java.security.SecureRandom
4 | import java.security.cert.X509Certificate
5 | import javax.net.ssl.*
6 |
7 |
8 | class TrustAllCerts : X509TrustManager {
9 | override fun checkClientTrusted(p0: Array?, p1: String?) {
10 |
11 | }
12 |
13 | override fun checkServerTrusted(chain: Array?, p1: String?) {
14 | requireNotNull(chain) { " Check Server x509Certificates is null" }
15 | }
16 |
17 | override fun getAcceptedIssuers(): Array {
18 | return arrayOfNulls(0)
19 | }
20 |
21 |
22 | companion object {
23 | fun createSSLSocketFactory(): SSLSocketFactory? {
24 | var ssfFactory: SSLSocketFactory? = null
25 | try {
26 | val sc = SSLContext.getInstance("TLS")
27 | sc.init(
28 | null, arrayOf(TrustAllCerts()), SecureRandom()
29 | )
30 | ssfFactory = sc.socketFactory
31 | } catch (e: Exception) {
32 | }
33 | return ssfFactory
34 | }
35 | }
36 |
37 |
38 | class TrustAllHostnameVerifier : HostnameVerifier {
39 | override fun verify(hostname: String, session: SSLSession): Boolean {
40 | return true
41 | }
42 | }
43 | }
--------------------------------------------------------------------------------
/ktmvvm/src/main/java/com/kt/ktmvvm/net/dns/OkHttpDNS.kt:
--------------------------------------------------------------------------------
1 | package com.kt.ktmvvm.net.dns
2 |
3 |
4 | import android.content.Context
5 | import android.util.Log
6 | import com.alibaba.sdk.android.httpdns.HttpDns
7 | import com.alibaba.sdk.android.httpdns.HttpDnsService
8 | import okhttp3.Dns
9 | import java.net.InetAddress
10 |
11 | /**
12 | * DNS 优化
13 | */
14 | class OkHttpDNS(context: Context?) : Dns {
15 | private val SYSTEM = Dns.SYSTEM
16 | private var httpDns: HttpDnsService? = null
17 |
18 | init {
19 | httpDns = HttpDns.getService(context)
20 | }
21 |
22 |
23 | companion object {
24 | private var instance: OkHttpDNS? = null
25 | fun get(context: Context?): OkHttpDNS {
26 | if (instance == null) {
27 | synchronized(OkHttpDNS::class.java) {
28 | if (instance == null) {
29 | instance = OkHttpDNS(context)
30 | }
31 | }
32 | }
33 | return instance!!
34 | }
35 | }
36 |
37 | override fun lookup(hostname: String): MutableList {
38 | //通过异步解析接⼝获取ip
39 | val ip = httpDns?.getIpByHostAsync(hostname)
40 | ip?.let {
41 |
42 | val inetAddresses = listOf(InetAddress.getAllByName(ip)) as MutableList
43 | Log.e("OkHttpDns", "inetAddresses:$inetAddresses")
44 | return inetAddresses
45 | } ?: let {
46 | return Dns.SYSTEM.lookup(hostname)
47 | }
48 | }
49 |
50 |
51 | }
--------------------------------------------------------------------------------
/ktmvvm/src/main/java/com/kt/ktmvvm/net/event/OkHttpEvent.kt:
--------------------------------------------------------------------------------
1 | package com.kt.ktmvvm.net.event
2 |
3 | import android.text.TextUtils
4 |
5 | class OkHttpEvent {
6 | var callStartTime: Long = 0
7 | var callEndTime: Long = 0
8 | var dnsStartTime: Long = 0
9 | var dnsEndTime: Long = 0
10 | var connectStartTime: Long = 0
11 | var connectEndTime: Long = 0
12 | var secureConnectStart: Long = 0
13 | var secureConnectEnd: Long = 0
14 | var responseBodySize: Long = 0
15 | var apiSuccess = false
16 | var errorReason: String? = null
17 |
18 |
19 | override fun toString(): String {
20 | val sb = StringBuilder()
21 | sb.append("NetData: [").append("\n")
22 | sb.append("callTime: ").append(callEndTime - callStartTime).append("\n")
23 | sb.append("dnsParseTime: ").append(dnsEndTime - dnsStartTime).append("\n")
24 | sb.append("connectTime: ").append(connectEndTime - callStartTime).append("\n")
25 | sb.append("secureConnectTime: ").append(secureConnectEnd - secureConnectStart).append("\n")
26 | sb.append("responseBodySize: ").append(responseBodySize).append("\n")
27 | sb.append("apiSuccess: ").append(apiSuccess).append("\n")
28 | if (!TextUtils.isEmpty(errorReason)) {
29 | sb.append("errorReason: ").append(errorReason).append("\n")
30 | }
31 | sb.append("]")
32 | return sb.toString()
33 | }
34 |
35 | }
--------------------------------------------------------------------------------
/ktmvvm/src/main/java/com/kt/ktmvvm/net/event/OkHttpEventListener.kt:
--------------------------------------------------------------------------------
1 | package com.kt.ktmvvm.net.event
2 |
3 | import android.util.Log
4 | import okhttp3.*
5 | import okhttp3.EventListener.Factory
6 | import java.io.IOException
7 | import java.net.InetAddress
8 | import java.net.InetSocketAddress
9 | import java.net.Proxy
10 |
11 | class OkHttpEventListener : EventListener() {
12 |
13 |
14 | private var OkHttpEvent: OkHttpEvent? = null
15 |
16 | companion object {
17 | val TAG = OkHttpEventListener::class.simpleName
18 | val FACTORY = Factory {
19 | OkHttpEventListener()
20 | }
21 | }
22 |
23 | init {
24 | OkHttpEvent = OkHttpEvent()
25 | }
26 |
27 | override fun callStart(call: Call) {
28 | super.callStart(call)
29 | OkHttpEvent?.callStartTime = System.currentTimeMillis()
30 | }
31 |
32 | /**
33 | * dns解析开始
34 | */
35 | override fun dnsStart(call: Call, domainName: String) {
36 | super.dnsStart(call, domainName)
37 | OkHttpEvent?.dnsStartTime = System.currentTimeMillis()
38 | }
39 |
40 | /**
41 | * dns 解析结束
42 | */
43 | override fun dnsEnd(call: Call, domainName: String, inetAddressList: MutableList) {
44 | super.dnsEnd(call, domainName, inetAddressList)
45 | OkHttpEvent?.dnsEndTime = System.currentTimeMillis()
46 | }
47 |
48 | /**
49 | * 连接开始
50 | */
51 | override fun connectStart(call: Call, inetSocketAddress: InetSocketAddress, proxy: Proxy) {
52 | super.connectStart(call, inetSocketAddress, proxy)
53 | OkHttpEvent?.connectStartTime = System.currentTimeMillis()
54 | }
55 |
56 | /**
57 | *连接结束
58 | */
59 | override fun connectEnd(
60 | call: Call,
61 | inetSocketAddress: InetSocketAddress,
62 | proxy: Proxy,
63 | protocol: Protocol?
64 | ) {
65 | super.connectEnd(call, inetSocketAddress, proxy, protocol)
66 | OkHttpEvent?.connectEndTime = System.currentTimeMillis()
67 | }
68 |
69 | /**
70 | * 安全连接开始
71 | */
72 | override fun secureConnectStart(call: Call) {
73 | super.secureConnectStart(call)
74 | OkHttpEvent?.secureConnectStart = System.currentTimeMillis()
75 | }
76 |
77 | /**
78 | * 安全连接结束
79 | */
80 | override fun secureConnectEnd(call: Call, handshake: Handshake?) {
81 | super.secureConnectEnd(call, handshake)
82 | OkHttpEvent?.secureConnectEnd = System.currentTimeMillis()
83 | }
84 |
85 |
86 | override fun connectFailed(
87 | call: Call,
88 | inetSocketAddress: InetSocketAddress,
89 | proxy: Proxy,
90 | protocol: Protocol?,
91 | ioe: IOException
92 | ) {
93 | super.connectFailed(call, inetSocketAddress, proxy, protocol, ioe)
94 | }
95 |
96 | override fun connectionAcquired(call: Call, connection: Connection) {
97 | super.connectionAcquired(call, connection)
98 | }
99 |
100 | override fun connectionReleased(call: Call, connection: Connection) {
101 | super.connectionReleased(call, connection)
102 | }
103 |
104 | override fun requestHeadersStart(call: Call) {
105 | super.requestHeadersStart(call)
106 | }
107 |
108 | override fun requestHeadersEnd(call: Call, request: Request) {
109 | super.requestHeadersEnd(call, request)
110 | }
111 |
112 | override fun requestBodyStart(call: Call) {
113 | super.requestBodyStart(call)
114 | }
115 |
116 | override fun requestBodyEnd(call: Call, byteCount: Long) {
117 | super.requestBodyEnd(call, byteCount)
118 | }
119 |
120 | override fun responseHeadersStart(call: Call) {
121 | super.responseHeadersStart(call)
122 | }
123 |
124 | override fun responseHeadersEnd(call: Call, response: Response) {
125 | super.responseHeadersEnd(call, response)
126 | }
127 |
128 | override fun responseBodyStart(call: Call) {
129 | super.responseBodyStart(call)
130 | }
131 |
132 | override fun responseBodyEnd(call: Call, byteCount: Long) {
133 | super.responseBodyEnd(call, byteCount)
134 | OkHttpEvent?.responseBodySize = byteCount
135 | }
136 |
137 | override fun callEnd(call: Call) {
138 | super.callEnd(call)
139 | OkHttpEvent?.callEndTime = System.currentTimeMillis()
140 | // 记录 API 请求成功
141 | OkHttpEvent?.apiSuccess = true
142 | OkHttpEvent?.toString()?.let { Log.i(TAG, it) }
143 | }
144 |
145 | override fun callFailed(call: Call, ioe: IOException) {
146 | super.callFailed(call, ioe)
147 | // 记录 API 请求失败及原因
148 | OkHttpEvent?.apiSuccess = false
149 | OkHttpEvent?.errorReason = Log.getStackTraceString(ioe)
150 | Log.i(TAG, "reason " + OkHttpEvent?.errorReason)
151 | OkHttpEvent?.toString()?.let { Log.i(TAG, it) }
152 | }
153 | }
--------------------------------------------------------------------------------
/ktmvvm/src/main/java/com/kt/ktmvvm/net/interceptor/HTTPDNSInterceptor.kt:
--------------------------------------------------------------------------------
1 | package com.kt.ktmvvm.net.interceptor
2 |
3 | import android.content.Context
4 | import com.alibaba.sdk.android.httpdns.HttpDns
5 | import okhttp3.Interceptor
6 | import okhttp3.Response
7 |
8 | class HTTPDNSInterceptor(private var context: Context?) : Interceptor {
9 |
10 |
11 | override fun intercept(chain: Interceptor.Chain): Response {
12 |
13 | val originRequest = chain.request()
14 | val httpUrl = originRequest.url()
15 | val url = httpUrl.toString()
16 | val host = httpUrl.host()
17 | val service = HttpDns.getService(context)
18 |
19 | val hostIP =service.getIpByHostAsync(host)
20 | val builder = originRequest.newBuilder()
21 |
22 | if (hostIP != null) {
23 | builder.url( url.replaceFirst(url,hostIP))
24 |
25 | builder.header("host", hostIP)
26 | }
27 | val newRequest = builder.build()
28 | return chain.proceed(newRequest)
29 | }
30 | }
--------------------------------------------------------------------------------
/ktmvvm/src/main/java/com/kt/ktmvvm/net/interceptor/NoNetworkInterceptor.kt:
--------------------------------------------------------------------------------
1 | package com.kt.ktmvvm.net.interceptor
2 |
3 | import android.annotation.SuppressLint
4 | import android.content.Context
5 | import android.net.ConnectivityManager
6 | import okhttp3.CacheControl
7 | import okhttp3.Interceptor
8 | import okhttp3.Response
9 |
10 | class NoNetworkInterceptor(private var context: Context?) : Interceptor {
11 |
12 |
13 | override fun intercept(chain: Interceptor.Chain): Response {
14 | val request = chain.request()
15 | val newBuilder = request.newBuilder()
16 |
17 | if (getNetworkStatus(context) == -1) {
18 | //无网时,只从缓存中取
19 | newBuilder.cacheControl(CacheControl.FORCE_CACHE)
20 | } else {
21 | //有网时,只从服务器取
22 | newBuilder.cacheControl(CacheControl.FORCE_NETWORK)
23 |
24 | }
25 |
26 |
27 |
28 | return chain.proceed(newBuilder.build())
29 | }
30 |
31 |
32 | companion object {
33 | @SuppressLint("MissingPermission")
34 | fun getNetworkStatus(context: Context?): Int {
35 | try {
36 | if (context == null) {
37 | return -1
38 | }
39 | val conMan = context.getSystemService(
40 | Context.CONNECTIVITY_SERVICE
41 | ) as ConnectivityManager
42 | val info = conMan.activeNetworkInfo
43 | if (null != info && info.isConnected) {
44 | if (info.type == ConnectivityManager.TYPE_MOBILE) {
45 | return when (info.subtype) {
46 | 1, 2, 4 -> // 2G网络
47 | 2
48 | else -> // 3G及其以上网络
49 | 3
50 | }
51 | } else if (info.type == ConnectivityManager.TYPE_WIFI) {
52 | // wifi网络
53 | return 1
54 | }
55 | }
56 | } catch (e: Exception) {
57 | //报错的就当有
58 | return 1
59 | }
60 | // 无网络
61 | return -1
62 | }
63 | }
64 |
65 |
66 | }
--------------------------------------------------------------------------------
/ktmvvm/src/test/java/com/kt/ktmvvm/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.kt.ktmvvm
2 |
3 | import org.junit.Test
4 |
5 | import org.junit.Assert.*
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * See [testing documentation](http://d.android.com/tools/testing).
11 | */
12 | class ExampleUnitTest {
13 | @Test
14 | fun addition_isCorrect() {
15 | assertEquals(4, 2 + 2)
16 | }
17 | }
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | pluginManagement {
2 | repositories {
3 | gradlePluginPortal()
4 | google()
5 | mavenCentral()
6 | }
7 |
8 |
9 | }
10 | dependencyResolutionManagement {
11 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
12 | repositories {
13 | google()
14 | mavenCentral()
15 | maven { url 'https://jitpack.io' }
16 | maven {
17 | allowInsecureProtocol = true
18 | url 'http://maven.aliyun.com/nexus/content/repositories/releases/'
19 | }
20 | }
21 | }
22 | rootProject.name = "KtMvvm"
23 | include ':demo'
24 | include ':ktmvvm'
25 |
--------------------------------------------------------------------------------