diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..35eb1dd
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..35eb1dd
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
index 4ca4a9f..0002b4a 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -27,6 +27,12 @@
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
+
+ kotlin {
+ experimental {
+ coroutines 'enable'
+ }
+ }
}
dependencies {
@@ -47,19 +53,24 @@
implementation 'com.gyf.immersionbar:immersionbar:3.0.0'
//fragment快速实现
implementation 'com.gyf.immersionbar:immersionbar-components:3.0.0'
+ //MVVM
+ implementation "androidx.lifecycle:lifecycle-livedata:2.2.0"
+ implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0"
+ implementation "androidx.lifecycle:lifecycle-extensions:2.2.0"
+ //Kotlin协程
+ implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.0'
+ implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.0'
+ //返回值转换器
+ implementation 'com.jakewharton.retrofit:retrofit2-kotlin-coroutines-adapter:0.9.2'
+ implementation 'com.squareup.retrofit2:converter-scalars:2.0.0'
+ implementation 'com.squareup.retrofit2:converter-gson:2.8.1'
+ //okhttp3日志拦截器
+ implementation 'com.squareup.okhttp3:logging-interceptor:4.6.0'
- //MVP网络请求框架retrofit2+rxjava
- implementation 'io.reactivex:rxjava:1.3.8'
- implementation 'io.reactivex:rxandroid:1.2.1'
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.okhttp3:okhttp:4.6.0'
- implementation 'com.squareup.retrofit2:converter-gson:2.8.1'
- implementation 'com.squareup.retrofit2:adapter-rxjava:2.8.1'
- implementation 'com.squareup.okhttp3:logging-interceptor:4.6.0'
//官方Json解析库
implementation 'com.google.code.gson:gson:2.8.6'
- //Toast提示
- implementation 'com.sdsmdg.tastytoast:tastytoast:0.1.1'
//图片选择框架
implementation 'com.github.LuckSiege.PictureSelector:picture_library:v2.6.0'
//上拉加载下拉刷新
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..35eb1dd
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
index 4ca4a9f..0002b4a 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -27,6 +27,12 @@
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
+
+ kotlin {
+ experimental {
+ coroutines 'enable'
+ }
+ }
}
dependencies {
@@ -47,19 +53,24 @@
implementation 'com.gyf.immersionbar:immersionbar:3.0.0'
//fragment快速实现
implementation 'com.gyf.immersionbar:immersionbar-components:3.0.0'
+ //MVVM
+ implementation "androidx.lifecycle:lifecycle-livedata:2.2.0"
+ implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0"
+ implementation "androidx.lifecycle:lifecycle-extensions:2.2.0"
+ //Kotlin协程
+ implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.0'
+ implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.0'
+ //返回值转换器
+ implementation 'com.jakewharton.retrofit:retrofit2-kotlin-coroutines-adapter:0.9.2'
+ implementation 'com.squareup.retrofit2:converter-scalars:2.0.0'
+ implementation 'com.squareup.retrofit2:converter-gson:2.8.1'
+ //okhttp3日志拦截器
+ implementation 'com.squareup.okhttp3:logging-interceptor:4.6.0'
- //MVP网络请求框架retrofit2+rxjava
- implementation 'io.reactivex:rxjava:1.3.8'
- implementation 'io.reactivex:rxandroid:1.2.1'
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.okhttp3:okhttp:4.6.0'
- implementation 'com.squareup.retrofit2:converter-gson:2.8.1'
- implementation 'com.squareup.retrofit2:adapter-rxjava:2.8.1'
- implementation 'com.squareup.okhttp3:logging-interceptor:4.6.0'
//官方Json解析库
implementation 'com.google.code.gson:gson:2.8.6'
- //Toast提示
- implementation 'com.sdsmdg.tastytoast:tastytoast:0.1.1'
//图片选择框架
implementation 'com.github.LuckSiege.PictureSelector:picture_library:v2.6.0'
//上拉加载下拉刷新
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 7096527..be35467 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -23,16 +23,16 @@
android:theme="@style/QMUI.Compat.NoActionBar"
android:usesCleartextTraffic="true"
tools:targetApi="m">
-
+
-
-
-
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..35eb1dd
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
index 4ca4a9f..0002b4a 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -27,6 +27,12 @@
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
+
+ kotlin {
+ experimental {
+ coroutines 'enable'
+ }
+ }
}
dependencies {
@@ -47,19 +53,24 @@
implementation 'com.gyf.immersionbar:immersionbar:3.0.0'
//fragment快速实现
implementation 'com.gyf.immersionbar:immersionbar-components:3.0.0'
+ //MVVM
+ implementation "androidx.lifecycle:lifecycle-livedata:2.2.0"
+ implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0"
+ implementation "androidx.lifecycle:lifecycle-extensions:2.2.0"
+ //Kotlin协程
+ implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.0'
+ implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.0'
+ //返回值转换器
+ implementation 'com.jakewharton.retrofit:retrofit2-kotlin-coroutines-adapter:0.9.2'
+ implementation 'com.squareup.retrofit2:converter-scalars:2.0.0'
+ implementation 'com.squareup.retrofit2:converter-gson:2.8.1'
+ //okhttp3日志拦截器
+ implementation 'com.squareup.okhttp3:logging-interceptor:4.6.0'
- //MVP网络请求框架retrofit2+rxjava
- implementation 'io.reactivex:rxjava:1.3.8'
- implementation 'io.reactivex:rxandroid:1.2.1'
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.okhttp3:okhttp:4.6.0'
- implementation 'com.squareup.retrofit2:converter-gson:2.8.1'
- implementation 'com.squareup.retrofit2:adapter-rxjava:2.8.1'
- implementation 'com.squareup.okhttp3:logging-interceptor:4.6.0'
//官方Json解析库
implementation 'com.google.code.gson:gson:2.8.6'
- //Toast提示
- implementation 'com.sdsmdg.tastytoast:tastytoast:0.1.1'
//图片选择框架
implementation 'com.github.LuckSiege.PictureSelector:picture_library:v2.6.0'
//上拉加载下拉刷新
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 7096527..be35467 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -23,16 +23,16 @@
android:theme="@style/QMUI.Compat.NoActionBar"
android:usesCleartextTraffic="true"
tools:targetApi="m">
-
+
-
-
-
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/base/BaseActivity.kt b/app/src/main/java/com/casic/birmm/inspect/base/BaseActivity.kt
index aefdbb6..b6b9f53 100644
--- a/app/src/main/java/com/casic/birmm/inspect/base/BaseActivity.kt
+++ b/app/src/main/java/com/casic/birmm/inspect/base/BaseActivity.kt
@@ -4,6 +4,9 @@
import androidx.appcompat.app.AppCompatActivity
import com.qmuiteam.qmui.util.QMUIStatusBarHelper
+/**
+ * 无网络请求等普通页面的基础类
+ * */
abstract class BaseActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..35eb1dd
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
index 4ca4a9f..0002b4a 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -27,6 +27,12 @@
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
+
+ kotlin {
+ experimental {
+ coroutines 'enable'
+ }
+ }
}
dependencies {
@@ -47,19 +53,24 @@
implementation 'com.gyf.immersionbar:immersionbar:3.0.0'
//fragment快速实现
implementation 'com.gyf.immersionbar:immersionbar-components:3.0.0'
+ //MVVM
+ implementation "androidx.lifecycle:lifecycle-livedata:2.2.0"
+ implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0"
+ implementation "androidx.lifecycle:lifecycle-extensions:2.2.0"
+ //Kotlin协程
+ implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.0'
+ implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.0'
+ //返回值转换器
+ implementation 'com.jakewharton.retrofit:retrofit2-kotlin-coroutines-adapter:0.9.2'
+ implementation 'com.squareup.retrofit2:converter-scalars:2.0.0'
+ implementation 'com.squareup.retrofit2:converter-gson:2.8.1'
+ //okhttp3日志拦截器
+ implementation 'com.squareup.okhttp3:logging-interceptor:4.6.0'
- //MVP网络请求框架retrofit2+rxjava
- implementation 'io.reactivex:rxjava:1.3.8'
- implementation 'io.reactivex:rxandroid:1.2.1'
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.okhttp3:okhttp:4.6.0'
- implementation 'com.squareup.retrofit2:converter-gson:2.8.1'
- implementation 'com.squareup.retrofit2:adapter-rxjava:2.8.1'
- implementation 'com.squareup.okhttp3:logging-interceptor:4.6.0'
//官方Json解析库
implementation 'com.google.code.gson:gson:2.8.6'
- //Toast提示
- implementation 'com.sdsmdg.tastytoast:tastytoast:0.1.1'
//图片选择框架
implementation 'com.github.LuckSiege.PictureSelector:picture_library:v2.6.0'
//上拉加载下拉刷新
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 7096527..be35467 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -23,16 +23,16 @@
android:theme="@style/QMUI.Compat.NoActionBar"
android:usesCleartextTraffic="true"
tools:targetApi="m">
-
+
-
-
-
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/base/BaseActivity.kt b/app/src/main/java/com/casic/birmm/inspect/base/BaseActivity.kt
index aefdbb6..b6b9f53 100644
--- a/app/src/main/java/com/casic/birmm/inspect/base/BaseActivity.kt
+++ b/app/src/main/java/com/casic/birmm/inspect/base/BaseActivity.kt
@@ -4,6 +4,9 @@
import androidx.appcompat.app.AppCompatActivity
import com.qmuiteam.qmui.util.QMUIStatusBarHelper
+/**
+ * 无网络请求等普通页面的基础类
+ * */
abstract class BaseActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
diff --git a/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModel.kt b/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModel.kt
new file mode 100644
index 0000000..968b877
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModel.kt
@@ -0,0 +1,9 @@
+package com.casic.birmm.inspect.base
+
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.ViewModel
+import com.casic.birmm.inspect.utils.LoadState
+
+abstract class BaseViewModel : ViewModel() {
+ val loadState = MutableLiveData()
+}
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..35eb1dd
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
index 4ca4a9f..0002b4a 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -27,6 +27,12 @@
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
+
+ kotlin {
+ experimental {
+ coroutines 'enable'
+ }
+ }
}
dependencies {
@@ -47,19 +53,24 @@
implementation 'com.gyf.immersionbar:immersionbar:3.0.0'
//fragment快速实现
implementation 'com.gyf.immersionbar:immersionbar-components:3.0.0'
+ //MVVM
+ implementation "androidx.lifecycle:lifecycle-livedata:2.2.0"
+ implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0"
+ implementation "androidx.lifecycle:lifecycle-extensions:2.2.0"
+ //Kotlin协程
+ implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.0'
+ implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.0'
+ //返回值转换器
+ implementation 'com.jakewharton.retrofit:retrofit2-kotlin-coroutines-adapter:0.9.2'
+ implementation 'com.squareup.retrofit2:converter-scalars:2.0.0'
+ implementation 'com.squareup.retrofit2:converter-gson:2.8.1'
+ //okhttp3日志拦截器
+ implementation 'com.squareup.okhttp3:logging-interceptor:4.6.0'
- //MVP网络请求框架retrofit2+rxjava
- implementation 'io.reactivex:rxjava:1.3.8'
- implementation 'io.reactivex:rxandroid:1.2.1'
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.okhttp3:okhttp:4.6.0'
- implementation 'com.squareup.retrofit2:converter-gson:2.8.1'
- implementation 'com.squareup.retrofit2:adapter-rxjava:2.8.1'
- implementation 'com.squareup.okhttp3:logging-interceptor:4.6.0'
//官方Json解析库
implementation 'com.google.code.gson:gson:2.8.6'
- //Toast提示
- implementation 'com.sdsmdg.tastytoast:tastytoast:0.1.1'
//图片选择框架
implementation 'com.github.LuckSiege.PictureSelector:picture_library:v2.6.0'
//上拉加载下拉刷新
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 7096527..be35467 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -23,16 +23,16 @@
android:theme="@style/QMUI.Compat.NoActionBar"
android:usesCleartextTraffic="true"
tools:targetApi="m">
-
+
-
-
-
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/base/BaseActivity.kt b/app/src/main/java/com/casic/birmm/inspect/base/BaseActivity.kt
index aefdbb6..b6b9f53 100644
--- a/app/src/main/java/com/casic/birmm/inspect/base/BaseActivity.kt
+++ b/app/src/main/java/com/casic/birmm/inspect/base/BaseActivity.kt
@@ -4,6 +4,9 @@
import androidx.appcompat.app.AppCompatActivity
import com.qmuiteam.qmui.util.QMUIStatusBarHelper
+/**
+ * 无网络请求等普通页面的基础类
+ * */
abstract class BaseActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
diff --git a/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModel.kt b/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModel.kt
new file mode 100644
index 0000000..968b877
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModel.kt
@@ -0,0 +1,9 @@
+package com.casic.birmm.inspect.base
+
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.ViewModel
+import com.casic.birmm.inspect.utils.LoadState
+
+abstract class BaseViewModel : ViewModel() {
+ val loadState = MutableLiveData()
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModelActivity.kt b/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModelActivity.kt
new file mode 100644
index 0000000..ee93c84
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModelActivity.kt
@@ -0,0 +1,61 @@
+package com.casic.birmm.inspect.base
+
+import android.os.Bundle
+import androidx.appcompat.app.AppCompatActivity
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.ViewModelProvider
+import com.qmuiteam.qmui.util.QMUIStatusBarHelper
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.MainScope
+import kotlinx.coroutines.cancel
+
+/**
+ * MV ViewModel 架构
+ *
+ * 有网络请求等普通页面的基础类
+ */
+abstract class BaseViewModelActivity : AppCompatActivity(),
+ CoroutineScope by MainScope() {
+
+ protected lateinit var viewModel: VM
+
+ /**
+ * 初始化xml布局
+ */
+ protected abstract fun initLayoutView(): Int
+
+ /**
+ * 特定页面定制沉浸式状态栏
+ */
+ protected abstract fun setupTopBarLayout()
+
+ /**
+ * 初始化默认数据
+ */
+ abstract fun initData()
+
+ /**
+ * 初始化业务逻辑
+ */
+ abstract fun initEvent()
+
+ /**
+ * 提供ViewModel类
+ */
+ protected abstract fun createViewModelByClass(): Class?
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(initLayoutView())
+ createViewModelByClass()?.let { viewModel = ViewModelProvider(this).get(it) }
+ QMUIStatusBarHelper.translucent(this) //沉浸式状态栏
+ setupTopBarLayout()
+ initData()
+ initEvent()
+ }
+
+ override fun onDestroy() {
+ cancel()// 取消协程
+ super.onDestroy()
+ }
+}
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..35eb1dd
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
index 4ca4a9f..0002b4a 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -27,6 +27,12 @@
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
+
+ kotlin {
+ experimental {
+ coroutines 'enable'
+ }
+ }
}
dependencies {
@@ -47,19 +53,24 @@
implementation 'com.gyf.immersionbar:immersionbar:3.0.0'
//fragment快速实现
implementation 'com.gyf.immersionbar:immersionbar-components:3.0.0'
+ //MVVM
+ implementation "androidx.lifecycle:lifecycle-livedata:2.2.0"
+ implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0"
+ implementation "androidx.lifecycle:lifecycle-extensions:2.2.0"
+ //Kotlin协程
+ implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.0'
+ implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.0'
+ //返回值转换器
+ implementation 'com.jakewharton.retrofit:retrofit2-kotlin-coroutines-adapter:0.9.2'
+ implementation 'com.squareup.retrofit2:converter-scalars:2.0.0'
+ implementation 'com.squareup.retrofit2:converter-gson:2.8.1'
+ //okhttp3日志拦截器
+ implementation 'com.squareup.okhttp3:logging-interceptor:4.6.0'
- //MVP网络请求框架retrofit2+rxjava
- implementation 'io.reactivex:rxjava:1.3.8'
- implementation 'io.reactivex:rxandroid:1.2.1'
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.okhttp3:okhttp:4.6.0'
- implementation 'com.squareup.retrofit2:converter-gson:2.8.1'
- implementation 'com.squareup.retrofit2:adapter-rxjava:2.8.1'
- implementation 'com.squareup.okhttp3:logging-interceptor:4.6.0'
//官方Json解析库
implementation 'com.google.code.gson:gson:2.8.6'
- //Toast提示
- implementation 'com.sdsmdg.tastytoast:tastytoast:0.1.1'
//图片选择框架
implementation 'com.github.LuckSiege.PictureSelector:picture_library:v2.6.0'
//上拉加载下拉刷新
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 7096527..be35467 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -23,16 +23,16 @@
android:theme="@style/QMUI.Compat.NoActionBar"
android:usesCleartextTraffic="true"
tools:targetApi="m">
-
+
-
-
-
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/base/BaseActivity.kt b/app/src/main/java/com/casic/birmm/inspect/base/BaseActivity.kt
index aefdbb6..b6b9f53 100644
--- a/app/src/main/java/com/casic/birmm/inspect/base/BaseActivity.kt
+++ b/app/src/main/java/com/casic/birmm/inspect/base/BaseActivity.kt
@@ -4,6 +4,9 @@
import androidx.appcompat.app.AppCompatActivity
import com.qmuiteam.qmui.util.QMUIStatusBarHelper
+/**
+ * 无网络请求等普通页面的基础类
+ * */
abstract class BaseActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
diff --git a/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModel.kt b/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModel.kt
new file mode 100644
index 0000000..968b877
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModel.kt
@@ -0,0 +1,9 @@
+package com.casic.birmm.inspect.base
+
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.ViewModel
+import com.casic.birmm.inspect.utils.LoadState
+
+abstract class BaseViewModel : ViewModel() {
+ val loadState = MutableLiveData()
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModelActivity.kt b/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModelActivity.kt
new file mode 100644
index 0000000..ee93c84
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModelActivity.kt
@@ -0,0 +1,61 @@
+package com.casic.birmm.inspect.base
+
+import android.os.Bundle
+import androidx.appcompat.app.AppCompatActivity
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.ViewModelProvider
+import com.qmuiteam.qmui.util.QMUIStatusBarHelper
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.MainScope
+import kotlinx.coroutines.cancel
+
+/**
+ * MV ViewModel 架构
+ *
+ * 有网络请求等普通页面的基础类
+ */
+abstract class BaseViewModelActivity : AppCompatActivity(),
+ CoroutineScope by MainScope() {
+
+ protected lateinit var viewModel: VM
+
+ /**
+ * 初始化xml布局
+ */
+ protected abstract fun initLayoutView(): Int
+
+ /**
+ * 特定页面定制沉浸式状态栏
+ */
+ protected abstract fun setupTopBarLayout()
+
+ /**
+ * 初始化默认数据
+ */
+ abstract fun initData()
+
+ /**
+ * 初始化业务逻辑
+ */
+ abstract fun initEvent()
+
+ /**
+ * 提供ViewModel类
+ */
+ protected abstract fun createViewModelByClass(): Class?
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(initLayoutView())
+ createViewModelByClass()?.let { viewModel = ViewModelProvider(this).get(it) }
+ QMUIStatusBarHelper.translucent(this) //沉浸式状态栏
+ setupTopBarLayout()
+ initData()
+ initEvent()
+ }
+
+ override fun onDestroy() {
+ cancel()// 取消协程
+ super.onDestroy()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/model/PublicKeyBean.kt b/app/src/main/java/com/casic/birmm/inspect/model/PublicKeyBean.kt
new file mode 100644
index 0000000..25c5436
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/model/PublicKeyBean.kt
@@ -0,0 +1,18 @@
+package com.casic.birmm.inspect.model
+
+/**
+ * PublicKey 登录校验Key
+ */
+class PublicKeyBean {
+ var code = 0
+ var data: DataBean? = null
+ var message: String? = null
+ var isSuccess = false
+
+ class DataBean {
+ var isAppKaptcha = false
+ var isKaptcha = false
+ var publicKey: String? = null
+ var sid: String? = null
+ }
+}
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..35eb1dd
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
index 4ca4a9f..0002b4a 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -27,6 +27,12 @@
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
+
+ kotlin {
+ experimental {
+ coroutines 'enable'
+ }
+ }
}
dependencies {
@@ -47,19 +53,24 @@
implementation 'com.gyf.immersionbar:immersionbar:3.0.0'
//fragment快速实现
implementation 'com.gyf.immersionbar:immersionbar-components:3.0.0'
+ //MVVM
+ implementation "androidx.lifecycle:lifecycle-livedata:2.2.0"
+ implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0"
+ implementation "androidx.lifecycle:lifecycle-extensions:2.2.0"
+ //Kotlin协程
+ implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.0'
+ implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.0'
+ //返回值转换器
+ implementation 'com.jakewharton.retrofit:retrofit2-kotlin-coroutines-adapter:0.9.2'
+ implementation 'com.squareup.retrofit2:converter-scalars:2.0.0'
+ implementation 'com.squareup.retrofit2:converter-gson:2.8.1'
+ //okhttp3日志拦截器
+ implementation 'com.squareup.okhttp3:logging-interceptor:4.6.0'
- //MVP网络请求框架retrofit2+rxjava
- implementation 'io.reactivex:rxjava:1.3.8'
- implementation 'io.reactivex:rxandroid:1.2.1'
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.okhttp3:okhttp:4.6.0'
- implementation 'com.squareup.retrofit2:converter-gson:2.8.1'
- implementation 'com.squareup.retrofit2:adapter-rxjava:2.8.1'
- implementation 'com.squareup.okhttp3:logging-interceptor:4.6.0'
//官方Json解析库
implementation 'com.google.code.gson:gson:2.8.6'
- //Toast提示
- implementation 'com.sdsmdg.tastytoast:tastytoast:0.1.1'
//图片选择框架
implementation 'com.github.LuckSiege.PictureSelector:picture_library:v2.6.0'
//上拉加载下拉刷新
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 7096527..be35467 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -23,16 +23,16 @@
android:theme="@style/QMUI.Compat.NoActionBar"
android:usesCleartextTraffic="true"
tools:targetApi="m">
-
+
-
-
-
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/base/BaseActivity.kt b/app/src/main/java/com/casic/birmm/inspect/base/BaseActivity.kt
index aefdbb6..b6b9f53 100644
--- a/app/src/main/java/com/casic/birmm/inspect/base/BaseActivity.kt
+++ b/app/src/main/java/com/casic/birmm/inspect/base/BaseActivity.kt
@@ -4,6 +4,9 @@
import androidx.appcompat.app.AppCompatActivity
import com.qmuiteam.qmui.util.QMUIStatusBarHelper
+/**
+ * 无网络请求等普通页面的基础类
+ * */
abstract class BaseActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
diff --git a/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModel.kt b/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModel.kt
new file mode 100644
index 0000000..968b877
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModel.kt
@@ -0,0 +1,9 @@
+package com.casic.birmm.inspect.base
+
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.ViewModel
+import com.casic.birmm.inspect.utils.LoadState
+
+abstract class BaseViewModel : ViewModel() {
+ val loadState = MutableLiveData()
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModelActivity.kt b/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModelActivity.kt
new file mode 100644
index 0000000..ee93c84
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModelActivity.kt
@@ -0,0 +1,61 @@
+package com.casic.birmm.inspect.base
+
+import android.os.Bundle
+import androidx.appcompat.app.AppCompatActivity
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.ViewModelProvider
+import com.qmuiteam.qmui.util.QMUIStatusBarHelper
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.MainScope
+import kotlinx.coroutines.cancel
+
+/**
+ * MV ViewModel 架构
+ *
+ * 有网络请求等普通页面的基础类
+ */
+abstract class BaseViewModelActivity : AppCompatActivity(),
+ CoroutineScope by MainScope() {
+
+ protected lateinit var viewModel: VM
+
+ /**
+ * 初始化xml布局
+ */
+ protected abstract fun initLayoutView(): Int
+
+ /**
+ * 特定页面定制沉浸式状态栏
+ */
+ protected abstract fun setupTopBarLayout()
+
+ /**
+ * 初始化默认数据
+ */
+ abstract fun initData()
+
+ /**
+ * 初始化业务逻辑
+ */
+ abstract fun initEvent()
+
+ /**
+ * 提供ViewModel类
+ */
+ protected abstract fun createViewModelByClass(): Class?
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(initLayoutView())
+ createViewModelByClass()?.let { viewModel = ViewModelProvider(this).get(it) }
+ QMUIStatusBarHelper.translucent(this) //沉浸式状态栏
+ setupTopBarLayout()
+ initData()
+ initEvent()
+ }
+
+ override fun onDestroy() {
+ cancel()// 取消协程
+ super.onDestroy()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/model/PublicKeyBean.kt b/app/src/main/java/com/casic/birmm/inspect/model/PublicKeyBean.kt
new file mode 100644
index 0000000..25c5436
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/model/PublicKeyBean.kt
@@ -0,0 +1,18 @@
+package com.casic.birmm.inspect.model
+
+/**
+ * PublicKey 登录校验Key
+ */
+class PublicKeyBean {
+ var code = 0
+ var data: DataBean? = null
+ var message: String? = null
+ var isSuccess = false
+
+ class DataBean {
+ var isAppKaptcha = false
+ var isKaptcha = false
+ var publicKey: String? = null
+ var sid: String? = null
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/ui/GuideActivity.kt b/app/src/main/java/com/casic/birmm/inspect/ui/GuideActivity.kt
deleted file mode 100644
index ddc160a..0000000
--- a/app/src/main/java/com/casic/birmm/inspect/ui/GuideActivity.kt
+++ /dev/null
@@ -1,56 +0,0 @@
-package com.casic.birmm.inspect.ui
-
-import android.annotation.SuppressLint
-import android.content.Intent
-import android.os.CountDownTimer
-import android.view.ViewGroup.MarginLayoutParams
-import com.casic.birmm.inspect.R
-import com.casic.birmm.inspect.base.BaseActivity
-import com.qmuiteam.qmui.util.QMUIDisplayHelper
-import kotlinx.android.synthetic.main.activity_guide.*
-
-@SuppressLint("SetTextI18n")
-class GuideActivity : BaseActivity() {
-
- private lateinit var countDownTimer: CountDownTimer
-
- override fun initLayoutView(): Int = R.layout.activity_guide
-
- override fun setupTopBarLayout() {
-
- }
-
- override fun initData() {
- //根据不同设备状态栏高度设置"跳过"按钮的Margin值
- val statusBarHeight = QMUIDisplayHelper.getStatusBarHeight(this)
- val rightMargin = QMUIDisplayHelper.dp2px(this, 10)
- if (skipButton.layoutParams is MarginLayoutParams) {
- val params = skipButton.layoutParams as MarginLayoutParams
- params.setMargins(skipButton.width, statusBarHeight, rightMargin, 0)
- skipButton.requestLayout()
- }
-
- countDownTimer = object : CountDownTimer(4000, 1000) {
- override fun onFinish() {
- startLoginActivity()
- }
-
- override fun onTick(millisUntilFinished: Long) {
- skipButton.text = "跳过\u3000${(millisUntilFinished / 1000)}s"
- }
- }
- }
-
- override fun initEvent() {
- countDownTimer.start()
- skipButton.setOnClickListener {
- countDownTimer.cancel()
- startLoginActivity()
- }
- }
-
- fun startLoginActivity() {
- startActivity(Intent(this, LoginActivity::class.java))
- finish()
- }
-}
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..35eb1dd
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
index 4ca4a9f..0002b4a 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -27,6 +27,12 @@
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
+
+ kotlin {
+ experimental {
+ coroutines 'enable'
+ }
+ }
}
dependencies {
@@ -47,19 +53,24 @@
implementation 'com.gyf.immersionbar:immersionbar:3.0.0'
//fragment快速实现
implementation 'com.gyf.immersionbar:immersionbar-components:3.0.0'
+ //MVVM
+ implementation "androidx.lifecycle:lifecycle-livedata:2.2.0"
+ implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0"
+ implementation "androidx.lifecycle:lifecycle-extensions:2.2.0"
+ //Kotlin协程
+ implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.0'
+ implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.0'
+ //返回值转换器
+ implementation 'com.jakewharton.retrofit:retrofit2-kotlin-coroutines-adapter:0.9.2'
+ implementation 'com.squareup.retrofit2:converter-scalars:2.0.0'
+ implementation 'com.squareup.retrofit2:converter-gson:2.8.1'
+ //okhttp3日志拦截器
+ implementation 'com.squareup.okhttp3:logging-interceptor:4.6.0'
- //MVP网络请求框架retrofit2+rxjava
- implementation 'io.reactivex:rxjava:1.3.8'
- implementation 'io.reactivex:rxandroid:1.2.1'
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.okhttp3:okhttp:4.6.0'
- implementation 'com.squareup.retrofit2:converter-gson:2.8.1'
- implementation 'com.squareup.retrofit2:adapter-rxjava:2.8.1'
- implementation 'com.squareup.okhttp3:logging-interceptor:4.6.0'
//官方Json解析库
implementation 'com.google.code.gson:gson:2.8.6'
- //Toast提示
- implementation 'com.sdsmdg.tastytoast:tastytoast:0.1.1'
//图片选择框架
implementation 'com.github.LuckSiege.PictureSelector:picture_library:v2.6.0'
//上拉加载下拉刷新
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 7096527..be35467 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -23,16 +23,16 @@
android:theme="@style/QMUI.Compat.NoActionBar"
android:usesCleartextTraffic="true"
tools:targetApi="m">
-
+
-
-
-
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/base/BaseActivity.kt b/app/src/main/java/com/casic/birmm/inspect/base/BaseActivity.kt
index aefdbb6..b6b9f53 100644
--- a/app/src/main/java/com/casic/birmm/inspect/base/BaseActivity.kt
+++ b/app/src/main/java/com/casic/birmm/inspect/base/BaseActivity.kt
@@ -4,6 +4,9 @@
import androidx.appcompat.app.AppCompatActivity
import com.qmuiteam.qmui.util.QMUIStatusBarHelper
+/**
+ * 无网络请求等普通页面的基础类
+ * */
abstract class BaseActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
diff --git a/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModel.kt b/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModel.kt
new file mode 100644
index 0000000..968b877
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModel.kt
@@ -0,0 +1,9 @@
+package com.casic.birmm.inspect.base
+
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.ViewModel
+import com.casic.birmm.inspect.utils.LoadState
+
+abstract class BaseViewModel : ViewModel() {
+ val loadState = MutableLiveData()
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModelActivity.kt b/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModelActivity.kt
new file mode 100644
index 0000000..ee93c84
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModelActivity.kt
@@ -0,0 +1,61 @@
+package com.casic.birmm.inspect.base
+
+import android.os.Bundle
+import androidx.appcompat.app.AppCompatActivity
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.ViewModelProvider
+import com.qmuiteam.qmui.util.QMUIStatusBarHelper
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.MainScope
+import kotlinx.coroutines.cancel
+
+/**
+ * MV ViewModel 架构
+ *
+ * 有网络请求等普通页面的基础类
+ */
+abstract class BaseViewModelActivity : AppCompatActivity(),
+ CoroutineScope by MainScope() {
+
+ protected lateinit var viewModel: VM
+
+ /**
+ * 初始化xml布局
+ */
+ protected abstract fun initLayoutView(): Int
+
+ /**
+ * 特定页面定制沉浸式状态栏
+ */
+ protected abstract fun setupTopBarLayout()
+
+ /**
+ * 初始化默认数据
+ */
+ abstract fun initData()
+
+ /**
+ * 初始化业务逻辑
+ */
+ abstract fun initEvent()
+
+ /**
+ * 提供ViewModel类
+ */
+ protected abstract fun createViewModelByClass(): Class?
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(initLayoutView())
+ createViewModelByClass()?.let { viewModel = ViewModelProvider(this).get(it) }
+ QMUIStatusBarHelper.translucent(this) //沉浸式状态栏
+ setupTopBarLayout()
+ initData()
+ initEvent()
+ }
+
+ override fun onDestroy() {
+ cancel()// 取消协程
+ super.onDestroy()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/model/PublicKeyBean.kt b/app/src/main/java/com/casic/birmm/inspect/model/PublicKeyBean.kt
new file mode 100644
index 0000000..25c5436
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/model/PublicKeyBean.kt
@@ -0,0 +1,18 @@
+package com.casic.birmm.inspect.model
+
+/**
+ * PublicKey 登录校验Key
+ */
+class PublicKeyBean {
+ var code = 0
+ var data: DataBean? = null
+ var message: String? = null
+ var isSuccess = false
+
+ class DataBean {
+ var isAppKaptcha = false
+ var isKaptcha = false
+ var publicKey: String? = null
+ var sid: String? = null
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/ui/GuideActivity.kt b/app/src/main/java/com/casic/birmm/inspect/ui/GuideActivity.kt
deleted file mode 100644
index ddc160a..0000000
--- a/app/src/main/java/com/casic/birmm/inspect/ui/GuideActivity.kt
+++ /dev/null
@@ -1,56 +0,0 @@
-package com.casic.birmm.inspect.ui
-
-import android.annotation.SuppressLint
-import android.content.Intent
-import android.os.CountDownTimer
-import android.view.ViewGroup.MarginLayoutParams
-import com.casic.birmm.inspect.R
-import com.casic.birmm.inspect.base.BaseActivity
-import com.qmuiteam.qmui.util.QMUIDisplayHelper
-import kotlinx.android.synthetic.main.activity_guide.*
-
-@SuppressLint("SetTextI18n")
-class GuideActivity : BaseActivity() {
-
- private lateinit var countDownTimer: CountDownTimer
-
- override fun initLayoutView(): Int = R.layout.activity_guide
-
- override fun setupTopBarLayout() {
-
- }
-
- override fun initData() {
- //根据不同设备状态栏高度设置"跳过"按钮的Margin值
- val statusBarHeight = QMUIDisplayHelper.getStatusBarHeight(this)
- val rightMargin = QMUIDisplayHelper.dp2px(this, 10)
- if (skipButton.layoutParams is MarginLayoutParams) {
- val params = skipButton.layoutParams as MarginLayoutParams
- params.setMargins(skipButton.width, statusBarHeight, rightMargin, 0)
- skipButton.requestLayout()
- }
-
- countDownTimer = object : CountDownTimer(4000, 1000) {
- override fun onFinish() {
- startLoginActivity()
- }
-
- override fun onTick(millisUntilFinished: Long) {
- skipButton.text = "跳过\u3000${(millisUntilFinished / 1000)}s"
- }
- }
- }
-
- override fun initEvent() {
- countDownTimer.start()
- skipButton.setOnClickListener {
- countDownTimer.cancel()
- startLoginActivity()
- }
- }
-
- fun startLoginActivity() {
- startActivity(Intent(this, LoginActivity::class.java))
- finish()
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/ui/LoginActivity.kt b/app/src/main/java/com/casic/birmm/inspect/ui/LoginActivity.kt
deleted file mode 100644
index 6ef4548..0000000
--- a/app/src/main/java/com/casic/birmm/inspect/ui/LoginActivity.kt
+++ /dev/null
@@ -1,81 +0,0 @@
-package com.casic.birmm.inspect.ui
-
-import android.text.Editable
-import android.text.TextWatcher
-import android.view.KeyEvent
-import android.view.inputmethod.EditorInfo
-import android.widget.EditText
-import android.widget.TextView
-import com.casic.birmm.inspect.R
-import com.casic.birmm.inspect.base.BaseActivity
-import com.casic.birmm.inspect.utils.Constant
-import com.casic.birmm.inspect.utils.SaveKeyValues
-import com.casic.birmm.inspect.widgets.InputDialog
-import kotlinx.android.synthetic.main.activity_login.*
-
-
-class LoginActivity : BaseActivity() {
-
- companion object {
- private const val Tag = "LoginActivity"
- }
-
- override fun initLayoutView(): Int = R.layout.activity_login
-
- override fun setupTopBarLayout() {
-
- }
-
- override fun initData() {
-
- }
-
- override fun initEvent() {
- loginButton.setChangeAlphaWhenPress(true)
- val editText: EditText? = inputLayout.editText
- editText?.addTextChangedListener(object : TextWatcher {
- override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
-
- }
-
- override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
-
- }
-
- override fun afterTextChanged(s: Editable) {
- if (s.toString().trim { it <= ' ' }.length > 12) {
- inputLayout.error = "密码长度超出限制"
- } else {
- inputLayout.error = null
- }
- }
- })
- //点击输入法键盘"完成"
- editText?.setOnEditorActionListener { _: TextView?, actionId: Int, _: KeyEvent? ->
- if (actionId == EditorInfo.IME_ACTION_DONE) {
-// authenticatePresenter.onReadyRetrofitRequest()
- return@setOnEditorActionListener true
- }
- false
- }
-
- //修改服务器配置
- changeServerConfigView.setOnClickListener {
- val defaultValue = SaveKeyValues.getValue(
- Constant.DEFAULT_SERVER_CONFIG,
- "http://139.198.6.177:8093/"
- ) as String
- InputDialog.Builder().setContext(this)
- .setTitle("请输入后台服务器地址")
- .setDefaultValue(defaultValue)
- .setNegativeButton("取消")
- .setPositiveButton("保存")
- .setOnDialogClickListener(object : InputDialog.OnDialogButtonClickListener {
- override fun onButtonClick(input: String) {
- SaveKeyValues.putValue(Constant.DEFAULT_SERVER_CONFIG, input)
- }
- })
- .build().show()
- }
- }
-}
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..35eb1dd
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
index 4ca4a9f..0002b4a 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -27,6 +27,12 @@
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
+
+ kotlin {
+ experimental {
+ coroutines 'enable'
+ }
+ }
}
dependencies {
@@ -47,19 +53,24 @@
implementation 'com.gyf.immersionbar:immersionbar:3.0.0'
//fragment快速实现
implementation 'com.gyf.immersionbar:immersionbar-components:3.0.0'
+ //MVVM
+ implementation "androidx.lifecycle:lifecycle-livedata:2.2.0"
+ implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0"
+ implementation "androidx.lifecycle:lifecycle-extensions:2.2.0"
+ //Kotlin协程
+ implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.0'
+ implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.0'
+ //返回值转换器
+ implementation 'com.jakewharton.retrofit:retrofit2-kotlin-coroutines-adapter:0.9.2'
+ implementation 'com.squareup.retrofit2:converter-scalars:2.0.0'
+ implementation 'com.squareup.retrofit2:converter-gson:2.8.1'
+ //okhttp3日志拦截器
+ implementation 'com.squareup.okhttp3:logging-interceptor:4.6.0'
- //MVP网络请求框架retrofit2+rxjava
- implementation 'io.reactivex:rxjava:1.3.8'
- implementation 'io.reactivex:rxandroid:1.2.1'
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.okhttp3:okhttp:4.6.0'
- implementation 'com.squareup.retrofit2:converter-gson:2.8.1'
- implementation 'com.squareup.retrofit2:adapter-rxjava:2.8.1'
- implementation 'com.squareup.okhttp3:logging-interceptor:4.6.0'
//官方Json解析库
implementation 'com.google.code.gson:gson:2.8.6'
- //Toast提示
- implementation 'com.sdsmdg.tastytoast:tastytoast:0.1.1'
//图片选择框架
implementation 'com.github.LuckSiege.PictureSelector:picture_library:v2.6.0'
//上拉加载下拉刷新
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 7096527..be35467 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -23,16 +23,16 @@
android:theme="@style/QMUI.Compat.NoActionBar"
android:usesCleartextTraffic="true"
tools:targetApi="m">
-
+
-
-
-
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/base/BaseActivity.kt b/app/src/main/java/com/casic/birmm/inspect/base/BaseActivity.kt
index aefdbb6..b6b9f53 100644
--- a/app/src/main/java/com/casic/birmm/inspect/base/BaseActivity.kt
+++ b/app/src/main/java/com/casic/birmm/inspect/base/BaseActivity.kt
@@ -4,6 +4,9 @@
import androidx.appcompat.app.AppCompatActivity
import com.qmuiteam.qmui.util.QMUIStatusBarHelper
+/**
+ * 无网络请求等普通页面的基础类
+ * */
abstract class BaseActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
diff --git a/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModel.kt b/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModel.kt
new file mode 100644
index 0000000..968b877
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModel.kt
@@ -0,0 +1,9 @@
+package com.casic.birmm.inspect.base
+
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.ViewModel
+import com.casic.birmm.inspect.utils.LoadState
+
+abstract class BaseViewModel : ViewModel() {
+ val loadState = MutableLiveData()
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModelActivity.kt b/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModelActivity.kt
new file mode 100644
index 0000000..ee93c84
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModelActivity.kt
@@ -0,0 +1,61 @@
+package com.casic.birmm.inspect.base
+
+import android.os.Bundle
+import androidx.appcompat.app.AppCompatActivity
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.ViewModelProvider
+import com.qmuiteam.qmui.util.QMUIStatusBarHelper
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.MainScope
+import kotlinx.coroutines.cancel
+
+/**
+ * MV ViewModel 架构
+ *
+ * 有网络请求等普通页面的基础类
+ */
+abstract class BaseViewModelActivity : AppCompatActivity(),
+ CoroutineScope by MainScope() {
+
+ protected lateinit var viewModel: VM
+
+ /**
+ * 初始化xml布局
+ */
+ protected abstract fun initLayoutView(): Int
+
+ /**
+ * 特定页面定制沉浸式状态栏
+ */
+ protected abstract fun setupTopBarLayout()
+
+ /**
+ * 初始化默认数据
+ */
+ abstract fun initData()
+
+ /**
+ * 初始化业务逻辑
+ */
+ abstract fun initEvent()
+
+ /**
+ * 提供ViewModel类
+ */
+ protected abstract fun createViewModelByClass(): Class?
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(initLayoutView())
+ createViewModelByClass()?.let { viewModel = ViewModelProvider(this).get(it) }
+ QMUIStatusBarHelper.translucent(this) //沉浸式状态栏
+ setupTopBarLayout()
+ initData()
+ initEvent()
+ }
+
+ override fun onDestroy() {
+ cancel()// 取消协程
+ super.onDestroy()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/model/PublicKeyBean.kt b/app/src/main/java/com/casic/birmm/inspect/model/PublicKeyBean.kt
new file mode 100644
index 0000000..25c5436
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/model/PublicKeyBean.kt
@@ -0,0 +1,18 @@
+package com.casic.birmm.inspect.model
+
+/**
+ * PublicKey 登录校验Key
+ */
+class PublicKeyBean {
+ var code = 0
+ var data: DataBean? = null
+ var message: String? = null
+ var isSuccess = false
+
+ class DataBean {
+ var isAppKaptcha = false
+ var isKaptcha = false
+ var publicKey: String? = null
+ var sid: String? = null
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/ui/GuideActivity.kt b/app/src/main/java/com/casic/birmm/inspect/ui/GuideActivity.kt
deleted file mode 100644
index ddc160a..0000000
--- a/app/src/main/java/com/casic/birmm/inspect/ui/GuideActivity.kt
+++ /dev/null
@@ -1,56 +0,0 @@
-package com.casic.birmm.inspect.ui
-
-import android.annotation.SuppressLint
-import android.content.Intent
-import android.os.CountDownTimer
-import android.view.ViewGroup.MarginLayoutParams
-import com.casic.birmm.inspect.R
-import com.casic.birmm.inspect.base.BaseActivity
-import com.qmuiteam.qmui.util.QMUIDisplayHelper
-import kotlinx.android.synthetic.main.activity_guide.*
-
-@SuppressLint("SetTextI18n")
-class GuideActivity : BaseActivity() {
-
- private lateinit var countDownTimer: CountDownTimer
-
- override fun initLayoutView(): Int = R.layout.activity_guide
-
- override fun setupTopBarLayout() {
-
- }
-
- override fun initData() {
- //根据不同设备状态栏高度设置"跳过"按钮的Margin值
- val statusBarHeight = QMUIDisplayHelper.getStatusBarHeight(this)
- val rightMargin = QMUIDisplayHelper.dp2px(this, 10)
- if (skipButton.layoutParams is MarginLayoutParams) {
- val params = skipButton.layoutParams as MarginLayoutParams
- params.setMargins(skipButton.width, statusBarHeight, rightMargin, 0)
- skipButton.requestLayout()
- }
-
- countDownTimer = object : CountDownTimer(4000, 1000) {
- override fun onFinish() {
- startLoginActivity()
- }
-
- override fun onTick(millisUntilFinished: Long) {
- skipButton.text = "跳过\u3000${(millisUntilFinished / 1000)}s"
- }
- }
- }
-
- override fun initEvent() {
- countDownTimer.start()
- skipButton.setOnClickListener {
- countDownTimer.cancel()
- startLoginActivity()
- }
- }
-
- fun startLoginActivity() {
- startActivity(Intent(this, LoginActivity::class.java))
- finish()
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/ui/LoginActivity.kt b/app/src/main/java/com/casic/birmm/inspect/ui/LoginActivity.kt
deleted file mode 100644
index 6ef4548..0000000
--- a/app/src/main/java/com/casic/birmm/inspect/ui/LoginActivity.kt
+++ /dev/null
@@ -1,81 +0,0 @@
-package com.casic.birmm.inspect.ui
-
-import android.text.Editable
-import android.text.TextWatcher
-import android.view.KeyEvent
-import android.view.inputmethod.EditorInfo
-import android.widget.EditText
-import android.widget.TextView
-import com.casic.birmm.inspect.R
-import com.casic.birmm.inspect.base.BaseActivity
-import com.casic.birmm.inspect.utils.Constant
-import com.casic.birmm.inspect.utils.SaveKeyValues
-import com.casic.birmm.inspect.widgets.InputDialog
-import kotlinx.android.synthetic.main.activity_login.*
-
-
-class LoginActivity : BaseActivity() {
-
- companion object {
- private const val Tag = "LoginActivity"
- }
-
- override fun initLayoutView(): Int = R.layout.activity_login
-
- override fun setupTopBarLayout() {
-
- }
-
- override fun initData() {
-
- }
-
- override fun initEvent() {
- loginButton.setChangeAlphaWhenPress(true)
- val editText: EditText? = inputLayout.editText
- editText?.addTextChangedListener(object : TextWatcher {
- override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
-
- }
-
- override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
-
- }
-
- override fun afterTextChanged(s: Editable) {
- if (s.toString().trim { it <= ' ' }.length > 12) {
- inputLayout.error = "密码长度超出限制"
- } else {
- inputLayout.error = null
- }
- }
- })
- //点击输入法键盘"完成"
- editText?.setOnEditorActionListener { _: TextView?, actionId: Int, _: KeyEvent? ->
- if (actionId == EditorInfo.IME_ACTION_DONE) {
-// authenticatePresenter.onReadyRetrofitRequest()
- return@setOnEditorActionListener true
- }
- false
- }
-
- //修改服务器配置
- changeServerConfigView.setOnClickListener {
- val defaultValue = SaveKeyValues.getValue(
- Constant.DEFAULT_SERVER_CONFIG,
- "http://139.198.6.177:8093/"
- ) as String
- InputDialog.Builder().setContext(this)
- .setTitle("请输入后台服务器地址")
- .setDefaultValue(defaultValue)
- .setNegativeButton("取消")
- .setPositiveButton("保存")
- .setOnDialogClickListener(object : InputDialog.OnDialogButtonClickListener {
- override fun onButtonClick(input: String) {
- SaveKeyValues.putValue(Constant.DEFAULT_SERVER_CONFIG, input)
- }
- })
- .build().show()
- }
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/ui/MainActivity.kt b/app/src/main/java/com/casic/birmm/inspect/ui/MainActivity.kt
deleted file mode 100644
index 0e97af7..0000000
--- a/app/src/main/java/com/casic/birmm/inspect/ui/MainActivity.kt
+++ /dev/null
@@ -1,21 +0,0 @@
-package com.casic.birmm.inspect.ui
-
-import com.casic.birmm.inspect.R
-import com.casic.birmm.inspect.base.BaseActivity
-
-class MainActivity : BaseActivity() {
-
- override fun initLayoutView(): Int = R.layout.activity_main
-
- override fun setupTopBarLayout() {
-
- }
-
- override fun initData() {
-
- }
-
- override fun initEvent() {
-
- }
-}
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..35eb1dd
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
index 4ca4a9f..0002b4a 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -27,6 +27,12 @@
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
+
+ kotlin {
+ experimental {
+ coroutines 'enable'
+ }
+ }
}
dependencies {
@@ -47,19 +53,24 @@
implementation 'com.gyf.immersionbar:immersionbar:3.0.0'
//fragment快速实现
implementation 'com.gyf.immersionbar:immersionbar-components:3.0.0'
+ //MVVM
+ implementation "androidx.lifecycle:lifecycle-livedata:2.2.0"
+ implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0"
+ implementation "androidx.lifecycle:lifecycle-extensions:2.2.0"
+ //Kotlin协程
+ implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.0'
+ implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.0'
+ //返回值转换器
+ implementation 'com.jakewharton.retrofit:retrofit2-kotlin-coroutines-adapter:0.9.2'
+ implementation 'com.squareup.retrofit2:converter-scalars:2.0.0'
+ implementation 'com.squareup.retrofit2:converter-gson:2.8.1'
+ //okhttp3日志拦截器
+ implementation 'com.squareup.okhttp3:logging-interceptor:4.6.0'
- //MVP网络请求框架retrofit2+rxjava
- implementation 'io.reactivex:rxjava:1.3.8'
- implementation 'io.reactivex:rxandroid:1.2.1'
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.okhttp3:okhttp:4.6.0'
- implementation 'com.squareup.retrofit2:converter-gson:2.8.1'
- implementation 'com.squareup.retrofit2:adapter-rxjava:2.8.1'
- implementation 'com.squareup.okhttp3:logging-interceptor:4.6.0'
//官方Json解析库
implementation 'com.google.code.gson:gson:2.8.6'
- //Toast提示
- implementation 'com.sdsmdg.tastytoast:tastytoast:0.1.1'
//图片选择框架
implementation 'com.github.LuckSiege.PictureSelector:picture_library:v2.6.0'
//上拉加载下拉刷新
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 7096527..be35467 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -23,16 +23,16 @@
android:theme="@style/QMUI.Compat.NoActionBar"
android:usesCleartextTraffic="true"
tools:targetApi="m">
-
+
-
-
-
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/base/BaseActivity.kt b/app/src/main/java/com/casic/birmm/inspect/base/BaseActivity.kt
index aefdbb6..b6b9f53 100644
--- a/app/src/main/java/com/casic/birmm/inspect/base/BaseActivity.kt
+++ b/app/src/main/java/com/casic/birmm/inspect/base/BaseActivity.kt
@@ -4,6 +4,9 @@
import androidx.appcompat.app.AppCompatActivity
import com.qmuiteam.qmui.util.QMUIStatusBarHelper
+/**
+ * 无网络请求等普通页面的基础类
+ * */
abstract class BaseActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
diff --git a/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModel.kt b/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModel.kt
new file mode 100644
index 0000000..968b877
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModel.kt
@@ -0,0 +1,9 @@
+package com.casic.birmm.inspect.base
+
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.ViewModel
+import com.casic.birmm.inspect.utils.LoadState
+
+abstract class BaseViewModel : ViewModel() {
+ val loadState = MutableLiveData()
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModelActivity.kt b/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModelActivity.kt
new file mode 100644
index 0000000..ee93c84
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModelActivity.kt
@@ -0,0 +1,61 @@
+package com.casic.birmm.inspect.base
+
+import android.os.Bundle
+import androidx.appcompat.app.AppCompatActivity
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.ViewModelProvider
+import com.qmuiteam.qmui.util.QMUIStatusBarHelper
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.MainScope
+import kotlinx.coroutines.cancel
+
+/**
+ * MV ViewModel 架构
+ *
+ * 有网络请求等普通页面的基础类
+ */
+abstract class BaseViewModelActivity : AppCompatActivity(),
+ CoroutineScope by MainScope() {
+
+ protected lateinit var viewModel: VM
+
+ /**
+ * 初始化xml布局
+ */
+ protected abstract fun initLayoutView(): Int
+
+ /**
+ * 特定页面定制沉浸式状态栏
+ */
+ protected abstract fun setupTopBarLayout()
+
+ /**
+ * 初始化默认数据
+ */
+ abstract fun initData()
+
+ /**
+ * 初始化业务逻辑
+ */
+ abstract fun initEvent()
+
+ /**
+ * 提供ViewModel类
+ */
+ protected abstract fun createViewModelByClass(): Class?
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(initLayoutView())
+ createViewModelByClass()?.let { viewModel = ViewModelProvider(this).get(it) }
+ QMUIStatusBarHelper.translucent(this) //沉浸式状态栏
+ setupTopBarLayout()
+ initData()
+ initEvent()
+ }
+
+ override fun onDestroy() {
+ cancel()// 取消协程
+ super.onDestroy()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/model/PublicKeyBean.kt b/app/src/main/java/com/casic/birmm/inspect/model/PublicKeyBean.kt
new file mode 100644
index 0000000..25c5436
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/model/PublicKeyBean.kt
@@ -0,0 +1,18 @@
+package com.casic.birmm.inspect.model
+
+/**
+ * PublicKey 登录校验Key
+ */
+class PublicKeyBean {
+ var code = 0
+ var data: DataBean? = null
+ var message: String? = null
+ var isSuccess = false
+
+ class DataBean {
+ var isAppKaptcha = false
+ var isKaptcha = false
+ var publicKey: String? = null
+ var sid: String? = null
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/ui/GuideActivity.kt b/app/src/main/java/com/casic/birmm/inspect/ui/GuideActivity.kt
deleted file mode 100644
index ddc160a..0000000
--- a/app/src/main/java/com/casic/birmm/inspect/ui/GuideActivity.kt
+++ /dev/null
@@ -1,56 +0,0 @@
-package com.casic.birmm.inspect.ui
-
-import android.annotation.SuppressLint
-import android.content.Intent
-import android.os.CountDownTimer
-import android.view.ViewGroup.MarginLayoutParams
-import com.casic.birmm.inspect.R
-import com.casic.birmm.inspect.base.BaseActivity
-import com.qmuiteam.qmui.util.QMUIDisplayHelper
-import kotlinx.android.synthetic.main.activity_guide.*
-
-@SuppressLint("SetTextI18n")
-class GuideActivity : BaseActivity() {
-
- private lateinit var countDownTimer: CountDownTimer
-
- override fun initLayoutView(): Int = R.layout.activity_guide
-
- override fun setupTopBarLayout() {
-
- }
-
- override fun initData() {
- //根据不同设备状态栏高度设置"跳过"按钮的Margin值
- val statusBarHeight = QMUIDisplayHelper.getStatusBarHeight(this)
- val rightMargin = QMUIDisplayHelper.dp2px(this, 10)
- if (skipButton.layoutParams is MarginLayoutParams) {
- val params = skipButton.layoutParams as MarginLayoutParams
- params.setMargins(skipButton.width, statusBarHeight, rightMargin, 0)
- skipButton.requestLayout()
- }
-
- countDownTimer = object : CountDownTimer(4000, 1000) {
- override fun onFinish() {
- startLoginActivity()
- }
-
- override fun onTick(millisUntilFinished: Long) {
- skipButton.text = "跳过\u3000${(millisUntilFinished / 1000)}s"
- }
- }
- }
-
- override fun initEvent() {
- countDownTimer.start()
- skipButton.setOnClickListener {
- countDownTimer.cancel()
- startLoginActivity()
- }
- }
-
- fun startLoginActivity() {
- startActivity(Intent(this, LoginActivity::class.java))
- finish()
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/ui/LoginActivity.kt b/app/src/main/java/com/casic/birmm/inspect/ui/LoginActivity.kt
deleted file mode 100644
index 6ef4548..0000000
--- a/app/src/main/java/com/casic/birmm/inspect/ui/LoginActivity.kt
+++ /dev/null
@@ -1,81 +0,0 @@
-package com.casic.birmm.inspect.ui
-
-import android.text.Editable
-import android.text.TextWatcher
-import android.view.KeyEvent
-import android.view.inputmethod.EditorInfo
-import android.widget.EditText
-import android.widget.TextView
-import com.casic.birmm.inspect.R
-import com.casic.birmm.inspect.base.BaseActivity
-import com.casic.birmm.inspect.utils.Constant
-import com.casic.birmm.inspect.utils.SaveKeyValues
-import com.casic.birmm.inspect.widgets.InputDialog
-import kotlinx.android.synthetic.main.activity_login.*
-
-
-class LoginActivity : BaseActivity() {
-
- companion object {
- private const val Tag = "LoginActivity"
- }
-
- override fun initLayoutView(): Int = R.layout.activity_login
-
- override fun setupTopBarLayout() {
-
- }
-
- override fun initData() {
-
- }
-
- override fun initEvent() {
- loginButton.setChangeAlphaWhenPress(true)
- val editText: EditText? = inputLayout.editText
- editText?.addTextChangedListener(object : TextWatcher {
- override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
-
- }
-
- override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
-
- }
-
- override fun afterTextChanged(s: Editable) {
- if (s.toString().trim { it <= ' ' }.length > 12) {
- inputLayout.error = "密码长度超出限制"
- } else {
- inputLayout.error = null
- }
- }
- })
- //点击输入法键盘"完成"
- editText?.setOnEditorActionListener { _: TextView?, actionId: Int, _: KeyEvent? ->
- if (actionId == EditorInfo.IME_ACTION_DONE) {
-// authenticatePresenter.onReadyRetrofitRequest()
- return@setOnEditorActionListener true
- }
- false
- }
-
- //修改服务器配置
- changeServerConfigView.setOnClickListener {
- val defaultValue = SaveKeyValues.getValue(
- Constant.DEFAULT_SERVER_CONFIG,
- "http://139.198.6.177:8093/"
- ) as String
- InputDialog.Builder().setContext(this)
- .setTitle("请输入后台服务器地址")
- .setDefaultValue(defaultValue)
- .setNegativeButton("取消")
- .setPositiveButton("保存")
- .setOnDialogClickListener(object : InputDialog.OnDialogButtonClickListener {
- override fun onButtonClick(input: String) {
- SaveKeyValues.putValue(Constant.DEFAULT_SERVER_CONFIG, input)
- }
- })
- .build().show()
- }
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/ui/MainActivity.kt b/app/src/main/java/com/casic/birmm/inspect/ui/MainActivity.kt
deleted file mode 100644
index 0e97af7..0000000
--- a/app/src/main/java/com/casic/birmm/inspect/ui/MainActivity.kt
+++ /dev/null
@@ -1,21 +0,0 @@
-package com.casic.birmm.inspect.ui
-
-import com.casic.birmm.inspect.R
-import com.casic.birmm.inspect.base.BaseActivity
-
-class MainActivity : BaseActivity() {
-
- override fun initLayoutView(): Int = R.layout.activity_main
-
- override fun setupTopBarLayout() {
-
- }
-
- override fun initData() {
-
- }
-
- override fun initEvent() {
-
- }
-}
diff --git a/app/src/main/java/com/casic/birmm/inspect/ui/PermissionActivity.kt b/app/src/main/java/com/casic/birmm/inspect/ui/PermissionActivity.kt
deleted file mode 100644
index 21fbba2..0000000
--- a/app/src/main/java/com/casic/birmm/inspect/ui/PermissionActivity.kt
+++ /dev/null
@@ -1,58 +0,0 @@
-package com.casic.birmm.inspect.ui
-
-import android.content.Intent
-import android.os.Build
-import android.os.Bundle
-import android.util.Log
-import androidx.appcompat.app.AppCompatActivity
-import com.casic.birmm.inspect.utils.Constant
-import pub.devrel.easypermissions.EasyPermissions
-import pub.devrel.easypermissions.EasyPermissions.PermissionCallbacks
-
-class PermissionActivity : AppCompatActivity(), PermissionCallbacks {
-
- companion object {
- private const val TAG = "PermissionActivity"
- }
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- //判断是否有权限,如果版本大于5.1才需要判断(即6.0以上),其他则不需要判断。
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
- if (EasyPermissions.hasPermissions(this, *Constant.USER_PERMISSIONS)) {
- startGuideActivity()
- } else {
- EasyPermissions.requestPermissions(
- this,
- "需要获取相关权限",
- Constant.PERMISSIONS_CODE,
- *Constant.USER_PERMISSIONS
- )
- }
- } else {
- startGuideActivity()
- }
- }
-
- private fun startGuideActivity() {
- startActivity(Intent(this, GuideActivity::class.java))
- finish()
- }
-
- override fun onRequestPermissionsResult(
- requestCode: Int,
- permissions: Array,
- grantResults: IntArray
- ) {
- super.onRequestPermissionsResult(requestCode, permissions, grantResults)
- EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this)
- }
-
- override fun onPermissionsGranted(requestCode: Int, perms: List) {
- startGuideActivity()
- }
-
- override fun onPermissionsDenied(requestCode: Int, perms: List) {
- Log.e(TAG, "onPermissionsDenied: $perms")
- }
-}
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..35eb1dd
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
index 4ca4a9f..0002b4a 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -27,6 +27,12 @@
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
+
+ kotlin {
+ experimental {
+ coroutines 'enable'
+ }
+ }
}
dependencies {
@@ -47,19 +53,24 @@
implementation 'com.gyf.immersionbar:immersionbar:3.0.0'
//fragment快速实现
implementation 'com.gyf.immersionbar:immersionbar-components:3.0.0'
+ //MVVM
+ implementation "androidx.lifecycle:lifecycle-livedata:2.2.0"
+ implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0"
+ implementation "androidx.lifecycle:lifecycle-extensions:2.2.0"
+ //Kotlin协程
+ implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.0'
+ implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.0'
+ //返回值转换器
+ implementation 'com.jakewharton.retrofit:retrofit2-kotlin-coroutines-adapter:0.9.2'
+ implementation 'com.squareup.retrofit2:converter-scalars:2.0.0'
+ implementation 'com.squareup.retrofit2:converter-gson:2.8.1'
+ //okhttp3日志拦截器
+ implementation 'com.squareup.okhttp3:logging-interceptor:4.6.0'
- //MVP网络请求框架retrofit2+rxjava
- implementation 'io.reactivex:rxjava:1.3.8'
- implementation 'io.reactivex:rxandroid:1.2.1'
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.okhttp3:okhttp:4.6.0'
- implementation 'com.squareup.retrofit2:converter-gson:2.8.1'
- implementation 'com.squareup.retrofit2:adapter-rxjava:2.8.1'
- implementation 'com.squareup.okhttp3:logging-interceptor:4.6.0'
//官方Json解析库
implementation 'com.google.code.gson:gson:2.8.6'
- //Toast提示
- implementation 'com.sdsmdg.tastytoast:tastytoast:0.1.1'
//图片选择框架
implementation 'com.github.LuckSiege.PictureSelector:picture_library:v2.6.0'
//上拉加载下拉刷新
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 7096527..be35467 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -23,16 +23,16 @@
android:theme="@style/QMUI.Compat.NoActionBar"
android:usesCleartextTraffic="true"
tools:targetApi="m">
-
+
-
-
-
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/base/BaseActivity.kt b/app/src/main/java/com/casic/birmm/inspect/base/BaseActivity.kt
index aefdbb6..b6b9f53 100644
--- a/app/src/main/java/com/casic/birmm/inspect/base/BaseActivity.kt
+++ b/app/src/main/java/com/casic/birmm/inspect/base/BaseActivity.kt
@@ -4,6 +4,9 @@
import androidx.appcompat.app.AppCompatActivity
import com.qmuiteam.qmui.util.QMUIStatusBarHelper
+/**
+ * 无网络请求等普通页面的基础类
+ * */
abstract class BaseActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
diff --git a/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModel.kt b/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModel.kt
new file mode 100644
index 0000000..968b877
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModel.kt
@@ -0,0 +1,9 @@
+package com.casic.birmm.inspect.base
+
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.ViewModel
+import com.casic.birmm.inspect.utils.LoadState
+
+abstract class BaseViewModel : ViewModel() {
+ val loadState = MutableLiveData()
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModelActivity.kt b/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModelActivity.kt
new file mode 100644
index 0000000..ee93c84
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModelActivity.kt
@@ -0,0 +1,61 @@
+package com.casic.birmm.inspect.base
+
+import android.os.Bundle
+import androidx.appcompat.app.AppCompatActivity
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.ViewModelProvider
+import com.qmuiteam.qmui.util.QMUIStatusBarHelper
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.MainScope
+import kotlinx.coroutines.cancel
+
+/**
+ * MV ViewModel 架构
+ *
+ * 有网络请求等普通页面的基础类
+ */
+abstract class BaseViewModelActivity : AppCompatActivity(),
+ CoroutineScope by MainScope() {
+
+ protected lateinit var viewModel: VM
+
+ /**
+ * 初始化xml布局
+ */
+ protected abstract fun initLayoutView(): Int
+
+ /**
+ * 特定页面定制沉浸式状态栏
+ */
+ protected abstract fun setupTopBarLayout()
+
+ /**
+ * 初始化默认数据
+ */
+ abstract fun initData()
+
+ /**
+ * 初始化业务逻辑
+ */
+ abstract fun initEvent()
+
+ /**
+ * 提供ViewModel类
+ */
+ protected abstract fun createViewModelByClass(): Class?
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(initLayoutView())
+ createViewModelByClass()?.let { viewModel = ViewModelProvider(this).get(it) }
+ QMUIStatusBarHelper.translucent(this) //沉浸式状态栏
+ setupTopBarLayout()
+ initData()
+ initEvent()
+ }
+
+ override fun onDestroy() {
+ cancel()// 取消协程
+ super.onDestroy()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/model/PublicKeyBean.kt b/app/src/main/java/com/casic/birmm/inspect/model/PublicKeyBean.kt
new file mode 100644
index 0000000..25c5436
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/model/PublicKeyBean.kt
@@ -0,0 +1,18 @@
+package com.casic.birmm.inspect.model
+
+/**
+ * PublicKey 登录校验Key
+ */
+class PublicKeyBean {
+ var code = 0
+ var data: DataBean? = null
+ var message: String? = null
+ var isSuccess = false
+
+ class DataBean {
+ var isAppKaptcha = false
+ var isKaptcha = false
+ var publicKey: String? = null
+ var sid: String? = null
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/ui/GuideActivity.kt b/app/src/main/java/com/casic/birmm/inspect/ui/GuideActivity.kt
deleted file mode 100644
index ddc160a..0000000
--- a/app/src/main/java/com/casic/birmm/inspect/ui/GuideActivity.kt
+++ /dev/null
@@ -1,56 +0,0 @@
-package com.casic.birmm.inspect.ui
-
-import android.annotation.SuppressLint
-import android.content.Intent
-import android.os.CountDownTimer
-import android.view.ViewGroup.MarginLayoutParams
-import com.casic.birmm.inspect.R
-import com.casic.birmm.inspect.base.BaseActivity
-import com.qmuiteam.qmui.util.QMUIDisplayHelper
-import kotlinx.android.synthetic.main.activity_guide.*
-
-@SuppressLint("SetTextI18n")
-class GuideActivity : BaseActivity() {
-
- private lateinit var countDownTimer: CountDownTimer
-
- override fun initLayoutView(): Int = R.layout.activity_guide
-
- override fun setupTopBarLayout() {
-
- }
-
- override fun initData() {
- //根据不同设备状态栏高度设置"跳过"按钮的Margin值
- val statusBarHeight = QMUIDisplayHelper.getStatusBarHeight(this)
- val rightMargin = QMUIDisplayHelper.dp2px(this, 10)
- if (skipButton.layoutParams is MarginLayoutParams) {
- val params = skipButton.layoutParams as MarginLayoutParams
- params.setMargins(skipButton.width, statusBarHeight, rightMargin, 0)
- skipButton.requestLayout()
- }
-
- countDownTimer = object : CountDownTimer(4000, 1000) {
- override fun onFinish() {
- startLoginActivity()
- }
-
- override fun onTick(millisUntilFinished: Long) {
- skipButton.text = "跳过\u3000${(millisUntilFinished / 1000)}s"
- }
- }
- }
-
- override fun initEvent() {
- countDownTimer.start()
- skipButton.setOnClickListener {
- countDownTimer.cancel()
- startLoginActivity()
- }
- }
-
- fun startLoginActivity() {
- startActivity(Intent(this, LoginActivity::class.java))
- finish()
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/ui/LoginActivity.kt b/app/src/main/java/com/casic/birmm/inspect/ui/LoginActivity.kt
deleted file mode 100644
index 6ef4548..0000000
--- a/app/src/main/java/com/casic/birmm/inspect/ui/LoginActivity.kt
+++ /dev/null
@@ -1,81 +0,0 @@
-package com.casic.birmm.inspect.ui
-
-import android.text.Editable
-import android.text.TextWatcher
-import android.view.KeyEvent
-import android.view.inputmethod.EditorInfo
-import android.widget.EditText
-import android.widget.TextView
-import com.casic.birmm.inspect.R
-import com.casic.birmm.inspect.base.BaseActivity
-import com.casic.birmm.inspect.utils.Constant
-import com.casic.birmm.inspect.utils.SaveKeyValues
-import com.casic.birmm.inspect.widgets.InputDialog
-import kotlinx.android.synthetic.main.activity_login.*
-
-
-class LoginActivity : BaseActivity() {
-
- companion object {
- private const val Tag = "LoginActivity"
- }
-
- override fun initLayoutView(): Int = R.layout.activity_login
-
- override fun setupTopBarLayout() {
-
- }
-
- override fun initData() {
-
- }
-
- override fun initEvent() {
- loginButton.setChangeAlphaWhenPress(true)
- val editText: EditText? = inputLayout.editText
- editText?.addTextChangedListener(object : TextWatcher {
- override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
-
- }
-
- override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
-
- }
-
- override fun afterTextChanged(s: Editable) {
- if (s.toString().trim { it <= ' ' }.length > 12) {
- inputLayout.error = "密码长度超出限制"
- } else {
- inputLayout.error = null
- }
- }
- })
- //点击输入法键盘"完成"
- editText?.setOnEditorActionListener { _: TextView?, actionId: Int, _: KeyEvent? ->
- if (actionId == EditorInfo.IME_ACTION_DONE) {
-// authenticatePresenter.onReadyRetrofitRequest()
- return@setOnEditorActionListener true
- }
- false
- }
-
- //修改服务器配置
- changeServerConfigView.setOnClickListener {
- val defaultValue = SaveKeyValues.getValue(
- Constant.DEFAULT_SERVER_CONFIG,
- "http://139.198.6.177:8093/"
- ) as String
- InputDialog.Builder().setContext(this)
- .setTitle("请输入后台服务器地址")
- .setDefaultValue(defaultValue)
- .setNegativeButton("取消")
- .setPositiveButton("保存")
- .setOnDialogClickListener(object : InputDialog.OnDialogButtonClickListener {
- override fun onButtonClick(input: String) {
- SaveKeyValues.putValue(Constant.DEFAULT_SERVER_CONFIG, input)
- }
- })
- .build().show()
- }
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/ui/MainActivity.kt b/app/src/main/java/com/casic/birmm/inspect/ui/MainActivity.kt
deleted file mode 100644
index 0e97af7..0000000
--- a/app/src/main/java/com/casic/birmm/inspect/ui/MainActivity.kt
+++ /dev/null
@@ -1,21 +0,0 @@
-package com.casic.birmm.inspect.ui
-
-import com.casic.birmm.inspect.R
-import com.casic.birmm.inspect.base.BaseActivity
-
-class MainActivity : BaseActivity() {
-
- override fun initLayoutView(): Int = R.layout.activity_main
-
- override fun setupTopBarLayout() {
-
- }
-
- override fun initData() {
-
- }
-
- override fun initEvent() {
-
- }
-}
diff --git a/app/src/main/java/com/casic/birmm/inspect/ui/PermissionActivity.kt b/app/src/main/java/com/casic/birmm/inspect/ui/PermissionActivity.kt
deleted file mode 100644
index 21fbba2..0000000
--- a/app/src/main/java/com/casic/birmm/inspect/ui/PermissionActivity.kt
+++ /dev/null
@@ -1,58 +0,0 @@
-package com.casic.birmm.inspect.ui
-
-import android.content.Intent
-import android.os.Build
-import android.os.Bundle
-import android.util.Log
-import androidx.appcompat.app.AppCompatActivity
-import com.casic.birmm.inspect.utils.Constant
-import pub.devrel.easypermissions.EasyPermissions
-import pub.devrel.easypermissions.EasyPermissions.PermissionCallbacks
-
-class PermissionActivity : AppCompatActivity(), PermissionCallbacks {
-
- companion object {
- private const val TAG = "PermissionActivity"
- }
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- //判断是否有权限,如果版本大于5.1才需要判断(即6.0以上),其他则不需要判断。
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
- if (EasyPermissions.hasPermissions(this, *Constant.USER_PERMISSIONS)) {
- startGuideActivity()
- } else {
- EasyPermissions.requestPermissions(
- this,
- "需要获取相关权限",
- Constant.PERMISSIONS_CODE,
- *Constant.USER_PERMISSIONS
- )
- }
- } else {
- startGuideActivity()
- }
- }
-
- private fun startGuideActivity() {
- startActivity(Intent(this, GuideActivity::class.java))
- finish()
- }
-
- override fun onRequestPermissionsResult(
- requestCode: Int,
- permissions: Array,
- grantResults: IntArray
- ) {
- super.onRequestPermissionsResult(requestCode, permissions, grantResults)
- EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this)
- }
-
- override fun onPermissionsGranted(requestCode: Int, perms: List) {
- startGuideActivity()
- }
-
- override fun onPermissionsDenied(requestCode: Int, perms: List) {
- Log.e(TAG, "onPermissionsDenied: $perms")
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/ExtensionViewModel.kt b/app/src/main/java/com/casic/birmm/inspect/utils/ExtensionViewModel.kt
new file mode 100644
index 0000000..2259965
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/utils/ExtensionViewModel.kt
@@ -0,0 +1,33 @@
+package com.casic.birmm.inspect.utils
+
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import kotlinx.coroutines.CoroutineExceptionHandler
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.launch
+
+/**
+ * ViewModel扩展方法:启动协程
+ * @param block 协程逻辑
+ * @param onError 错误回调方法
+ * @param onComplete 完成回调方法
+ */
+fun ViewModel.launch(
+ block: suspend CoroutineScope.() -> Unit,
+ onError: (e: Throwable) -> Unit = {},
+ onComplete: () -> Unit = {}
+) {
+ viewModelScope.launch(
+ CoroutineExceptionHandler { _, throwable ->
+ run {
+ onError(throwable)
+ }
+ }
+ ) {
+ try {
+ block.invoke(this)
+ } finally {
+ onComplete()
+ }
+ }
+}
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..35eb1dd
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
index 4ca4a9f..0002b4a 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -27,6 +27,12 @@
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
+
+ kotlin {
+ experimental {
+ coroutines 'enable'
+ }
+ }
}
dependencies {
@@ -47,19 +53,24 @@
implementation 'com.gyf.immersionbar:immersionbar:3.0.0'
//fragment快速实现
implementation 'com.gyf.immersionbar:immersionbar-components:3.0.0'
+ //MVVM
+ implementation "androidx.lifecycle:lifecycle-livedata:2.2.0"
+ implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0"
+ implementation "androidx.lifecycle:lifecycle-extensions:2.2.0"
+ //Kotlin协程
+ implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.0'
+ implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.0'
+ //返回值转换器
+ implementation 'com.jakewharton.retrofit:retrofit2-kotlin-coroutines-adapter:0.9.2'
+ implementation 'com.squareup.retrofit2:converter-scalars:2.0.0'
+ implementation 'com.squareup.retrofit2:converter-gson:2.8.1'
+ //okhttp3日志拦截器
+ implementation 'com.squareup.okhttp3:logging-interceptor:4.6.0'
- //MVP网络请求框架retrofit2+rxjava
- implementation 'io.reactivex:rxjava:1.3.8'
- implementation 'io.reactivex:rxandroid:1.2.1'
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.okhttp3:okhttp:4.6.0'
- implementation 'com.squareup.retrofit2:converter-gson:2.8.1'
- implementation 'com.squareup.retrofit2:adapter-rxjava:2.8.1'
- implementation 'com.squareup.okhttp3:logging-interceptor:4.6.0'
//官方Json解析库
implementation 'com.google.code.gson:gson:2.8.6'
- //Toast提示
- implementation 'com.sdsmdg.tastytoast:tastytoast:0.1.1'
//图片选择框架
implementation 'com.github.LuckSiege.PictureSelector:picture_library:v2.6.0'
//上拉加载下拉刷新
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 7096527..be35467 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -23,16 +23,16 @@
android:theme="@style/QMUI.Compat.NoActionBar"
android:usesCleartextTraffic="true"
tools:targetApi="m">
-
+
-
-
-
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/base/BaseActivity.kt b/app/src/main/java/com/casic/birmm/inspect/base/BaseActivity.kt
index aefdbb6..b6b9f53 100644
--- a/app/src/main/java/com/casic/birmm/inspect/base/BaseActivity.kt
+++ b/app/src/main/java/com/casic/birmm/inspect/base/BaseActivity.kt
@@ -4,6 +4,9 @@
import androidx.appcompat.app.AppCompatActivity
import com.qmuiteam.qmui.util.QMUIStatusBarHelper
+/**
+ * 无网络请求等普通页面的基础类
+ * */
abstract class BaseActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
diff --git a/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModel.kt b/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModel.kt
new file mode 100644
index 0000000..968b877
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModel.kt
@@ -0,0 +1,9 @@
+package com.casic.birmm.inspect.base
+
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.ViewModel
+import com.casic.birmm.inspect.utils.LoadState
+
+abstract class BaseViewModel : ViewModel() {
+ val loadState = MutableLiveData()
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModelActivity.kt b/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModelActivity.kt
new file mode 100644
index 0000000..ee93c84
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModelActivity.kt
@@ -0,0 +1,61 @@
+package com.casic.birmm.inspect.base
+
+import android.os.Bundle
+import androidx.appcompat.app.AppCompatActivity
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.ViewModelProvider
+import com.qmuiteam.qmui.util.QMUIStatusBarHelper
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.MainScope
+import kotlinx.coroutines.cancel
+
+/**
+ * MV ViewModel 架构
+ *
+ * 有网络请求等普通页面的基础类
+ */
+abstract class BaseViewModelActivity : AppCompatActivity(),
+ CoroutineScope by MainScope() {
+
+ protected lateinit var viewModel: VM
+
+ /**
+ * 初始化xml布局
+ */
+ protected abstract fun initLayoutView(): Int
+
+ /**
+ * 特定页面定制沉浸式状态栏
+ */
+ protected abstract fun setupTopBarLayout()
+
+ /**
+ * 初始化默认数据
+ */
+ abstract fun initData()
+
+ /**
+ * 初始化业务逻辑
+ */
+ abstract fun initEvent()
+
+ /**
+ * 提供ViewModel类
+ */
+ protected abstract fun createViewModelByClass(): Class?
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(initLayoutView())
+ createViewModelByClass()?.let { viewModel = ViewModelProvider(this).get(it) }
+ QMUIStatusBarHelper.translucent(this) //沉浸式状态栏
+ setupTopBarLayout()
+ initData()
+ initEvent()
+ }
+
+ override fun onDestroy() {
+ cancel()// 取消协程
+ super.onDestroy()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/model/PublicKeyBean.kt b/app/src/main/java/com/casic/birmm/inspect/model/PublicKeyBean.kt
new file mode 100644
index 0000000..25c5436
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/model/PublicKeyBean.kt
@@ -0,0 +1,18 @@
+package com.casic.birmm.inspect.model
+
+/**
+ * PublicKey 登录校验Key
+ */
+class PublicKeyBean {
+ var code = 0
+ var data: DataBean? = null
+ var message: String? = null
+ var isSuccess = false
+
+ class DataBean {
+ var isAppKaptcha = false
+ var isKaptcha = false
+ var publicKey: String? = null
+ var sid: String? = null
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/ui/GuideActivity.kt b/app/src/main/java/com/casic/birmm/inspect/ui/GuideActivity.kt
deleted file mode 100644
index ddc160a..0000000
--- a/app/src/main/java/com/casic/birmm/inspect/ui/GuideActivity.kt
+++ /dev/null
@@ -1,56 +0,0 @@
-package com.casic.birmm.inspect.ui
-
-import android.annotation.SuppressLint
-import android.content.Intent
-import android.os.CountDownTimer
-import android.view.ViewGroup.MarginLayoutParams
-import com.casic.birmm.inspect.R
-import com.casic.birmm.inspect.base.BaseActivity
-import com.qmuiteam.qmui.util.QMUIDisplayHelper
-import kotlinx.android.synthetic.main.activity_guide.*
-
-@SuppressLint("SetTextI18n")
-class GuideActivity : BaseActivity() {
-
- private lateinit var countDownTimer: CountDownTimer
-
- override fun initLayoutView(): Int = R.layout.activity_guide
-
- override fun setupTopBarLayout() {
-
- }
-
- override fun initData() {
- //根据不同设备状态栏高度设置"跳过"按钮的Margin值
- val statusBarHeight = QMUIDisplayHelper.getStatusBarHeight(this)
- val rightMargin = QMUIDisplayHelper.dp2px(this, 10)
- if (skipButton.layoutParams is MarginLayoutParams) {
- val params = skipButton.layoutParams as MarginLayoutParams
- params.setMargins(skipButton.width, statusBarHeight, rightMargin, 0)
- skipButton.requestLayout()
- }
-
- countDownTimer = object : CountDownTimer(4000, 1000) {
- override fun onFinish() {
- startLoginActivity()
- }
-
- override fun onTick(millisUntilFinished: Long) {
- skipButton.text = "跳过\u3000${(millisUntilFinished / 1000)}s"
- }
- }
- }
-
- override fun initEvent() {
- countDownTimer.start()
- skipButton.setOnClickListener {
- countDownTimer.cancel()
- startLoginActivity()
- }
- }
-
- fun startLoginActivity() {
- startActivity(Intent(this, LoginActivity::class.java))
- finish()
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/ui/LoginActivity.kt b/app/src/main/java/com/casic/birmm/inspect/ui/LoginActivity.kt
deleted file mode 100644
index 6ef4548..0000000
--- a/app/src/main/java/com/casic/birmm/inspect/ui/LoginActivity.kt
+++ /dev/null
@@ -1,81 +0,0 @@
-package com.casic.birmm.inspect.ui
-
-import android.text.Editable
-import android.text.TextWatcher
-import android.view.KeyEvent
-import android.view.inputmethod.EditorInfo
-import android.widget.EditText
-import android.widget.TextView
-import com.casic.birmm.inspect.R
-import com.casic.birmm.inspect.base.BaseActivity
-import com.casic.birmm.inspect.utils.Constant
-import com.casic.birmm.inspect.utils.SaveKeyValues
-import com.casic.birmm.inspect.widgets.InputDialog
-import kotlinx.android.synthetic.main.activity_login.*
-
-
-class LoginActivity : BaseActivity() {
-
- companion object {
- private const val Tag = "LoginActivity"
- }
-
- override fun initLayoutView(): Int = R.layout.activity_login
-
- override fun setupTopBarLayout() {
-
- }
-
- override fun initData() {
-
- }
-
- override fun initEvent() {
- loginButton.setChangeAlphaWhenPress(true)
- val editText: EditText? = inputLayout.editText
- editText?.addTextChangedListener(object : TextWatcher {
- override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
-
- }
-
- override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
-
- }
-
- override fun afterTextChanged(s: Editable) {
- if (s.toString().trim { it <= ' ' }.length > 12) {
- inputLayout.error = "密码长度超出限制"
- } else {
- inputLayout.error = null
- }
- }
- })
- //点击输入法键盘"完成"
- editText?.setOnEditorActionListener { _: TextView?, actionId: Int, _: KeyEvent? ->
- if (actionId == EditorInfo.IME_ACTION_DONE) {
-// authenticatePresenter.onReadyRetrofitRequest()
- return@setOnEditorActionListener true
- }
- false
- }
-
- //修改服务器配置
- changeServerConfigView.setOnClickListener {
- val defaultValue = SaveKeyValues.getValue(
- Constant.DEFAULT_SERVER_CONFIG,
- "http://139.198.6.177:8093/"
- ) as String
- InputDialog.Builder().setContext(this)
- .setTitle("请输入后台服务器地址")
- .setDefaultValue(defaultValue)
- .setNegativeButton("取消")
- .setPositiveButton("保存")
- .setOnDialogClickListener(object : InputDialog.OnDialogButtonClickListener {
- override fun onButtonClick(input: String) {
- SaveKeyValues.putValue(Constant.DEFAULT_SERVER_CONFIG, input)
- }
- })
- .build().show()
- }
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/ui/MainActivity.kt b/app/src/main/java/com/casic/birmm/inspect/ui/MainActivity.kt
deleted file mode 100644
index 0e97af7..0000000
--- a/app/src/main/java/com/casic/birmm/inspect/ui/MainActivity.kt
+++ /dev/null
@@ -1,21 +0,0 @@
-package com.casic.birmm.inspect.ui
-
-import com.casic.birmm.inspect.R
-import com.casic.birmm.inspect.base.BaseActivity
-
-class MainActivity : BaseActivity() {
-
- override fun initLayoutView(): Int = R.layout.activity_main
-
- override fun setupTopBarLayout() {
-
- }
-
- override fun initData() {
-
- }
-
- override fun initEvent() {
-
- }
-}
diff --git a/app/src/main/java/com/casic/birmm/inspect/ui/PermissionActivity.kt b/app/src/main/java/com/casic/birmm/inspect/ui/PermissionActivity.kt
deleted file mode 100644
index 21fbba2..0000000
--- a/app/src/main/java/com/casic/birmm/inspect/ui/PermissionActivity.kt
+++ /dev/null
@@ -1,58 +0,0 @@
-package com.casic.birmm.inspect.ui
-
-import android.content.Intent
-import android.os.Build
-import android.os.Bundle
-import android.util.Log
-import androidx.appcompat.app.AppCompatActivity
-import com.casic.birmm.inspect.utils.Constant
-import pub.devrel.easypermissions.EasyPermissions
-import pub.devrel.easypermissions.EasyPermissions.PermissionCallbacks
-
-class PermissionActivity : AppCompatActivity(), PermissionCallbacks {
-
- companion object {
- private const val TAG = "PermissionActivity"
- }
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- //判断是否有权限,如果版本大于5.1才需要判断(即6.0以上),其他则不需要判断。
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
- if (EasyPermissions.hasPermissions(this, *Constant.USER_PERMISSIONS)) {
- startGuideActivity()
- } else {
- EasyPermissions.requestPermissions(
- this,
- "需要获取相关权限",
- Constant.PERMISSIONS_CODE,
- *Constant.USER_PERMISSIONS
- )
- }
- } else {
- startGuideActivity()
- }
- }
-
- private fun startGuideActivity() {
- startActivity(Intent(this, GuideActivity::class.java))
- finish()
- }
-
- override fun onRequestPermissionsResult(
- requestCode: Int,
- permissions: Array,
- grantResults: IntArray
- ) {
- super.onRequestPermissionsResult(requestCode, permissions, grantResults)
- EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this)
- }
-
- override fun onPermissionsGranted(requestCode: Int, perms: List) {
- startGuideActivity()
- }
-
- override fun onPermissionsDenied(requestCode: Int, perms: List) {
- Log.e(TAG, "onPermissionsDenied: $perms")
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/ExtensionViewModel.kt b/app/src/main/java/com/casic/birmm/inspect/utils/ExtensionViewModel.kt
new file mode 100644
index 0000000..2259965
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/utils/ExtensionViewModel.kt
@@ -0,0 +1,33 @@
+package com.casic.birmm.inspect.utils
+
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import kotlinx.coroutines.CoroutineExceptionHandler
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.launch
+
+/**
+ * ViewModel扩展方法:启动协程
+ * @param block 协程逻辑
+ * @param onError 错误回调方法
+ * @param onComplete 完成回调方法
+ */
+fun ViewModel.launch(
+ block: suspend CoroutineScope.() -> Unit,
+ onError: (e: Throwable) -> Unit = {},
+ onComplete: () -> Unit = {}
+) {
+ viewModelScope.launch(
+ CoroutineExceptionHandler { _, throwable ->
+ run {
+ onError(throwable)
+ }
+ }
+ ) {
+ try {
+ block.invoke(this)
+ } finally {
+ onComplete()
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/LoadState.kt b/app/src/main/java/com/casic/birmm/inspect/utils/LoadState.kt
new file mode 100644
index 0000000..9c83224
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/utils/LoadState.kt
@@ -0,0 +1,22 @@
+package com.casic.birmm.inspect.utils
+
+/**
+ * 加载状态
+ * sealed 关键字表示此类仅内部继承
+ */
+sealed class LoadState(val msg: String) {
+ /**
+ * 加载中
+ */
+ class Loading(msg: String = "") : LoadState(msg)
+
+ /**
+ * 成功
+ */
+ class Success(msg: String = "") : LoadState(msg)
+
+ /**
+ * 失败
+ */
+ class Fail(msg: String = "") : LoadState(msg)
+}
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..35eb1dd
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
index 4ca4a9f..0002b4a 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -27,6 +27,12 @@
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
+
+ kotlin {
+ experimental {
+ coroutines 'enable'
+ }
+ }
}
dependencies {
@@ -47,19 +53,24 @@
implementation 'com.gyf.immersionbar:immersionbar:3.0.0'
//fragment快速实现
implementation 'com.gyf.immersionbar:immersionbar-components:3.0.0'
+ //MVVM
+ implementation "androidx.lifecycle:lifecycle-livedata:2.2.0"
+ implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0"
+ implementation "androidx.lifecycle:lifecycle-extensions:2.2.0"
+ //Kotlin协程
+ implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.0'
+ implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.0'
+ //返回值转换器
+ implementation 'com.jakewharton.retrofit:retrofit2-kotlin-coroutines-adapter:0.9.2'
+ implementation 'com.squareup.retrofit2:converter-scalars:2.0.0'
+ implementation 'com.squareup.retrofit2:converter-gson:2.8.1'
+ //okhttp3日志拦截器
+ implementation 'com.squareup.okhttp3:logging-interceptor:4.6.0'
- //MVP网络请求框架retrofit2+rxjava
- implementation 'io.reactivex:rxjava:1.3.8'
- implementation 'io.reactivex:rxandroid:1.2.1'
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.okhttp3:okhttp:4.6.0'
- implementation 'com.squareup.retrofit2:converter-gson:2.8.1'
- implementation 'com.squareup.retrofit2:adapter-rxjava:2.8.1'
- implementation 'com.squareup.okhttp3:logging-interceptor:4.6.0'
//官方Json解析库
implementation 'com.google.code.gson:gson:2.8.6'
- //Toast提示
- implementation 'com.sdsmdg.tastytoast:tastytoast:0.1.1'
//图片选择框架
implementation 'com.github.LuckSiege.PictureSelector:picture_library:v2.6.0'
//上拉加载下拉刷新
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 7096527..be35467 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -23,16 +23,16 @@
android:theme="@style/QMUI.Compat.NoActionBar"
android:usesCleartextTraffic="true"
tools:targetApi="m">
-
+
-
-
-
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/base/BaseActivity.kt b/app/src/main/java/com/casic/birmm/inspect/base/BaseActivity.kt
index aefdbb6..b6b9f53 100644
--- a/app/src/main/java/com/casic/birmm/inspect/base/BaseActivity.kt
+++ b/app/src/main/java/com/casic/birmm/inspect/base/BaseActivity.kt
@@ -4,6 +4,9 @@
import androidx.appcompat.app.AppCompatActivity
import com.qmuiteam.qmui.util.QMUIStatusBarHelper
+/**
+ * 无网络请求等普通页面的基础类
+ * */
abstract class BaseActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
diff --git a/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModel.kt b/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModel.kt
new file mode 100644
index 0000000..968b877
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModel.kt
@@ -0,0 +1,9 @@
+package com.casic.birmm.inspect.base
+
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.ViewModel
+import com.casic.birmm.inspect.utils.LoadState
+
+abstract class BaseViewModel : ViewModel() {
+ val loadState = MutableLiveData()
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModelActivity.kt b/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModelActivity.kt
new file mode 100644
index 0000000..ee93c84
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModelActivity.kt
@@ -0,0 +1,61 @@
+package com.casic.birmm.inspect.base
+
+import android.os.Bundle
+import androidx.appcompat.app.AppCompatActivity
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.ViewModelProvider
+import com.qmuiteam.qmui.util.QMUIStatusBarHelper
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.MainScope
+import kotlinx.coroutines.cancel
+
+/**
+ * MV ViewModel 架构
+ *
+ * 有网络请求等普通页面的基础类
+ */
+abstract class BaseViewModelActivity : AppCompatActivity(),
+ CoroutineScope by MainScope() {
+
+ protected lateinit var viewModel: VM
+
+ /**
+ * 初始化xml布局
+ */
+ protected abstract fun initLayoutView(): Int
+
+ /**
+ * 特定页面定制沉浸式状态栏
+ */
+ protected abstract fun setupTopBarLayout()
+
+ /**
+ * 初始化默认数据
+ */
+ abstract fun initData()
+
+ /**
+ * 初始化业务逻辑
+ */
+ abstract fun initEvent()
+
+ /**
+ * 提供ViewModel类
+ */
+ protected abstract fun createViewModelByClass(): Class?
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(initLayoutView())
+ createViewModelByClass()?.let { viewModel = ViewModelProvider(this).get(it) }
+ QMUIStatusBarHelper.translucent(this) //沉浸式状态栏
+ setupTopBarLayout()
+ initData()
+ initEvent()
+ }
+
+ override fun onDestroy() {
+ cancel()// 取消协程
+ super.onDestroy()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/model/PublicKeyBean.kt b/app/src/main/java/com/casic/birmm/inspect/model/PublicKeyBean.kt
new file mode 100644
index 0000000..25c5436
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/model/PublicKeyBean.kt
@@ -0,0 +1,18 @@
+package com.casic.birmm.inspect.model
+
+/**
+ * PublicKey 登录校验Key
+ */
+class PublicKeyBean {
+ var code = 0
+ var data: DataBean? = null
+ var message: String? = null
+ var isSuccess = false
+
+ class DataBean {
+ var isAppKaptcha = false
+ var isKaptcha = false
+ var publicKey: String? = null
+ var sid: String? = null
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/ui/GuideActivity.kt b/app/src/main/java/com/casic/birmm/inspect/ui/GuideActivity.kt
deleted file mode 100644
index ddc160a..0000000
--- a/app/src/main/java/com/casic/birmm/inspect/ui/GuideActivity.kt
+++ /dev/null
@@ -1,56 +0,0 @@
-package com.casic.birmm.inspect.ui
-
-import android.annotation.SuppressLint
-import android.content.Intent
-import android.os.CountDownTimer
-import android.view.ViewGroup.MarginLayoutParams
-import com.casic.birmm.inspect.R
-import com.casic.birmm.inspect.base.BaseActivity
-import com.qmuiteam.qmui.util.QMUIDisplayHelper
-import kotlinx.android.synthetic.main.activity_guide.*
-
-@SuppressLint("SetTextI18n")
-class GuideActivity : BaseActivity() {
-
- private lateinit var countDownTimer: CountDownTimer
-
- override fun initLayoutView(): Int = R.layout.activity_guide
-
- override fun setupTopBarLayout() {
-
- }
-
- override fun initData() {
- //根据不同设备状态栏高度设置"跳过"按钮的Margin值
- val statusBarHeight = QMUIDisplayHelper.getStatusBarHeight(this)
- val rightMargin = QMUIDisplayHelper.dp2px(this, 10)
- if (skipButton.layoutParams is MarginLayoutParams) {
- val params = skipButton.layoutParams as MarginLayoutParams
- params.setMargins(skipButton.width, statusBarHeight, rightMargin, 0)
- skipButton.requestLayout()
- }
-
- countDownTimer = object : CountDownTimer(4000, 1000) {
- override fun onFinish() {
- startLoginActivity()
- }
-
- override fun onTick(millisUntilFinished: Long) {
- skipButton.text = "跳过\u3000${(millisUntilFinished / 1000)}s"
- }
- }
- }
-
- override fun initEvent() {
- countDownTimer.start()
- skipButton.setOnClickListener {
- countDownTimer.cancel()
- startLoginActivity()
- }
- }
-
- fun startLoginActivity() {
- startActivity(Intent(this, LoginActivity::class.java))
- finish()
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/ui/LoginActivity.kt b/app/src/main/java/com/casic/birmm/inspect/ui/LoginActivity.kt
deleted file mode 100644
index 6ef4548..0000000
--- a/app/src/main/java/com/casic/birmm/inspect/ui/LoginActivity.kt
+++ /dev/null
@@ -1,81 +0,0 @@
-package com.casic.birmm.inspect.ui
-
-import android.text.Editable
-import android.text.TextWatcher
-import android.view.KeyEvent
-import android.view.inputmethod.EditorInfo
-import android.widget.EditText
-import android.widget.TextView
-import com.casic.birmm.inspect.R
-import com.casic.birmm.inspect.base.BaseActivity
-import com.casic.birmm.inspect.utils.Constant
-import com.casic.birmm.inspect.utils.SaveKeyValues
-import com.casic.birmm.inspect.widgets.InputDialog
-import kotlinx.android.synthetic.main.activity_login.*
-
-
-class LoginActivity : BaseActivity() {
-
- companion object {
- private const val Tag = "LoginActivity"
- }
-
- override fun initLayoutView(): Int = R.layout.activity_login
-
- override fun setupTopBarLayout() {
-
- }
-
- override fun initData() {
-
- }
-
- override fun initEvent() {
- loginButton.setChangeAlphaWhenPress(true)
- val editText: EditText? = inputLayout.editText
- editText?.addTextChangedListener(object : TextWatcher {
- override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
-
- }
-
- override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
-
- }
-
- override fun afterTextChanged(s: Editable) {
- if (s.toString().trim { it <= ' ' }.length > 12) {
- inputLayout.error = "密码长度超出限制"
- } else {
- inputLayout.error = null
- }
- }
- })
- //点击输入法键盘"完成"
- editText?.setOnEditorActionListener { _: TextView?, actionId: Int, _: KeyEvent? ->
- if (actionId == EditorInfo.IME_ACTION_DONE) {
-// authenticatePresenter.onReadyRetrofitRequest()
- return@setOnEditorActionListener true
- }
- false
- }
-
- //修改服务器配置
- changeServerConfigView.setOnClickListener {
- val defaultValue = SaveKeyValues.getValue(
- Constant.DEFAULT_SERVER_CONFIG,
- "http://139.198.6.177:8093/"
- ) as String
- InputDialog.Builder().setContext(this)
- .setTitle("请输入后台服务器地址")
- .setDefaultValue(defaultValue)
- .setNegativeButton("取消")
- .setPositiveButton("保存")
- .setOnDialogClickListener(object : InputDialog.OnDialogButtonClickListener {
- override fun onButtonClick(input: String) {
- SaveKeyValues.putValue(Constant.DEFAULT_SERVER_CONFIG, input)
- }
- })
- .build().show()
- }
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/ui/MainActivity.kt b/app/src/main/java/com/casic/birmm/inspect/ui/MainActivity.kt
deleted file mode 100644
index 0e97af7..0000000
--- a/app/src/main/java/com/casic/birmm/inspect/ui/MainActivity.kt
+++ /dev/null
@@ -1,21 +0,0 @@
-package com.casic.birmm.inspect.ui
-
-import com.casic.birmm.inspect.R
-import com.casic.birmm.inspect.base.BaseActivity
-
-class MainActivity : BaseActivity() {
-
- override fun initLayoutView(): Int = R.layout.activity_main
-
- override fun setupTopBarLayout() {
-
- }
-
- override fun initData() {
-
- }
-
- override fun initEvent() {
-
- }
-}
diff --git a/app/src/main/java/com/casic/birmm/inspect/ui/PermissionActivity.kt b/app/src/main/java/com/casic/birmm/inspect/ui/PermissionActivity.kt
deleted file mode 100644
index 21fbba2..0000000
--- a/app/src/main/java/com/casic/birmm/inspect/ui/PermissionActivity.kt
+++ /dev/null
@@ -1,58 +0,0 @@
-package com.casic.birmm.inspect.ui
-
-import android.content.Intent
-import android.os.Build
-import android.os.Bundle
-import android.util.Log
-import androidx.appcompat.app.AppCompatActivity
-import com.casic.birmm.inspect.utils.Constant
-import pub.devrel.easypermissions.EasyPermissions
-import pub.devrel.easypermissions.EasyPermissions.PermissionCallbacks
-
-class PermissionActivity : AppCompatActivity(), PermissionCallbacks {
-
- companion object {
- private const val TAG = "PermissionActivity"
- }
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- //判断是否有权限,如果版本大于5.1才需要判断(即6.0以上),其他则不需要判断。
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
- if (EasyPermissions.hasPermissions(this, *Constant.USER_PERMISSIONS)) {
- startGuideActivity()
- } else {
- EasyPermissions.requestPermissions(
- this,
- "需要获取相关权限",
- Constant.PERMISSIONS_CODE,
- *Constant.USER_PERMISSIONS
- )
- }
- } else {
- startGuideActivity()
- }
- }
-
- private fun startGuideActivity() {
- startActivity(Intent(this, GuideActivity::class.java))
- finish()
- }
-
- override fun onRequestPermissionsResult(
- requestCode: Int,
- permissions: Array,
- grantResults: IntArray
- ) {
- super.onRequestPermissionsResult(requestCode, permissions, grantResults)
- EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this)
- }
-
- override fun onPermissionsGranted(requestCode: Int, perms: List) {
- startGuideActivity()
- }
-
- override fun onPermissionsDenied(requestCode: Int, perms: List) {
- Log.e(TAG, "onPermissionsDenied: $perms")
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/ExtensionViewModel.kt b/app/src/main/java/com/casic/birmm/inspect/utils/ExtensionViewModel.kt
new file mode 100644
index 0000000..2259965
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/utils/ExtensionViewModel.kt
@@ -0,0 +1,33 @@
+package com.casic.birmm.inspect.utils
+
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import kotlinx.coroutines.CoroutineExceptionHandler
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.launch
+
+/**
+ * ViewModel扩展方法:启动协程
+ * @param block 协程逻辑
+ * @param onError 错误回调方法
+ * @param onComplete 完成回调方法
+ */
+fun ViewModel.launch(
+ block: suspend CoroutineScope.() -> Unit,
+ onError: (e: Throwable) -> Unit = {},
+ onComplete: () -> Unit = {}
+) {
+ viewModelScope.launch(
+ CoroutineExceptionHandler { _, throwable ->
+ run {
+ onError(throwable)
+ }
+ }
+ ) {
+ try {
+ block.invoke(this)
+ } finally {
+ onComplete()
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/LoadState.kt b/app/src/main/java/com/casic/birmm/inspect/utils/LoadState.kt
new file mode 100644
index 0000000..9c83224
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/utils/LoadState.kt
@@ -0,0 +1,22 @@
+package com.casic.birmm.inspect.utils
+
+/**
+ * 加载状态
+ * sealed 关键字表示此类仅内部继承
+ */
+sealed class LoadState(val msg: String) {
+ /**
+ * 加载中
+ */
+ class Loading(msg: String = "") : LoadState(msg)
+
+ /**
+ * 成功
+ */
+ class Success(msg: String = "") : LoadState(msg)
+
+ /**
+ * 失败
+ */
+ class Fail(msg: String = "") : LoadState(msg)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/OtherUtils.kt b/app/src/main/java/com/casic/birmm/inspect/utils/OtherUtils.kt
index 4c38241..ff63747 100644
--- a/app/src/main/java/com/casic/birmm/inspect/utils/OtherUtils.kt
+++ b/app/src/main/java/com/casic/birmm/inspect/utils/OtherUtils.kt
@@ -6,6 +6,8 @@
object OtherUtils {
+ private var loadingDialog: QMUITipDialog? = null
+
//替换Toast
fun showTipsDialog(context: Context, message: String, view: View) {
val tipDialog = QMUITipDialog.Builder(context)
@@ -16,4 +18,20 @@
tipDialog.dismiss()
}, 2000)
}
+
+ fun showLoadingDialog(context: Context?, message: String?) {
+ loadingDialog = QMUITipDialog.Builder(context)
+ .setIconType(QMUITipDialog.Builder.ICON_TYPE_LOADING)
+ .setTipWord(message)
+ .create()
+ loadingDialog!!.show()
+ }
+
+ fun dismissLoadingDialog() {
+ if (loadingDialog != null) {
+ if (loadingDialog!!.isShowing) {
+ loadingDialog!!.dismiss()
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..35eb1dd
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
index 4ca4a9f..0002b4a 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -27,6 +27,12 @@
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
+
+ kotlin {
+ experimental {
+ coroutines 'enable'
+ }
+ }
}
dependencies {
@@ -47,19 +53,24 @@
implementation 'com.gyf.immersionbar:immersionbar:3.0.0'
//fragment快速实现
implementation 'com.gyf.immersionbar:immersionbar-components:3.0.0'
+ //MVVM
+ implementation "androidx.lifecycle:lifecycle-livedata:2.2.0"
+ implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0"
+ implementation "androidx.lifecycle:lifecycle-extensions:2.2.0"
+ //Kotlin协程
+ implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.0'
+ implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.0'
+ //返回值转换器
+ implementation 'com.jakewharton.retrofit:retrofit2-kotlin-coroutines-adapter:0.9.2'
+ implementation 'com.squareup.retrofit2:converter-scalars:2.0.0'
+ implementation 'com.squareup.retrofit2:converter-gson:2.8.1'
+ //okhttp3日志拦截器
+ implementation 'com.squareup.okhttp3:logging-interceptor:4.6.0'
- //MVP网络请求框架retrofit2+rxjava
- implementation 'io.reactivex:rxjava:1.3.8'
- implementation 'io.reactivex:rxandroid:1.2.1'
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.okhttp3:okhttp:4.6.0'
- implementation 'com.squareup.retrofit2:converter-gson:2.8.1'
- implementation 'com.squareup.retrofit2:adapter-rxjava:2.8.1'
- implementation 'com.squareup.okhttp3:logging-interceptor:4.6.0'
//官方Json解析库
implementation 'com.google.code.gson:gson:2.8.6'
- //Toast提示
- implementation 'com.sdsmdg.tastytoast:tastytoast:0.1.1'
//图片选择框架
implementation 'com.github.LuckSiege.PictureSelector:picture_library:v2.6.0'
//上拉加载下拉刷新
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 7096527..be35467 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -23,16 +23,16 @@
android:theme="@style/QMUI.Compat.NoActionBar"
android:usesCleartextTraffic="true"
tools:targetApi="m">
-
+
-
-
-
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/base/BaseActivity.kt b/app/src/main/java/com/casic/birmm/inspect/base/BaseActivity.kt
index aefdbb6..b6b9f53 100644
--- a/app/src/main/java/com/casic/birmm/inspect/base/BaseActivity.kt
+++ b/app/src/main/java/com/casic/birmm/inspect/base/BaseActivity.kt
@@ -4,6 +4,9 @@
import androidx.appcompat.app.AppCompatActivity
import com.qmuiteam.qmui.util.QMUIStatusBarHelper
+/**
+ * 无网络请求等普通页面的基础类
+ * */
abstract class BaseActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
diff --git a/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModel.kt b/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModel.kt
new file mode 100644
index 0000000..968b877
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModel.kt
@@ -0,0 +1,9 @@
+package com.casic.birmm.inspect.base
+
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.ViewModel
+import com.casic.birmm.inspect.utils.LoadState
+
+abstract class BaseViewModel : ViewModel() {
+ val loadState = MutableLiveData()
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModelActivity.kt b/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModelActivity.kt
new file mode 100644
index 0000000..ee93c84
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModelActivity.kt
@@ -0,0 +1,61 @@
+package com.casic.birmm.inspect.base
+
+import android.os.Bundle
+import androidx.appcompat.app.AppCompatActivity
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.ViewModelProvider
+import com.qmuiteam.qmui.util.QMUIStatusBarHelper
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.MainScope
+import kotlinx.coroutines.cancel
+
+/**
+ * MV ViewModel 架构
+ *
+ * 有网络请求等普通页面的基础类
+ */
+abstract class BaseViewModelActivity : AppCompatActivity(),
+ CoroutineScope by MainScope() {
+
+ protected lateinit var viewModel: VM
+
+ /**
+ * 初始化xml布局
+ */
+ protected abstract fun initLayoutView(): Int
+
+ /**
+ * 特定页面定制沉浸式状态栏
+ */
+ protected abstract fun setupTopBarLayout()
+
+ /**
+ * 初始化默认数据
+ */
+ abstract fun initData()
+
+ /**
+ * 初始化业务逻辑
+ */
+ abstract fun initEvent()
+
+ /**
+ * 提供ViewModel类
+ */
+ protected abstract fun createViewModelByClass(): Class?
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(initLayoutView())
+ createViewModelByClass()?.let { viewModel = ViewModelProvider(this).get(it) }
+ QMUIStatusBarHelper.translucent(this) //沉浸式状态栏
+ setupTopBarLayout()
+ initData()
+ initEvent()
+ }
+
+ override fun onDestroy() {
+ cancel()// 取消协程
+ super.onDestroy()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/model/PublicKeyBean.kt b/app/src/main/java/com/casic/birmm/inspect/model/PublicKeyBean.kt
new file mode 100644
index 0000000..25c5436
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/model/PublicKeyBean.kt
@@ -0,0 +1,18 @@
+package com.casic.birmm.inspect.model
+
+/**
+ * PublicKey 登录校验Key
+ */
+class PublicKeyBean {
+ var code = 0
+ var data: DataBean? = null
+ var message: String? = null
+ var isSuccess = false
+
+ class DataBean {
+ var isAppKaptcha = false
+ var isKaptcha = false
+ var publicKey: String? = null
+ var sid: String? = null
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/ui/GuideActivity.kt b/app/src/main/java/com/casic/birmm/inspect/ui/GuideActivity.kt
deleted file mode 100644
index ddc160a..0000000
--- a/app/src/main/java/com/casic/birmm/inspect/ui/GuideActivity.kt
+++ /dev/null
@@ -1,56 +0,0 @@
-package com.casic.birmm.inspect.ui
-
-import android.annotation.SuppressLint
-import android.content.Intent
-import android.os.CountDownTimer
-import android.view.ViewGroup.MarginLayoutParams
-import com.casic.birmm.inspect.R
-import com.casic.birmm.inspect.base.BaseActivity
-import com.qmuiteam.qmui.util.QMUIDisplayHelper
-import kotlinx.android.synthetic.main.activity_guide.*
-
-@SuppressLint("SetTextI18n")
-class GuideActivity : BaseActivity() {
-
- private lateinit var countDownTimer: CountDownTimer
-
- override fun initLayoutView(): Int = R.layout.activity_guide
-
- override fun setupTopBarLayout() {
-
- }
-
- override fun initData() {
- //根据不同设备状态栏高度设置"跳过"按钮的Margin值
- val statusBarHeight = QMUIDisplayHelper.getStatusBarHeight(this)
- val rightMargin = QMUIDisplayHelper.dp2px(this, 10)
- if (skipButton.layoutParams is MarginLayoutParams) {
- val params = skipButton.layoutParams as MarginLayoutParams
- params.setMargins(skipButton.width, statusBarHeight, rightMargin, 0)
- skipButton.requestLayout()
- }
-
- countDownTimer = object : CountDownTimer(4000, 1000) {
- override fun onFinish() {
- startLoginActivity()
- }
-
- override fun onTick(millisUntilFinished: Long) {
- skipButton.text = "跳过\u3000${(millisUntilFinished / 1000)}s"
- }
- }
- }
-
- override fun initEvent() {
- countDownTimer.start()
- skipButton.setOnClickListener {
- countDownTimer.cancel()
- startLoginActivity()
- }
- }
-
- fun startLoginActivity() {
- startActivity(Intent(this, LoginActivity::class.java))
- finish()
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/ui/LoginActivity.kt b/app/src/main/java/com/casic/birmm/inspect/ui/LoginActivity.kt
deleted file mode 100644
index 6ef4548..0000000
--- a/app/src/main/java/com/casic/birmm/inspect/ui/LoginActivity.kt
+++ /dev/null
@@ -1,81 +0,0 @@
-package com.casic.birmm.inspect.ui
-
-import android.text.Editable
-import android.text.TextWatcher
-import android.view.KeyEvent
-import android.view.inputmethod.EditorInfo
-import android.widget.EditText
-import android.widget.TextView
-import com.casic.birmm.inspect.R
-import com.casic.birmm.inspect.base.BaseActivity
-import com.casic.birmm.inspect.utils.Constant
-import com.casic.birmm.inspect.utils.SaveKeyValues
-import com.casic.birmm.inspect.widgets.InputDialog
-import kotlinx.android.synthetic.main.activity_login.*
-
-
-class LoginActivity : BaseActivity() {
-
- companion object {
- private const val Tag = "LoginActivity"
- }
-
- override fun initLayoutView(): Int = R.layout.activity_login
-
- override fun setupTopBarLayout() {
-
- }
-
- override fun initData() {
-
- }
-
- override fun initEvent() {
- loginButton.setChangeAlphaWhenPress(true)
- val editText: EditText? = inputLayout.editText
- editText?.addTextChangedListener(object : TextWatcher {
- override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
-
- }
-
- override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
-
- }
-
- override fun afterTextChanged(s: Editable) {
- if (s.toString().trim { it <= ' ' }.length > 12) {
- inputLayout.error = "密码长度超出限制"
- } else {
- inputLayout.error = null
- }
- }
- })
- //点击输入法键盘"完成"
- editText?.setOnEditorActionListener { _: TextView?, actionId: Int, _: KeyEvent? ->
- if (actionId == EditorInfo.IME_ACTION_DONE) {
-// authenticatePresenter.onReadyRetrofitRequest()
- return@setOnEditorActionListener true
- }
- false
- }
-
- //修改服务器配置
- changeServerConfigView.setOnClickListener {
- val defaultValue = SaveKeyValues.getValue(
- Constant.DEFAULT_SERVER_CONFIG,
- "http://139.198.6.177:8093/"
- ) as String
- InputDialog.Builder().setContext(this)
- .setTitle("请输入后台服务器地址")
- .setDefaultValue(defaultValue)
- .setNegativeButton("取消")
- .setPositiveButton("保存")
- .setOnDialogClickListener(object : InputDialog.OnDialogButtonClickListener {
- override fun onButtonClick(input: String) {
- SaveKeyValues.putValue(Constant.DEFAULT_SERVER_CONFIG, input)
- }
- })
- .build().show()
- }
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/ui/MainActivity.kt b/app/src/main/java/com/casic/birmm/inspect/ui/MainActivity.kt
deleted file mode 100644
index 0e97af7..0000000
--- a/app/src/main/java/com/casic/birmm/inspect/ui/MainActivity.kt
+++ /dev/null
@@ -1,21 +0,0 @@
-package com.casic.birmm.inspect.ui
-
-import com.casic.birmm.inspect.R
-import com.casic.birmm.inspect.base.BaseActivity
-
-class MainActivity : BaseActivity() {
-
- override fun initLayoutView(): Int = R.layout.activity_main
-
- override fun setupTopBarLayout() {
-
- }
-
- override fun initData() {
-
- }
-
- override fun initEvent() {
-
- }
-}
diff --git a/app/src/main/java/com/casic/birmm/inspect/ui/PermissionActivity.kt b/app/src/main/java/com/casic/birmm/inspect/ui/PermissionActivity.kt
deleted file mode 100644
index 21fbba2..0000000
--- a/app/src/main/java/com/casic/birmm/inspect/ui/PermissionActivity.kt
+++ /dev/null
@@ -1,58 +0,0 @@
-package com.casic.birmm.inspect.ui
-
-import android.content.Intent
-import android.os.Build
-import android.os.Bundle
-import android.util.Log
-import androidx.appcompat.app.AppCompatActivity
-import com.casic.birmm.inspect.utils.Constant
-import pub.devrel.easypermissions.EasyPermissions
-import pub.devrel.easypermissions.EasyPermissions.PermissionCallbacks
-
-class PermissionActivity : AppCompatActivity(), PermissionCallbacks {
-
- companion object {
- private const val TAG = "PermissionActivity"
- }
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- //判断是否有权限,如果版本大于5.1才需要判断(即6.0以上),其他则不需要判断。
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
- if (EasyPermissions.hasPermissions(this, *Constant.USER_PERMISSIONS)) {
- startGuideActivity()
- } else {
- EasyPermissions.requestPermissions(
- this,
- "需要获取相关权限",
- Constant.PERMISSIONS_CODE,
- *Constant.USER_PERMISSIONS
- )
- }
- } else {
- startGuideActivity()
- }
- }
-
- private fun startGuideActivity() {
- startActivity(Intent(this, GuideActivity::class.java))
- finish()
- }
-
- override fun onRequestPermissionsResult(
- requestCode: Int,
- permissions: Array,
- grantResults: IntArray
- ) {
- super.onRequestPermissionsResult(requestCode, permissions, grantResults)
- EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this)
- }
-
- override fun onPermissionsGranted(requestCode: Int, perms: List) {
- startGuideActivity()
- }
-
- override fun onPermissionsDenied(requestCode: Int, perms: List) {
- Log.e(TAG, "onPermissionsDenied: $perms")
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/ExtensionViewModel.kt b/app/src/main/java/com/casic/birmm/inspect/utils/ExtensionViewModel.kt
new file mode 100644
index 0000000..2259965
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/utils/ExtensionViewModel.kt
@@ -0,0 +1,33 @@
+package com.casic.birmm.inspect.utils
+
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import kotlinx.coroutines.CoroutineExceptionHandler
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.launch
+
+/**
+ * ViewModel扩展方法:启动协程
+ * @param block 协程逻辑
+ * @param onError 错误回调方法
+ * @param onComplete 完成回调方法
+ */
+fun ViewModel.launch(
+ block: suspend CoroutineScope.() -> Unit,
+ onError: (e: Throwable) -> Unit = {},
+ onComplete: () -> Unit = {}
+) {
+ viewModelScope.launch(
+ CoroutineExceptionHandler { _, throwable ->
+ run {
+ onError(throwable)
+ }
+ }
+ ) {
+ try {
+ block.invoke(this)
+ } finally {
+ onComplete()
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/LoadState.kt b/app/src/main/java/com/casic/birmm/inspect/utils/LoadState.kt
new file mode 100644
index 0000000..9c83224
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/utils/LoadState.kt
@@ -0,0 +1,22 @@
+package com.casic.birmm.inspect.utils
+
+/**
+ * 加载状态
+ * sealed 关键字表示此类仅内部继承
+ */
+sealed class LoadState(val msg: String) {
+ /**
+ * 加载中
+ */
+ class Loading(msg: String = "") : LoadState(msg)
+
+ /**
+ * 成功
+ */
+ class Success(msg: String = "") : LoadState(msg)
+
+ /**
+ * 失败
+ */
+ class Fail(msg: String = "") : LoadState(msg)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/OtherUtils.kt b/app/src/main/java/com/casic/birmm/inspect/utils/OtherUtils.kt
index 4c38241..ff63747 100644
--- a/app/src/main/java/com/casic/birmm/inspect/utils/OtherUtils.kt
+++ b/app/src/main/java/com/casic/birmm/inspect/utils/OtherUtils.kt
@@ -6,6 +6,8 @@
object OtherUtils {
+ private var loadingDialog: QMUITipDialog? = null
+
//替换Toast
fun showTipsDialog(context: Context, message: String, view: View) {
val tipDialog = QMUITipDialog.Builder(context)
@@ -16,4 +18,20 @@
tipDialog.dismiss()
}, 2000)
}
+
+ fun showLoadingDialog(context: Context?, message: String?) {
+ loadingDialog = QMUITipDialog.Builder(context)
+ .setIconType(QMUITipDialog.Builder.ICON_TYPE_LOADING)
+ .setTipWord(message)
+ .create()
+ loadingDialog!!.show()
+ }
+
+ fun dismissLoadingDialog() {
+ if (loadingDialog != null) {
+ if (loadingDialog!!.isShowing) {
+ loadingDialog!!.dismiss()
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/RSAUtils.kt b/app/src/main/java/com/casic/birmm/inspect/utils/RSAUtils.kt
new file mode 100644
index 0000000..b93983b
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/utils/RSAUtils.kt
@@ -0,0 +1,61 @@
+package com.casic.birmm.inspect.utils
+
+import android.util.Base64
+import java.security.*
+import java.security.spec.InvalidKeySpecException
+import java.security.spec.X509EncodedKeySpec
+import javax.crypto.BadPaddingException
+import javax.crypto.Cipher
+import javax.crypto.IllegalBlockSizeException
+import javax.crypto.NoSuchPaddingException
+
+/**
+ * Created by W530 on 2019/9/26.
+ */
+object RSAUtils {
+ //构建Cipher实例时所传入的的字符串,默认为"RSA/NONE/PKCS1Padding"
+ private fun processData(srcData: ByteArray, key: Key, mode: Int): ByteArray? { //用来保存处理结果
+ var resultBytes: ByteArray? = null
+ try { //获取Cipher实例
+ val cipher = Cipher.getInstance("RSA/None/PKCS1Padding")
+ //初始化Cipher,mode指定是加密还是解密,key为公钥或私钥
+ cipher.init(mode, key)
+ //处理数据
+ resultBytes = cipher.doFinal(srcData)
+ } catch (e: NoSuchAlgorithmException) {
+ e.printStackTrace()
+ } catch (e: NoSuchPaddingException) {
+ e.printStackTrace()
+ } catch (e: InvalidKeyException) {
+ e.printStackTrace()
+ } catch (e: BadPaddingException) {
+ e.printStackTrace()
+ } catch (e: IllegalBlockSizeException) {
+ e.printStackTrace()
+ }
+ return resultBytes
+ }
+
+ fun encryptDataByPublicKey(srcData: ByteArray, publicKey: PublicKey): String {
+ val resultBytes =
+ processData(srcData, publicKey, Cipher.ENCRYPT_MODE)
+ return Base64.encodeToString(resultBytes, Base64.DEFAULT)
+ }
+
+ fun keyStrToPublicKey(publicKeyStr: String?): PublicKey? {
+ var publicKey: PublicKey? = null
+ val keyBytes =
+ Base64.decode(publicKeyStr, Base64.DEFAULT)
+ val keySpec =
+ X509EncodedKeySpec(keyBytes)
+ try {
+ val keyFactory = KeyFactory.getInstance("RSA")
+ publicKey = keyFactory.generatePublic(keySpec)
+ } catch (e: NoSuchAlgorithmException) {
+ e.printStackTrace()
+ } catch (e: InvalidKeySpecException) {
+ e.printStackTrace()
+ }
+ return publicKey
+ }
+}
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..35eb1dd
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
index 4ca4a9f..0002b4a 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -27,6 +27,12 @@
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
+
+ kotlin {
+ experimental {
+ coroutines 'enable'
+ }
+ }
}
dependencies {
@@ -47,19 +53,24 @@
implementation 'com.gyf.immersionbar:immersionbar:3.0.0'
//fragment快速实现
implementation 'com.gyf.immersionbar:immersionbar-components:3.0.0'
+ //MVVM
+ implementation "androidx.lifecycle:lifecycle-livedata:2.2.0"
+ implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0"
+ implementation "androidx.lifecycle:lifecycle-extensions:2.2.0"
+ //Kotlin协程
+ implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.0'
+ implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.0'
+ //返回值转换器
+ implementation 'com.jakewharton.retrofit:retrofit2-kotlin-coroutines-adapter:0.9.2'
+ implementation 'com.squareup.retrofit2:converter-scalars:2.0.0'
+ implementation 'com.squareup.retrofit2:converter-gson:2.8.1'
+ //okhttp3日志拦截器
+ implementation 'com.squareup.okhttp3:logging-interceptor:4.6.0'
- //MVP网络请求框架retrofit2+rxjava
- implementation 'io.reactivex:rxjava:1.3.8'
- implementation 'io.reactivex:rxandroid:1.2.1'
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.okhttp3:okhttp:4.6.0'
- implementation 'com.squareup.retrofit2:converter-gson:2.8.1'
- implementation 'com.squareup.retrofit2:adapter-rxjava:2.8.1'
- implementation 'com.squareup.okhttp3:logging-interceptor:4.6.0'
//官方Json解析库
implementation 'com.google.code.gson:gson:2.8.6'
- //Toast提示
- implementation 'com.sdsmdg.tastytoast:tastytoast:0.1.1'
//图片选择框架
implementation 'com.github.LuckSiege.PictureSelector:picture_library:v2.6.0'
//上拉加载下拉刷新
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 7096527..be35467 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -23,16 +23,16 @@
android:theme="@style/QMUI.Compat.NoActionBar"
android:usesCleartextTraffic="true"
tools:targetApi="m">
-
+
-
-
-
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/base/BaseActivity.kt b/app/src/main/java/com/casic/birmm/inspect/base/BaseActivity.kt
index aefdbb6..b6b9f53 100644
--- a/app/src/main/java/com/casic/birmm/inspect/base/BaseActivity.kt
+++ b/app/src/main/java/com/casic/birmm/inspect/base/BaseActivity.kt
@@ -4,6 +4,9 @@
import androidx.appcompat.app.AppCompatActivity
import com.qmuiteam.qmui.util.QMUIStatusBarHelper
+/**
+ * 无网络请求等普通页面的基础类
+ * */
abstract class BaseActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
diff --git a/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModel.kt b/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModel.kt
new file mode 100644
index 0000000..968b877
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModel.kt
@@ -0,0 +1,9 @@
+package com.casic.birmm.inspect.base
+
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.ViewModel
+import com.casic.birmm.inspect.utils.LoadState
+
+abstract class BaseViewModel : ViewModel() {
+ val loadState = MutableLiveData()
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModelActivity.kt b/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModelActivity.kt
new file mode 100644
index 0000000..ee93c84
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModelActivity.kt
@@ -0,0 +1,61 @@
+package com.casic.birmm.inspect.base
+
+import android.os.Bundle
+import androidx.appcompat.app.AppCompatActivity
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.ViewModelProvider
+import com.qmuiteam.qmui.util.QMUIStatusBarHelper
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.MainScope
+import kotlinx.coroutines.cancel
+
+/**
+ * MV ViewModel 架构
+ *
+ * 有网络请求等普通页面的基础类
+ */
+abstract class BaseViewModelActivity : AppCompatActivity(),
+ CoroutineScope by MainScope() {
+
+ protected lateinit var viewModel: VM
+
+ /**
+ * 初始化xml布局
+ */
+ protected abstract fun initLayoutView(): Int
+
+ /**
+ * 特定页面定制沉浸式状态栏
+ */
+ protected abstract fun setupTopBarLayout()
+
+ /**
+ * 初始化默认数据
+ */
+ abstract fun initData()
+
+ /**
+ * 初始化业务逻辑
+ */
+ abstract fun initEvent()
+
+ /**
+ * 提供ViewModel类
+ */
+ protected abstract fun createViewModelByClass(): Class?
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(initLayoutView())
+ createViewModelByClass()?.let { viewModel = ViewModelProvider(this).get(it) }
+ QMUIStatusBarHelper.translucent(this) //沉浸式状态栏
+ setupTopBarLayout()
+ initData()
+ initEvent()
+ }
+
+ override fun onDestroy() {
+ cancel()// 取消协程
+ super.onDestroy()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/model/PublicKeyBean.kt b/app/src/main/java/com/casic/birmm/inspect/model/PublicKeyBean.kt
new file mode 100644
index 0000000..25c5436
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/model/PublicKeyBean.kt
@@ -0,0 +1,18 @@
+package com.casic.birmm.inspect.model
+
+/**
+ * PublicKey 登录校验Key
+ */
+class PublicKeyBean {
+ var code = 0
+ var data: DataBean? = null
+ var message: String? = null
+ var isSuccess = false
+
+ class DataBean {
+ var isAppKaptcha = false
+ var isKaptcha = false
+ var publicKey: String? = null
+ var sid: String? = null
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/ui/GuideActivity.kt b/app/src/main/java/com/casic/birmm/inspect/ui/GuideActivity.kt
deleted file mode 100644
index ddc160a..0000000
--- a/app/src/main/java/com/casic/birmm/inspect/ui/GuideActivity.kt
+++ /dev/null
@@ -1,56 +0,0 @@
-package com.casic.birmm.inspect.ui
-
-import android.annotation.SuppressLint
-import android.content.Intent
-import android.os.CountDownTimer
-import android.view.ViewGroup.MarginLayoutParams
-import com.casic.birmm.inspect.R
-import com.casic.birmm.inspect.base.BaseActivity
-import com.qmuiteam.qmui.util.QMUIDisplayHelper
-import kotlinx.android.synthetic.main.activity_guide.*
-
-@SuppressLint("SetTextI18n")
-class GuideActivity : BaseActivity() {
-
- private lateinit var countDownTimer: CountDownTimer
-
- override fun initLayoutView(): Int = R.layout.activity_guide
-
- override fun setupTopBarLayout() {
-
- }
-
- override fun initData() {
- //根据不同设备状态栏高度设置"跳过"按钮的Margin值
- val statusBarHeight = QMUIDisplayHelper.getStatusBarHeight(this)
- val rightMargin = QMUIDisplayHelper.dp2px(this, 10)
- if (skipButton.layoutParams is MarginLayoutParams) {
- val params = skipButton.layoutParams as MarginLayoutParams
- params.setMargins(skipButton.width, statusBarHeight, rightMargin, 0)
- skipButton.requestLayout()
- }
-
- countDownTimer = object : CountDownTimer(4000, 1000) {
- override fun onFinish() {
- startLoginActivity()
- }
-
- override fun onTick(millisUntilFinished: Long) {
- skipButton.text = "跳过\u3000${(millisUntilFinished / 1000)}s"
- }
- }
- }
-
- override fun initEvent() {
- countDownTimer.start()
- skipButton.setOnClickListener {
- countDownTimer.cancel()
- startLoginActivity()
- }
- }
-
- fun startLoginActivity() {
- startActivity(Intent(this, LoginActivity::class.java))
- finish()
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/ui/LoginActivity.kt b/app/src/main/java/com/casic/birmm/inspect/ui/LoginActivity.kt
deleted file mode 100644
index 6ef4548..0000000
--- a/app/src/main/java/com/casic/birmm/inspect/ui/LoginActivity.kt
+++ /dev/null
@@ -1,81 +0,0 @@
-package com.casic.birmm.inspect.ui
-
-import android.text.Editable
-import android.text.TextWatcher
-import android.view.KeyEvent
-import android.view.inputmethod.EditorInfo
-import android.widget.EditText
-import android.widget.TextView
-import com.casic.birmm.inspect.R
-import com.casic.birmm.inspect.base.BaseActivity
-import com.casic.birmm.inspect.utils.Constant
-import com.casic.birmm.inspect.utils.SaveKeyValues
-import com.casic.birmm.inspect.widgets.InputDialog
-import kotlinx.android.synthetic.main.activity_login.*
-
-
-class LoginActivity : BaseActivity() {
-
- companion object {
- private const val Tag = "LoginActivity"
- }
-
- override fun initLayoutView(): Int = R.layout.activity_login
-
- override fun setupTopBarLayout() {
-
- }
-
- override fun initData() {
-
- }
-
- override fun initEvent() {
- loginButton.setChangeAlphaWhenPress(true)
- val editText: EditText? = inputLayout.editText
- editText?.addTextChangedListener(object : TextWatcher {
- override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
-
- }
-
- override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
-
- }
-
- override fun afterTextChanged(s: Editable) {
- if (s.toString().trim { it <= ' ' }.length > 12) {
- inputLayout.error = "密码长度超出限制"
- } else {
- inputLayout.error = null
- }
- }
- })
- //点击输入法键盘"完成"
- editText?.setOnEditorActionListener { _: TextView?, actionId: Int, _: KeyEvent? ->
- if (actionId == EditorInfo.IME_ACTION_DONE) {
-// authenticatePresenter.onReadyRetrofitRequest()
- return@setOnEditorActionListener true
- }
- false
- }
-
- //修改服务器配置
- changeServerConfigView.setOnClickListener {
- val defaultValue = SaveKeyValues.getValue(
- Constant.DEFAULT_SERVER_CONFIG,
- "http://139.198.6.177:8093/"
- ) as String
- InputDialog.Builder().setContext(this)
- .setTitle("请输入后台服务器地址")
- .setDefaultValue(defaultValue)
- .setNegativeButton("取消")
- .setPositiveButton("保存")
- .setOnDialogClickListener(object : InputDialog.OnDialogButtonClickListener {
- override fun onButtonClick(input: String) {
- SaveKeyValues.putValue(Constant.DEFAULT_SERVER_CONFIG, input)
- }
- })
- .build().show()
- }
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/ui/MainActivity.kt b/app/src/main/java/com/casic/birmm/inspect/ui/MainActivity.kt
deleted file mode 100644
index 0e97af7..0000000
--- a/app/src/main/java/com/casic/birmm/inspect/ui/MainActivity.kt
+++ /dev/null
@@ -1,21 +0,0 @@
-package com.casic.birmm.inspect.ui
-
-import com.casic.birmm.inspect.R
-import com.casic.birmm.inspect.base.BaseActivity
-
-class MainActivity : BaseActivity() {
-
- override fun initLayoutView(): Int = R.layout.activity_main
-
- override fun setupTopBarLayout() {
-
- }
-
- override fun initData() {
-
- }
-
- override fun initEvent() {
-
- }
-}
diff --git a/app/src/main/java/com/casic/birmm/inspect/ui/PermissionActivity.kt b/app/src/main/java/com/casic/birmm/inspect/ui/PermissionActivity.kt
deleted file mode 100644
index 21fbba2..0000000
--- a/app/src/main/java/com/casic/birmm/inspect/ui/PermissionActivity.kt
+++ /dev/null
@@ -1,58 +0,0 @@
-package com.casic.birmm.inspect.ui
-
-import android.content.Intent
-import android.os.Build
-import android.os.Bundle
-import android.util.Log
-import androidx.appcompat.app.AppCompatActivity
-import com.casic.birmm.inspect.utils.Constant
-import pub.devrel.easypermissions.EasyPermissions
-import pub.devrel.easypermissions.EasyPermissions.PermissionCallbacks
-
-class PermissionActivity : AppCompatActivity(), PermissionCallbacks {
-
- companion object {
- private const val TAG = "PermissionActivity"
- }
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- //判断是否有权限,如果版本大于5.1才需要判断(即6.0以上),其他则不需要判断。
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
- if (EasyPermissions.hasPermissions(this, *Constant.USER_PERMISSIONS)) {
- startGuideActivity()
- } else {
- EasyPermissions.requestPermissions(
- this,
- "需要获取相关权限",
- Constant.PERMISSIONS_CODE,
- *Constant.USER_PERMISSIONS
- )
- }
- } else {
- startGuideActivity()
- }
- }
-
- private fun startGuideActivity() {
- startActivity(Intent(this, GuideActivity::class.java))
- finish()
- }
-
- override fun onRequestPermissionsResult(
- requestCode: Int,
- permissions: Array,
- grantResults: IntArray
- ) {
- super.onRequestPermissionsResult(requestCode, permissions, grantResults)
- EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this)
- }
-
- override fun onPermissionsGranted(requestCode: Int, perms: List) {
- startGuideActivity()
- }
-
- override fun onPermissionsDenied(requestCode: Int, perms: List) {
- Log.e(TAG, "onPermissionsDenied: $perms")
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/ExtensionViewModel.kt b/app/src/main/java/com/casic/birmm/inspect/utils/ExtensionViewModel.kt
new file mode 100644
index 0000000..2259965
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/utils/ExtensionViewModel.kt
@@ -0,0 +1,33 @@
+package com.casic.birmm.inspect.utils
+
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import kotlinx.coroutines.CoroutineExceptionHandler
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.launch
+
+/**
+ * ViewModel扩展方法:启动协程
+ * @param block 协程逻辑
+ * @param onError 错误回调方法
+ * @param onComplete 完成回调方法
+ */
+fun ViewModel.launch(
+ block: suspend CoroutineScope.() -> Unit,
+ onError: (e: Throwable) -> Unit = {},
+ onComplete: () -> Unit = {}
+) {
+ viewModelScope.launch(
+ CoroutineExceptionHandler { _, throwable ->
+ run {
+ onError(throwable)
+ }
+ }
+ ) {
+ try {
+ block.invoke(this)
+ } finally {
+ onComplete()
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/LoadState.kt b/app/src/main/java/com/casic/birmm/inspect/utils/LoadState.kt
new file mode 100644
index 0000000..9c83224
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/utils/LoadState.kt
@@ -0,0 +1,22 @@
+package com.casic.birmm.inspect.utils
+
+/**
+ * 加载状态
+ * sealed 关键字表示此类仅内部继承
+ */
+sealed class LoadState(val msg: String) {
+ /**
+ * 加载中
+ */
+ class Loading(msg: String = "") : LoadState(msg)
+
+ /**
+ * 成功
+ */
+ class Success(msg: String = "") : LoadState(msg)
+
+ /**
+ * 失败
+ */
+ class Fail(msg: String = "") : LoadState(msg)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/OtherUtils.kt b/app/src/main/java/com/casic/birmm/inspect/utils/OtherUtils.kt
index 4c38241..ff63747 100644
--- a/app/src/main/java/com/casic/birmm/inspect/utils/OtherUtils.kt
+++ b/app/src/main/java/com/casic/birmm/inspect/utils/OtherUtils.kt
@@ -6,6 +6,8 @@
object OtherUtils {
+ private var loadingDialog: QMUITipDialog? = null
+
//替换Toast
fun showTipsDialog(context: Context, message: String, view: View) {
val tipDialog = QMUITipDialog.Builder(context)
@@ -16,4 +18,20 @@
tipDialog.dismiss()
}, 2000)
}
+
+ fun showLoadingDialog(context: Context?, message: String?) {
+ loadingDialog = QMUITipDialog.Builder(context)
+ .setIconType(QMUITipDialog.Builder.ICON_TYPE_LOADING)
+ .setTipWord(message)
+ .create()
+ loadingDialog!!.show()
+ }
+
+ fun dismissLoadingDialog() {
+ if (loadingDialog != null) {
+ if (loadingDialog!!.isShowing) {
+ loadingDialog!!.dismiss()
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/RSAUtils.kt b/app/src/main/java/com/casic/birmm/inspect/utils/RSAUtils.kt
new file mode 100644
index 0000000..b93983b
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/utils/RSAUtils.kt
@@ -0,0 +1,61 @@
+package com.casic.birmm.inspect.utils
+
+import android.util.Base64
+import java.security.*
+import java.security.spec.InvalidKeySpecException
+import java.security.spec.X509EncodedKeySpec
+import javax.crypto.BadPaddingException
+import javax.crypto.Cipher
+import javax.crypto.IllegalBlockSizeException
+import javax.crypto.NoSuchPaddingException
+
+/**
+ * Created by W530 on 2019/9/26.
+ */
+object RSAUtils {
+ //构建Cipher实例时所传入的的字符串,默认为"RSA/NONE/PKCS1Padding"
+ private fun processData(srcData: ByteArray, key: Key, mode: Int): ByteArray? { //用来保存处理结果
+ var resultBytes: ByteArray? = null
+ try { //获取Cipher实例
+ val cipher = Cipher.getInstance("RSA/None/PKCS1Padding")
+ //初始化Cipher,mode指定是加密还是解密,key为公钥或私钥
+ cipher.init(mode, key)
+ //处理数据
+ resultBytes = cipher.doFinal(srcData)
+ } catch (e: NoSuchAlgorithmException) {
+ e.printStackTrace()
+ } catch (e: NoSuchPaddingException) {
+ e.printStackTrace()
+ } catch (e: InvalidKeyException) {
+ e.printStackTrace()
+ } catch (e: BadPaddingException) {
+ e.printStackTrace()
+ } catch (e: IllegalBlockSizeException) {
+ e.printStackTrace()
+ }
+ return resultBytes
+ }
+
+ fun encryptDataByPublicKey(srcData: ByteArray, publicKey: PublicKey): String {
+ val resultBytes =
+ processData(srcData, publicKey, Cipher.ENCRYPT_MODE)
+ return Base64.encodeToString(resultBytes, Base64.DEFAULT)
+ }
+
+ fun keyStrToPublicKey(publicKeyStr: String?): PublicKey? {
+ var publicKey: PublicKey? = null
+ val keyBytes =
+ Base64.decode(publicKeyStr, Base64.DEFAULT)
+ val keySpec =
+ X509EncodedKeySpec(keyBytes)
+ try {
+ val keyFactory = KeyFactory.getInstance("RSA")
+ publicKey = keyFactory.generatePublic(keySpec)
+ } catch (e: NoSuchAlgorithmException) {
+ e.printStackTrace()
+ } catch (e: InvalidKeySpecException) {
+ e.printStackTrace()
+ }
+ return publicKey
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitFactory.kt b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitFactory.kt
new file mode 100644
index 0000000..0dd341f
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitFactory.kt
@@ -0,0 +1,48 @@
+package com.casic.birmm.inspect.utils.retrofit;
+
+import android.util.Log
+import com.casic.birmm.inspect.utils.Constant
+import com.casic.birmm.inspect.utils.SaveKeyValues
+import com.jakewharton.retrofit2.adapter.kotlin.coroutines.CoroutineCallAdapterFactory
+import okhttp3.OkHttpClient
+import okhttp3.logging.HttpLoggingInterceptor
+import org.jetbrains.annotations.NotNull
+import retrofit2.Retrofit
+import retrofit2.converter.gson.GsonConverterFactory
+import retrofit2.converter.scalars.ScalarsConverterFactory
+import java.util.concurrent.TimeUnit
+
+object RetrofitFactory {
+ private const val Tag = "RetrofitFactory"
+
+ private val client: OkHttpClient by lazy { createOKHttpClient() }
+
+ fun createRetrofit(clazz: Class): T {
+ val defaultValue = SaveKeyValues.getValue(
+ Constant.DEFAULT_SERVER_CONFIG,
+ "http://111.198.10.15:12204"
+ ) as String
+ return Retrofit.Builder()
+ .baseUrl(defaultValue)
+ .addConverterFactory(ScalarsConverterFactory.create()) //字符串转换器
+ .addConverterFactory(GsonConverterFactory.create()) //Gson转换器
+ .addCallAdapterFactory(CoroutineCallAdapterFactory.invoke()) //协程请求适配器
+ .client(client) //log拦截器
+ .build().create(clazz)
+ }
+
+ private fun createOKHttpClient(): OkHttpClient { //日志显示级别
+ val interceptor =
+ HttpLoggingInterceptor(object : HttpLoggingInterceptor.Logger {
+ override fun log(@NotNull message: String) {
+ Log.d(Tag, "log: $message")
+ }
+ })
+ interceptor.setLevel(HttpLoggingInterceptor.Level.BODY)
+ val builder = OkHttpClient.Builder()
+ .connectTimeout(30, TimeUnit.SECONDS)// 连接时间:30s超时
+ .readTimeout(10, TimeUnit.SECONDS)// 读取时间:10s超时
+ .writeTimeout(10, TimeUnit.SECONDS)// 写入时间:10s超时
+ return builder.addInterceptor(interceptor).build()
+ }
+}
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..35eb1dd
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
index 4ca4a9f..0002b4a 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -27,6 +27,12 @@
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
+
+ kotlin {
+ experimental {
+ coroutines 'enable'
+ }
+ }
}
dependencies {
@@ -47,19 +53,24 @@
implementation 'com.gyf.immersionbar:immersionbar:3.0.0'
//fragment快速实现
implementation 'com.gyf.immersionbar:immersionbar-components:3.0.0'
+ //MVVM
+ implementation "androidx.lifecycle:lifecycle-livedata:2.2.0"
+ implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0"
+ implementation "androidx.lifecycle:lifecycle-extensions:2.2.0"
+ //Kotlin协程
+ implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.0'
+ implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.0'
+ //返回值转换器
+ implementation 'com.jakewharton.retrofit:retrofit2-kotlin-coroutines-adapter:0.9.2'
+ implementation 'com.squareup.retrofit2:converter-scalars:2.0.0'
+ implementation 'com.squareup.retrofit2:converter-gson:2.8.1'
+ //okhttp3日志拦截器
+ implementation 'com.squareup.okhttp3:logging-interceptor:4.6.0'
- //MVP网络请求框架retrofit2+rxjava
- implementation 'io.reactivex:rxjava:1.3.8'
- implementation 'io.reactivex:rxandroid:1.2.1'
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.okhttp3:okhttp:4.6.0'
- implementation 'com.squareup.retrofit2:converter-gson:2.8.1'
- implementation 'com.squareup.retrofit2:adapter-rxjava:2.8.1'
- implementation 'com.squareup.okhttp3:logging-interceptor:4.6.0'
//官方Json解析库
implementation 'com.google.code.gson:gson:2.8.6'
- //Toast提示
- implementation 'com.sdsmdg.tastytoast:tastytoast:0.1.1'
//图片选择框架
implementation 'com.github.LuckSiege.PictureSelector:picture_library:v2.6.0'
//上拉加载下拉刷新
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 7096527..be35467 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -23,16 +23,16 @@
android:theme="@style/QMUI.Compat.NoActionBar"
android:usesCleartextTraffic="true"
tools:targetApi="m">
-
+
-
-
-
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/base/BaseActivity.kt b/app/src/main/java/com/casic/birmm/inspect/base/BaseActivity.kt
index aefdbb6..b6b9f53 100644
--- a/app/src/main/java/com/casic/birmm/inspect/base/BaseActivity.kt
+++ b/app/src/main/java/com/casic/birmm/inspect/base/BaseActivity.kt
@@ -4,6 +4,9 @@
import androidx.appcompat.app.AppCompatActivity
import com.qmuiteam.qmui.util.QMUIStatusBarHelper
+/**
+ * 无网络请求等普通页面的基础类
+ * */
abstract class BaseActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
diff --git a/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModel.kt b/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModel.kt
new file mode 100644
index 0000000..968b877
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModel.kt
@@ -0,0 +1,9 @@
+package com.casic.birmm.inspect.base
+
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.ViewModel
+import com.casic.birmm.inspect.utils.LoadState
+
+abstract class BaseViewModel : ViewModel() {
+ val loadState = MutableLiveData()
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModelActivity.kt b/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModelActivity.kt
new file mode 100644
index 0000000..ee93c84
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModelActivity.kt
@@ -0,0 +1,61 @@
+package com.casic.birmm.inspect.base
+
+import android.os.Bundle
+import androidx.appcompat.app.AppCompatActivity
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.ViewModelProvider
+import com.qmuiteam.qmui.util.QMUIStatusBarHelper
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.MainScope
+import kotlinx.coroutines.cancel
+
+/**
+ * MV ViewModel 架构
+ *
+ * 有网络请求等普通页面的基础类
+ */
+abstract class BaseViewModelActivity : AppCompatActivity(),
+ CoroutineScope by MainScope() {
+
+ protected lateinit var viewModel: VM
+
+ /**
+ * 初始化xml布局
+ */
+ protected abstract fun initLayoutView(): Int
+
+ /**
+ * 特定页面定制沉浸式状态栏
+ */
+ protected abstract fun setupTopBarLayout()
+
+ /**
+ * 初始化默认数据
+ */
+ abstract fun initData()
+
+ /**
+ * 初始化业务逻辑
+ */
+ abstract fun initEvent()
+
+ /**
+ * 提供ViewModel类
+ */
+ protected abstract fun createViewModelByClass(): Class?
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(initLayoutView())
+ createViewModelByClass()?.let { viewModel = ViewModelProvider(this).get(it) }
+ QMUIStatusBarHelper.translucent(this) //沉浸式状态栏
+ setupTopBarLayout()
+ initData()
+ initEvent()
+ }
+
+ override fun onDestroy() {
+ cancel()// 取消协程
+ super.onDestroy()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/model/PublicKeyBean.kt b/app/src/main/java/com/casic/birmm/inspect/model/PublicKeyBean.kt
new file mode 100644
index 0000000..25c5436
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/model/PublicKeyBean.kt
@@ -0,0 +1,18 @@
+package com.casic.birmm.inspect.model
+
+/**
+ * PublicKey 登录校验Key
+ */
+class PublicKeyBean {
+ var code = 0
+ var data: DataBean? = null
+ var message: String? = null
+ var isSuccess = false
+
+ class DataBean {
+ var isAppKaptcha = false
+ var isKaptcha = false
+ var publicKey: String? = null
+ var sid: String? = null
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/ui/GuideActivity.kt b/app/src/main/java/com/casic/birmm/inspect/ui/GuideActivity.kt
deleted file mode 100644
index ddc160a..0000000
--- a/app/src/main/java/com/casic/birmm/inspect/ui/GuideActivity.kt
+++ /dev/null
@@ -1,56 +0,0 @@
-package com.casic.birmm.inspect.ui
-
-import android.annotation.SuppressLint
-import android.content.Intent
-import android.os.CountDownTimer
-import android.view.ViewGroup.MarginLayoutParams
-import com.casic.birmm.inspect.R
-import com.casic.birmm.inspect.base.BaseActivity
-import com.qmuiteam.qmui.util.QMUIDisplayHelper
-import kotlinx.android.synthetic.main.activity_guide.*
-
-@SuppressLint("SetTextI18n")
-class GuideActivity : BaseActivity() {
-
- private lateinit var countDownTimer: CountDownTimer
-
- override fun initLayoutView(): Int = R.layout.activity_guide
-
- override fun setupTopBarLayout() {
-
- }
-
- override fun initData() {
- //根据不同设备状态栏高度设置"跳过"按钮的Margin值
- val statusBarHeight = QMUIDisplayHelper.getStatusBarHeight(this)
- val rightMargin = QMUIDisplayHelper.dp2px(this, 10)
- if (skipButton.layoutParams is MarginLayoutParams) {
- val params = skipButton.layoutParams as MarginLayoutParams
- params.setMargins(skipButton.width, statusBarHeight, rightMargin, 0)
- skipButton.requestLayout()
- }
-
- countDownTimer = object : CountDownTimer(4000, 1000) {
- override fun onFinish() {
- startLoginActivity()
- }
-
- override fun onTick(millisUntilFinished: Long) {
- skipButton.text = "跳过\u3000${(millisUntilFinished / 1000)}s"
- }
- }
- }
-
- override fun initEvent() {
- countDownTimer.start()
- skipButton.setOnClickListener {
- countDownTimer.cancel()
- startLoginActivity()
- }
- }
-
- fun startLoginActivity() {
- startActivity(Intent(this, LoginActivity::class.java))
- finish()
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/ui/LoginActivity.kt b/app/src/main/java/com/casic/birmm/inspect/ui/LoginActivity.kt
deleted file mode 100644
index 6ef4548..0000000
--- a/app/src/main/java/com/casic/birmm/inspect/ui/LoginActivity.kt
+++ /dev/null
@@ -1,81 +0,0 @@
-package com.casic.birmm.inspect.ui
-
-import android.text.Editable
-import android.text.TextWatcher
-import android.view.KeyEvent
-import android.view.inputmethod.EditorInfo
-import android.widget.EditText
-import android.widget.TextView
-import com.casic.birmm.inspect.R
-import com.casic.birmm.inspect.base.BaseActivity
-import com.casic.birmm.inspect.utils.Constant
-import com.casic.birmm.inspect.utils.SaveKeyValues
-import com.casic.birmm.inspect.widgets.InputDialog
-import kotlinx.android.synthetic.main.activity_login.*
-
-
-class LoginActivity : BaseActivity() {
-
- companion object {
- private const val Tag = "LoginActivity"
- }
-
- override fun initLayoutView(): Int = R.layout.activity_login
-
- override fun setupTopBarLayout() {
-
- }
-
- override fun initData() {
-
- }
-
- override fun initEvent() {
- loginButton.setChangeAlphaWhenPress(true)
- val editText: EditText? = inputLayout.editText
- editText?.addTextChangedListener(object : TextWatcher {
- override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
-
- }
-
- override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
-
- }
-
- override fun afterTextChanged(s: Editable) {
- if (s.toString().trim { it <= ' ' }.length > 12) {
- inputLayout.error = "密码长度超出限制"
- } else {
- inputLayout.error = null
- }
- }
- })
- //点击输入法键盘"完成"
- editText?.setOnEditorActionListener { _: TextView?, actionId: Int, _: KeyEvent? ->
- if (actionId == EditorInfo.IME_ACTION_DONE) {
-// authenticatePresenter.onReadyRetrofitRequest()
- return@setOnEditorActionListener true
- }
- false
- }
-
- //修改服务器配置
- changeServerConfigView.setOnClickListener {
- val defaultValue = SaveKeyValues.getValue(
- Constant.DEFAULT_SERVER_CONFIG,
- "http://139.198.6.177:8093/"
- ) as String
- InputDialog.Builder().setContext(this)
- .setTitle("请输入后台服务器地址")
- .setDefaultValue(defaultValue)
- .setNegativeButton("取消")
- .setPositiveButton("保存")
- .setOnDialogClickListener(object : InputDialog.OnDialogButtonClickListener {
- override fun onButtonClick(input: String) {
- SaveKeyValues.putValue(Constant.DEFAULT_SERVER_CONFIG, input)
- }
- })
- .build().show()
- }
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/ui/MainActivity.kt b/app/src/main/java/com/casic/birmm/inspect/ui/MainActivity.kt
deleted file mode 100644
index 0e97af7..0000000
--- a/app/src/main/java/com/casic/birmm/inspect/ui/MainActivity.kt
+++ /dev/null
@@ -1,21 +0,0 @@
-package com.casic.birmm.inspect.ui
-
-import com.casic.birmm.inspect.R
-import com.casic.birmm.inspect.base.BaseActivity
-
-class MainActivity : BaseActivity() {
-
- override fun initLayoutView(): Int = R.layout.activity_main
-
- override fun setupTopBarLayout() {
-
- }
-
- override fun initData() {
-
- }
-
- override fun initEvent() {
-
- }
-}
diff --git a/app/src/main/java/com/casic/birmm/inspect/ui/PermissionActivity.kt b/app/src/main/java/com/casic/birmm/inspect/ui/PermissionActivity.kt
deleted file mode 100644
index 21fbba2..0000000
--- a/app/src/main/java/com/casic/birmm/inspect/ui/PermissionActivity.kt
+++ /dev/null
@@ -1,58 +0,0 @@
-package com.casic.birmm.inspect.ui
-
-import android.content.Intent
-import android.os.Build
-import android.os.Bundle
-import android.util.Log
-import androidx.appcompat.app.AppCompatActivity
-import com.casic.birmm.inspect.utils.Constant
-import pub.devrel.easypermissions.EasyPermissions
-import pub.devrel.easypermissions.EasyPermissions.PermissionCallbacks
-
-class PermissionActivity : AppCompatActivity(), PermissionCallbacks {
-
- companion object {
- private const val TAG = "PermissionActivity"
- }
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- //判断是否有权限,如果版本大于5.1才需要判断(即6.0以上),其他则不需要判断。
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
- if (EasyPermissions.hasPermissions(this, *Constant.USER_PERMISSIONS)) {
- startGuideActivity()
- } else {
- EasyPermissions.requestPermissions(
- this,
- "需要获取相关权限",
- Constant.PERMISSIONS_CODE,
- *Constant.USER_PERMISSIONS
- )
- }
- } else {
- startGuideActivity()
- }
- }
-
- private fun startGuideActivity() {
- startActivity(Intent(this, GuideActivity::class.java))
- finish()
- }
-
- override fun onRequestPermissionsResult(
- requestCode: Int,
- permissions: Array,
- grantResults: IntArray
- ) {
- super.onRequestPermissionsResult(requestCode, permissions, grantResults)
- EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this)
- }
-
- override fun onPermissionsGranted(requestCode: Int, perms: List) {
- startGuideActivity()
- }
-
- override fun onPermissionsDenied(requestCode: Int, perms: List) {
- Log.e(TAG, "onPermissionsDenied: $perms")
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/ExtensionViewModel.kt b/app/src/main/java/com/casic/birmm/inspect/utils/ExtensionViewModel.kt
new file mode 100644
index 0000000..2259965
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/utils/ExtensionViewModel.kt
@@ -0,0 +1,33 @@
+package com.casic.birmm.inspect.utils
+
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import kotlinx.coroutines.CoroutineExceptionHandler
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.launch
+
+/**
+ * ViewModel扩展方法:启动协程
+ * @param block 协程逻辑
+ * @param onError 错误回调方法
+ * @param onComplete 完成回调方法
+ */
+fun ViewModel.launch(
+ block: suspend CoroutineScope.() -> Unit,
+ onError: (e: Throwable) -> Unit = {},
+ onComplete: () -> Unit = {}
+) {
+ viewModelScope.launch(
+ CoroutineExceptionHandler { _, throwable ->
+ run {
+ onError(throwable)
+ }
+ }
+ ) {
+ try {
+ block.invoke(this)
+ } finally {
+ onComplete()
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/LoadState.kt b/app/src/main/java/com/casic/birmm/inspect/utils/LoadState.kt
new file mode 100644
index 0000000..9c83224
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/utils/LoadState.kt
@@ -0,0 +1,22 @@
+package com.casic.birmm.inspect.utils
+
+/**
+ * 加载状态
+ * sealed 关键字表示此类仅内部继承
+ */
+sealed class LoadState(val msg: String) {
+ /**
+ * 加载中
+ */
+ class Loading(msg: String = "") : LoadState(msg)
+
+ /**
+ * 成功
+ */
+ class Success(msg: String = "") : LoadState(msg)
+
+ /**
+ * 失败
+ */
+ class Fail(msg: String = "") : LoadState(msg)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/OtherUtils.kt b/app/src/main/java/com/casic/birmm/inspect/utils/OtherUtils.kt
index 4c38241..ff63747 100644
--- a/app/src/main/java/com/casic/birmm/inspect/utils/OtherUtils.kt
+++ b/app/src/main/java/com/casic/birmm/inspect/utils/OtherUtils.kt
@@ -6,6 +6,8 @@
object OtherUtils {
+ private var loadingDialog: QMUITipDialog? = null
+
//替换Toast
fun showTipsDialog(context: Context, message: String, view: View) {
val tipDialog = QMUITipDialog.Builder(context)
@@ -16,4 +18,20 @@
tipDialog.dismiss()
}, 2000)
}
+
+ fun showLoadingDialog(context: Context?, message: String?) {
+ loadingDialog = QMUITipDialog.Builder(context)
+ .setIconType(QMUITipDialog.Builder.ICON_TYPE_LOADING)
+ .setTipWord(message)
+ .create()
+ loadingDialog!!.show()
+ }
+
+ fun dismissLoadingDialog() {
+ if (loadingDialog != null) {
+ if (loadingDialog!!.isShowing) {
+ loadingDialog!!.dismiss()
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/RSAUtils.kt b/app/src/main/java/com/casic/birmm/inspect/utils/RSAUtils.kt
new file mode 100644
index 0000000..b93983b
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/utils/RSAUtils.kt
@@ -0,0 +1,61 @@
+package com.casic.birmm.inspect.utils
+
+import android.util.Base64
+import java.security.*
+import java.security.spec.InvalidKeySpecException
+import java.security.spec.X509EncodedKeySpec
+import javax.crypto.BadPaddingException
+import javax.crypto.Cipher
+import javax.crypto.IllegalBlockSizeException
+import javax.crypto.NoSuchPaddingException
+
+/**
+ * Created by W530 on 2019/9/26.
+ */
+object RSAUtils {
+ //构建Cipher实例时所传入的的字符串,默认为"RSA/NONE/PKCS1Padding"
+ private fun processData(srcData: ByteArray, key: Key, mode: Int): ByteArray? { //用来保存处理结果
+ var resultBytes: ByteArray? = null
+ try { //获取Cipher实例
+ val cipher = Cipher.getInstance("RSA/None/PKCS1Padding")
+ //初始化Cipher,mode指定是加密还是解密,key为公钥或私钥
+ cipher.init(mode, key)
+ //处理数据
+ resultBytes = cipher.doFinal(srcData)
+ } catch (e: NoSuchAlgorithmException) {
+ e.printStackTrace()
+ } catch (e: NoSuchPaddingException) {
+ e.printStackTrace()
+ } catch (e: InvalidKeyException) {
+ e.printStackTrace()
+ } catch (e: BadPaddingException) {
+ e.printStackTrace()
+ } catch (e: IllegalBlockSizeException) {
+ e.printStackTrace()
+ }
+ return resultBytes
+ }
+
+ fun encryptDataByPublicKey(srcData: ByteArray, publicKey: PublicKey): String {
+ val resultBytes =
+ processData(srcData, publicKey, Cipher.ENCRYPT_MODE)
+ return Base64.encodeToString(resultBytes, Base64.DEFAULT)
+ }
+
+ fun keyStrToPublicKey(publicKeyStr: String?): PublicKey? {
+ var publicKey: PublicKey? = null
+ val keyBytes =
+ Base64.decode(publicKeyStr, Base64.DEFAULT)
+ val keySpec =
+ X509EncodedKeySpec(keyBytes)
+ try {
+ val keyFactory = KeyFactory.getInstance("RSA")
+ publicKey = keyFactory.generatePublic(keySpec)
+ } catch (e: NoSuchAlgorithmException) {
+ e.printStackTrace()
+ } catch (e: InvalidKeySpecException) {
+ e.printStackTrace()
+ }
+ return publicKey
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitFactory.kt b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitFactory.kt
new file mode 100644
index 0000000..0dd341f
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitFactory.kt
@@ -0,0 +1,48 @@
+package com.casic.birmm.inspect.utils.retrofit;
+
+import android.util.Log
+import com.casic.birmm.inspect.utils.Constant
+import com.casic.birmm.inspect.utils.SaveKeyValues
+import com.jakewharton.retrofit2.adapter.kotlin.coroutines.CoroutineCallAdapterFactory
+import okhttp3.OkHttpClient
+import okhttp3.logging.HttpLoggingInterceptor
+import org.jetbrains.annotations.NotNull
+import retrofit2.Retrofit
+import retrofit2.converter.gson.GsonConverterFactory
+import retrofit2.converter.scalars.ScalarsConverterFactory
+import java.util.concurrent.TimeUnit
+
+object RetrofitFactory {
+ private const val Tag = "RetrofitFactory"
+
+ private val client: OkHttpClient by lazy { createOKHttpClient() }
+
+ fun createRetrofit(clazz: Class): T {
+ val defaultValue = SaveKeyValues.getValue(
+ Constant.DEFAULT_SERVER_CONFIG,
+ "http://111.198.10.15:12204"
+ ) as String
+ return Retrofit.Builder()
+ .baseUrl(defaultValue)
+ .addConverterFactory(ScalarsConverterFactory.create()) //字符串转换器
+ .addConverterFactory(GsonConverterFactory.create()) //Gson转换器
+ .addCallAdapterFactory(CoroutineCallAdapterFactory.invoke()) //协程请求适配器
+ .client(client) //log拦截器
+ .build().create(clazz)
+ }
+
+ private fun createOKHttpClient(): OkHttpClient { //日志显示级别
+ val interceptor =
+ HttpLoggingInterceptor(object : HttpLoggingInterceptor.Logger {
+ override fun log(@NotNull message: String) {
+ Log.d(Tag, "log: $message")
+ }
+ })
+ interceptor.setLevel(HttpLoggingInterceptor.Level.BODY)
+ val builder = OkHttpClient.Builder()
+ .connectTimeout(30, TimeUnit.SECONDS)// 连接时间:30s超时
+ .readTimeout(10, TimeUnit.SECONDS)// 读取时间:10s超时
+ .writeTimeout(10, TimeUnit.SECONDS)// 写入时间:10s超时
+ return builder.addInterceptor(interceptor).build()
+ }
+}
diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt
new file mode 100644
index 0000000..41348ab
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt
@@ -0,0 +1,16 @@
+package com.casic.birmm.inspect.utils.retrofit
+
+import com.casic.birmm.inspect.model.PublicKeyBean
+import retrofit2.http.GET
+
+/**
+ * @JvmSuppressWildcards 用来注解类和方法,使得被标记元素的泛型参数不会被编译成通配符?
+ * */
+@JvmSuppressWildcards
+interface RetrofitService {
+ /**
+ * PublicKey校验
+ */
+ @GET("/pan-tilt/config/baseConfig")
+ suspend fun obtainPublicKeyAsync(): PublicKeyBean
+}
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..35eb1dd
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
index 4ca4a9f..0002b4a 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -27,6 +27,12 @@
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
+
+ kotlin {
+ experimental {
+ coroutines 'enable'
+ }
+ }
}
dependencies {
@@ -47,19 +53,24 @@
implementation 'com.gyf.immersionbar:immersionbar:3.0.0'
//fragment快速实现
implementation 'com.gyf.immersionbar:immersionbar-components:3.0.0'
+ //MVVM
+ implementation "androidx.lifecycle:lifecycle-livedata:2.2.0"
+ implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0"
+ implementation "androidx.lifecycle:lifecycle-extensions:2.2.0"
+ //Kotlin协程
+ implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.0'
+ implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.0'
+ //返回值转换器
+ implementation 'com.jakewharton.retrofit:retrofit2-kotlin-coroutines-adapter:0.9.2'
+ implementation 'com.squareup.retrofit2:converter-scalars:2.0.0'
+ implementation 'com.squareup.retrofit2:converter-gson:2.8.1'
+ //okhttp3日志拦截器
+ implementation 'com.squareup.okhttp3:logging-interceptor:4.6.0'
- //MVP网络请求框架retrofit2+rxjava
- implementation 'io.reactivex:rxjava:1.3.8'
- implementation 'io.reactivex:rxandroid:1.2.1'
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.okhttp3:okhttp:4.6.0'
- implementation 'com.squareup.retrofit2:converter-gson:2.8.1'
- implementation 'com.squareup.retrofit2:adapter-rxjava:2.8.1'
- implementation 'com.squareup.okhttp3:logging-interceptor:4.6.0'
//官方Json解析库
implementation 'com.google.code.gson:gson:2.8.6'
- //Toast提示
- implementation 'com.sdsmdg.tastytoast:tastytoast:0.1.1'
//图片选择框架
implementation 'com.github.LuckSiege.PictureSelector:picture_library:v2.6.0'
//上拉加载下拉刷新
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 7096527..be35467 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -23,16 +23,16 @@
android:theme="@style/QMUI.Compat.NoActionBar"
android:usesCleartextTraffic="true"
tools:targetApi="m">
-
+
-
-
-
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/base/BaseActivity.kt b/app/src/main/java/com/casic/birmm/inspect/base/BaseActivity.kt
index aefdbb6..b6b9f53 100644
--- a/app/src/main/java/com/casic/birmm/inspect/base/BaseActivity.kt
+++ b/app/src/main/java/com/casic/birmm/inspect/base/BaseActivity.kt
@@ -4,6 +4,9 @@
import androidx.appcompat.app.AppCompatActivity
import com.qmuiteam.qmui.util.QMUIStatusBarHelper
+/**
+ * 无网络请求等普通页面的基础类
+ * */
abstract class BaseActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
diff --git a/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModel.kt b/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModel.kt
new file mode 100644
index 0000000..968b877
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModel.kt
@@ -0,0 +1,9 @@
+package com.casic.birmm.inspect.base
+
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.ViewModel
+import com.casic.birmm.inspect.utils.LoadState
+
+abstract class BaseViewModel : ViewModel() {
+ val loadState = MutableLiveData()
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModelActivity.kt b/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModelActivity.kt
new file mode 100644
index 0000000..ee93c84
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModelActivity.kt
@@ -0,0 +1,61 @@
+package com.casic.birmm.inspect.base
+
+import android.os.Bundle
+import androidx.appcompat.app.AppCompatActivity
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.ViewModelProvider
+import com.qmuiteam.qmui.util.QMUIStatusBarHelper
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.MainScope
+import kotlinx.coroutines.cancel
+
+/**
+ * MV ViewModel 架构
+ *
+ * 有网络请求等普通页面的基础类
+ */
+abstract class BaseViewModelActivity : AppCompatActivity(),
+ CoroutineScope by MainScope() {
+
+ protected lateinit var viewModel: VM
+
+ /**
+ * 初始化xml布局
+ */
+ protected abstract fun initLayoutView(): Int
+
+ /**
+ * 特定页面定制沉浸式状态栏
+ */
+ protected abstract fun setupTopBarLayout()
+
+ /**
+ * 初始化默认数据
+ */
+ abstract fun initData()
+
+ /**
+ * 初始化业务逻辑
+ */
+ abstract fun initEvent()
+
+ /**
+ * 提供ViewModel类
+ */
+ protected abstract fun createViewModelByClass(): Class?
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(initLayoutView())
+ createViewModelByClass()?.let { viewModel = ViewModelProvider(this).get(it) }
+ QMUIStatusBarHelper.translucent(this) //沉浸式状态栏
+ setupTopBarLayout()
+ initData()
+ initEvent()
+ }
+
+ override fun onDestroy() {
+ cancel()// 取消协程
+ super.onDestroy()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/model/PublicKeyBean.kt b/app/src/main/java/com/casic/birmm/inspect/model/PublicKeyBean.kt
new file mode 100644
index 0000000..25c5436
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/model/PublicKeyBean.kt
@@ -0,0 +1,18 @@
+package com.casic.birmm.inspect.model
+
+/**
+ * PublicKey 登录校验Key
+ */
+class PublicKeyBean {
+ var code = 0
+ var data: DataBean? = null
+ var message: String? = null
+ var isSuccess = false
+
+ class DataBean {
+ var isAppKaptcha = false
+ var isKaptcha = false
+ var publicKey: String? = null
+ var sid: String? = null
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/ui/GuideActivity.kt b/app/src/main/java/com/casic/birmm/inspect/ui/GuideActivity.kt
deleted file mode 100644
index ddc160a..0000000
--- a/app/src/main/java/com/casic/birmm/inspect/ui/GuideActivity.kt
+++ /dev/null
@@ -1,56 +0,0 @@
-package com.casic.birmm.inspect.ui
-
-import android.annotation.SuppressLint
-import android.content.Intent
-import android.os.CountDownTimer
-import android.view.ViewGroup.MarginLayoutParams
-import com.casic.birmm.inspect.R
-import com.casic.birmm.inspect.base.BaseActivity
-import com.qmuiteam.qmui.util.QMUIDisplayHelper
-import kotlinx.android.synthetic.main.activity_guide.*
-
-@SuppressLint("SetTextI18n")
-class GuideActivity : BaseActivity() {
-
- private lateinit var countDownTimer: CountDownTimer
-
- override fun initLayoutView(): Int = R.layout.activity_guide
-
- override fun setupTopBarLayout() {
-
- }
-
- override fun initData() {
- //根据不同设备状态栏高度设置"跳过"按钮的Margin值
- val statusBarHeight = QMUIDisplayHelper.getStatusBarHeight(this)
- val rightMargin = QMUIDisplayHelper.dp2px(this, 10)
- if (skipButton.layoutParams is MarginLayoutParams) {
- val params = skipButton.layoutParams as MarginLayoutParams
- params.setMargins(skipButton.width, statusBarHeight, rightMargin, 0)
- skipButton.requestLayout()
- }
-
- countDownTimer = object : CountDownTimer(4000, 1000) {
- override fun onFinish() {
- startLoginActivity()
- }
-
- override fun onTick(millisUntilFinished: Long) {
- skipButton.text = "跳过\u3000${(millisUntilFinished / 1000)}s"
- }
- }
- }
-
- override fun initEvent() {
- countDownTimer.start()
- skipButton.setOnClickListener {
- countDownTimer.cancel()
- startLoginActivity()
- }
- }
-
- fun startLoginActivity() {
- startActivity(Intent(this, LoginActivity::class.java))
- finish()
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/ui/LoginActivity.kt b/app/src/main/java/com/casic/birmm/inspect/ui/LoginActivity.kt
deleted file mode 100644
index 6ef4548..0000000
--- a/app/src/main/java/com/casic/birmm/inspect/ui/LoginActivity.kt
+++ /dev/null
@@ -1,81 +0,0 @@
-package com.casic.birmm.inspect.ui
-
-import android.text.Editable
-import android.text.TextWatcher
-import android.view.KeyEvent
-import android.view.inputmethod.EditorInfo
-import android.widget.EditText
-import android.widget.TextView
-import com.casic.birmm.inspect.R
-import com.casic.birmm.inspect.base.BaseActivity
-import com.casic.birmm.inspect.utils.Constant
-import com.casic.birmm.inspect.utils.SaveKeyValues
-import com.casic.birmm.inspect.widgets.InputDialog
-import kotlinx.android.synthetic.main.activity_login.*
-
-
-class LoginActivity : BaseActivity() {
-
- companion object {
- private const val Tag = "LoginActivity"
- }
-
- override fun initLayoutView(): Int = R.layout.activity_login
-
- override fun setupTopBarLayout() {
-
- }
-
- override fun initData() {
-
- }
-
- override fun initEvent() {
- loginButton.setChangeAlphaWhenPress(true)
- val editText: EditText? = inputLayout.editText
- editText?.addTextChangedListener(object : TextWatcher {
- override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
-
- }
-
- override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
-
- }
-
- override fun afterTextChanged(s: Editable) {
- if (s.toString().trim { it <= ' ' }.length > 12) {
- inputLayout.error = "密码长度超出限制"
- } else {
- inputLayout.error = null
- }
- }
- })
- //点击输入法键盘"完成"
- editText?.setOnEditorActionListener { _: TextView?, actionId: Int, _: KeyEvent? ->
- if (actionId == EditorInfo.IME_ACTION_DONE) {
-// authenticatePresenter.onReadyRetrofitRequest()
- return@setOnEditorActionListener true
- }
- false
- }
-
- //修改服务器配置
- changeServerConfigView.setOnClickListener {
- val defaultValue = SaveKeyValues.getValue(
- Constant.DEFAULT_SERVER_CONFIG,
- "http://139.198.6.177:8093/"
- ) as String
- InputDialog.Builder().setContext(this)
- .setTitle("请输入后台服务器地址")
- .setDefaultValue(defaultValue)
- .setNegativeButton("取消")
- .setPositiveButton("保存")
- .setOnDialogClickListener(object : InputDialog.OnDialogButtonClickListener {
- override fun onButtonClick(input: String) {
- SaveKeyValues.putValue(Constant.DEFAULT_SERVER_CONFIG, input)
- }
- })
- .build().show()
- }
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/ui/MainActivity.kt b/app/src/main/java/com/casic/birmm/inspect/ui/MainActivity.kt
deleted file mode 100644
index 0e97af7..0000000
--- a/app/src/main/java/com/casic/birmm/inspect/ui/MainActivity.kt
+++ /dev/null
@@ -1,21 +0,0 @@
-package com.casic.birmm.inspect.ui
-
-import com.casic.birmm.inspect.R
-import com.casic.birmm.inspect.base.BaseActivity
-
-class MainActivity : BaseActivity() {
-
- override fun initLayoutView(): Int = R.layout.activity_main
-
- override fun setupTopBarLayout() {
-
- }
-
- override fun initData() {
-
- }
-
- override fun initEvent() {
-
- }
-}
diff --git a/app/src/main/java/com/casic/birmm/inspect/ui/PermissionActivity.kt b/app/src/main/java/com/casic/birmm/inspect/ui/PermissionActivity.kt
deleted file mode 100644
index 21fbba2..0000000
--- a/app/src/main/java/com/casic/birmm/inspect/ui/PermissionActivity.kt
+++ /dev/null
@@ -1,58 +0,0 @@
-package com.casic.birmm.inspect.ui
-
-import android.content.Intent
-import android.os.Build
-import android.os.Bundle
-import android.util.Log
-import androidx.appcompat.app.AppCompatActivity
-import com.casic.birmm.inspect.utils.Constant
-import pub.devrel.easypermissions.EasyPermissions
-import pub.devrel.easypermissions.EasyPermissions.PermissionCallbacks
-
-class PermissionActivity : AppCompatActivity(), PermissionCallbacks {
-
- companion object {
- private const val TAG = "PermissionActivity"
- }
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- //判断是否有权限,如果版本大于5.1才需要判断(即6.0以上),其他则不需要判断。
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
- if (EasyPermissions.hasPermissions(this, *Constant.USER_PERMISSIONS)) {
- startGuideActivity()
- } else {
- EasyPermissions.requestPermissions(
- this,
- "需要获取相关权限",
- Constant.PERMISSIONS_CODE,
- *Constant.USER_PERMISSIONS
- )
- }
- } else {
- startGuideActivity()
- }
- }
-
- private fun startGuideActivity() {
- startActivity(Intent(this, GuideActivity::class.java))
- finish()
- }
-
- override fun onRequestPermissionsResult(
- requestCode: Int,
- permissions: Array,
- grantResults: IntArray
- ) {
- super.onRequestPermissionsResult(requestCode, permissions, grantResults)
- EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this)
- }
-
- override fun onPermissionsGranted(requestCode: Int, perms: List) {
- startGuideActivity()
- }
-
- override fun onPermissionsDenied(requestCode: Int, perms: List) {
- Log.e(TAG, "onPermissionsDenied: $perms")
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/ExtensionViewModel.kt b/app/src/main/java/com/casic/birmm/inspect/utils/ExtensionViewModel.kt
new file mode 100644
index 0000000..2259965
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/utils/ExtensionViewModel.kt
@@ -0,0 +1,33 @@
+package com.casic.birmm.inspect.utils
+
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import kotlinx.coroutines.CoroutineExceptionHandler
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.launch
+
+/**
+ * ViewModel扩展方法:启动协程
+ * @param block 协程逻辑
+ * @param onError 错误回调方法
+ * @param onComplete 完成回调方法
+ */
+fun ViewModel.launch(
+ block: suspend CoroutineScope.() -> Unit,
+ onError: (e: Throwable) -> Unit = {},
+ onComplete: () -> Unit = {}
+) {
+ viewModelScope.launch(
+ CoroutineExceptionHandler { _, throwable ->
+ run {
+ onError(throwable)
+ }
+ }
+ ) {
+ try {
+ block.invoke(this)
+ } finally {
+ onComplete()
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/LoadState.kt b/app/src/main/java/com/casic/birmm/inspect/utils/LoadState.kt
new file mode 100644
index 0000000..9c83224
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/utils/LoadState.kt
@@ -0,0 +1,22 @@
+package com.casic.birmm.inspect.utils
+
+/**
+ * 加载状态
+ * sealed 关键字表示此类仅内部继承
+ */
+sealed class LoadState(val msg: String) {
+ /**
+ * 加载中
+ */
+ class Loading(msg: String = "") : LoadState(msg)
+
+ /**
+ * 成功
+ */
+ class Success(msg: String = "") : LoadState(msg)
+
+ /**
+ * 失败
+ */
+ class Fail(msg: String = "") : LoadState(msg)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/OtherUtils.kt b/app/src/main/java/com/casic/birmm/inspect/utils/OtherUtils.kt
index 4c38241..ff63747 100644
--- a/app/src/main/java/com/casic/birmm/inspect/utils/OtherUtils.kt
+++ b/app/src/main/java/com/casic/birmm/inspect/utils/OtherUtils.kt
@@ -6,6 +6,8 @@
object OtherUtils {
+ private var loadingDialog: QMUITipDialog? = null
+
//替换Toast
fun showTipsDialog(context: Context, message: String, view: View) {
val tipDialog = QMUITipDialog.Builder(context)
@@ -16,4 +18,20 @@
tipDialog.dismiss()
}, 2000)
}
+
+ fun showLoadingDialog(context: Context?, message: String?) {
+ loadingDialog = QMUITipDialog.Builder(context)
+ .setIconType(QMUITipDialog.Builder.ICON_TYPE_LOADING)
+ .setTipWord(message)
+ .create()
+ loadingDialog!!.show()
+ }
+
+ fun dismissLoadingDialog() {
+ if (loadingDialog != null) {
+ if (loadingDialog!!.isShowing) {
+ loadingDialog!!.dismiss()
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/RSAUtils.kt b/app/src/main/java/com/casic/birmm/inspect/utils/RSAUtils.kt
new file mode 100644
index 0000000..b93983b
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/utils/RSAUtils.kt
@@ -0,0 +1,61 @@
+package com.casic.birmm.inspect.utils
+
+import android.util.Base64
+import java.security.*
+import java.security.spec.InvalidKeySpecException
+import java.security.spec.X509EncodedKeySpec
+import javax.crypto.BadPaddingException
+import javax.crypto.Cipher
+import javax.crypto.IllegalBlockSizeException
+import javax.crypto.NoSuchPaddingException
+
+/**
+ * Created by W530 on 2019/9/26.
+ */
+object RSAUtils {
+ //构建Cipher实例时所传入的的字符串,默认为"RSA/NONE/PKCS1Padding"
+ private fun processData(srcData: ByteArray, key: Key, mode: Int): ByteArray? { //用来保存处理结果
+ var resultBytes: ByteArray? = null
+ try { //获取Cipher实例
+ val cipher = Cipher.getInstance("RSA/None/PKCS1Padding")
+ //初始化Cipher,mode指定是加密还是解密,key为公钥或私钥
+ cipher.init(mode, key)
+ //处理数据
+ resultBytes = cipher.doFinal(srcData)
+ } catch (e: NoSuchAlgorithmException) {
+ e.printStackTrace()
+ } catch (e: NoSuchPaddingException) {
+ e.printStackTrace()
+ } catch (e: InvalidKeyException) {
+ e.printStackTrace()
+ } catch (e: BadPaddingException) {
+ e.printStackTrace()
+ } catch (e: IllegalBlockSizeException) {
+ e.printStackTrace()
+ }
+ return resultBytes
+ }
+
+ fun encryptDataByPublicKey(srcData: ByteArray, publicKey: PublicKey): String {
+ val resultBytes =
+ processData(srcData, publicKey, Cipher.ENCRYPT_MODE)
+ return Base64.encodeToString(resultBytes, Base64.DEFAULT)
+ }
+
+ fun keyStrToPublicKey(publicKeyStr: String?): PublicKey? {
+ var publicKey: PublicKey? = null
+ val keyBytes =
+ Base64.decode(publicKeyStr, Base64.DEFAULT)
+ val keySpec =
+ X509EncodedKeySpec(keyBytes)
+ try {
+ val keyFactory = KeyFactory.getInstance("RSA")
+ publicKey = keyFactory.generatePublic(keySpec)
+ } catch (e: NoSuchAlgorithmException) {
+ e.printStackTrace()
+ } catch (e: InvalidKeySpecException) {
+ e.printStackTrace()
+ }
+ return publicKey
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitFactory.kt b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitFactory.kt
new file mode 100644
index 0000000..0dd341f
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitFactory.kt
@@ -0,0 +1,48 @@
+package com.casic.birmm.inspect.utils.retrofit;
+
+import android.util.Log
+import com.casic.birmm.inspect.utils.Constant
+import com.casic.birmm.inspect.utils.SaveKeyValues
+import com.jakewharton.retrofit2.adapter.kotlin.coroutines.CoroutineCallAdapterFactory
+import okhttp3.OkHttpClient
+import okhttp3.logging.HttpLoggingInterceptor
+import org.jetbrains.annotations.NotNull
+import retrofit2.Retrofit
+import retrofit2.converter.gson.GsonConverterFactory
+import retrofit2.converter.scalars.ScalarsConverterFactory
+import java.util.concurrent.TimeUnit
+
+object RetrofitFactory {
+ private const val Tag = "RetrofitFactory"
+
+ private val client: OkHttpClient by lazy { createOKHttpClient() }
+
+ fun createRetrofit(clazz: Class): T {
+ val defaultValue = SaveKeyValues.getValue(
+ Constant.DEFAULT_SERVER_CONFIG,
+ "http://111.198.10.15:12204"
+ ) as String
+ return Retrofit.Builder()
+ .baseUrl(defaultValue)
+ .addConverterFactory(ScalarsConverterFactory.create()) //字符串转换器
+ .addConverterFactory(GsonConverterFactory.create()) //Gson转换器
+ .addCallAdapterFactory(CoroutineCallAdapterFactory.invoke()) //协程请求适配器
+ .client(client) //log拦截器
+ .build().create(clazz)
+ }
+
+ private fun createOKHttpClient(): OkHttpClient { //日志显示级别
+ val interceptor =
+ HttpLoggingInterceptor(object : HttpLoggingInterceptor.Logger {
+ override fun log(@NotNull message: String) {
+ Log.d(Tag, "log: $message")
+ }
+ })
+ interceptor.setLevel(HttpLoggingInterceptor.Level.BODY)
+ val builder = OkHttpClient.Builder()
+ .connectTimeout(30, TimeUnit.SECONDS)// 连接时间:30s超时
+ .readTimeout(10, TimeUnit.SECONDS)// 读取时间:10s超时
+ .writeTimeout(10, TimeUnit.SECONDS)// 写入时间:10s超时
+ return builder.addInterceptor(interceptor).build()
+ }
+}
diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt
new file mode 100644
index 0000000..41348ab
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt
@@ -0,0 +1,16 @@
+package com.casic.birmm.inspect.utils.retrofit
+
+import com.casic.birmm.inspect.model.PublicKeyBean
+import retrofit2.http.GET
+
+/**
+ * @JvmSuppressWildcards 用来注解类和方法,使得被标记元素的泛型参数不会被编译成通配符?
+ * */
+@JvmSuppressWildcards
+interface RetrofitService {
+ /**
+ * PublicKey校验
+ */
+ @GET("/pan-tilt/config/baseConfig")
+ suspend fun obtainPublicKeyAsync(): PublicKeyBean
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitServiceManager.kt
new file mode 100644
index 0000000..fe9869b
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitServiceManager.kt
@@ -0,0 +1,16 @@
+package com.casic.birmm.inspect.utils.retrofit
+
+import com.casic.birmm.inspect.model.PublicKeyBean
+
+
+object RetrofitServiceManager {
+
+ private val api by lazy { RetrofitFactory.createRetrofit(RetrofitService::class.java) }
+
+ /**
+ * 验证PublicKey
+ */
+ suspend fun authenticate(): PublicKeyBean {
+ return api.obtainPublicKeyAsync()
+ }
+}
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..35eb1dd
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
index 4ca4a9f..0002b4a 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -27,6 +27,12 @@
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
+
+ kotlin {
+ experimental {
+ coroutines 'enable'
+ }
+ }
}
dependencies {
@@ -47,19 +53,24 @@
implementation 'com.gyf.immersionbar:immersionbar:3.0.0'
//fragment快速实现
implementation 'com.gyf.immersionbar:immersionbar-components:3.0.0'
+ //MVVM
+ implementation "androidx.lifecycle:lifecycle-livedata:2.2.0"
+ implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0"
+ implementation "androidx.lifecycle:lifecycle-extensions:2.2.0"
+ //Kotlin协程
+ implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.0'
+ implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.0'
+ //返回值转换器
+ implementation 'com.jakewharton.retrofit:retrofit2-kotlin-coroutines-adapter:0.9.2'
+ implementation 'com.squareup.retrofit2:converter-scalars:2.0.0'
+ implementation 'com.squareup.retrofit2:converter-gson:2.8.1'
+ //okhttp3日志拦截器
+ implementation 'com.squareup.okhttp3:logging-interceptor:4.6.0'
- //MVP网络请求框架retrofit2+rxjava
- implementation 'io.reactivex:rxjava:1.3.8'
- implementation 'io.reactivex:rxandroid:1.2.1'
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.okhttp3:okhttp:4.6.0'
- implementation 'com.squareup.retrofit2:converter-gson:2.8.1'
- implementation 'com.squareup.retrofit2:adapter-rxjava:2.8.1'
- implementation 'com.squareup.okhttp3:logging-interceptor:4.6.0'
//官方Json解析库
implementation 'com.google.code.gson:gson:2.8.6'
- //Toast提示
- implementation 'com.sdsmdg.tastytoast:tastytoast:0.1.1'
//图片选择框架
implementation 'com.github.LuckSiege.PictureSelector:picture_library:v2.6.0'
//上拉加载下拉刷新
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 7096527..be35467 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -23,16 +23,16 @@
android:theme="@style/QMUI.Compat.NoActionBar"
android:usesCleartextTraffic="true"
tools:targetApi="m">
-
+
-
-
-
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/base/BaseActivity.kt b/app/src/main/java/com/casic/birmm/inspect/base/BaseActivity.kt
index aefdbb6..b6b9f53 100644
--- a/app/src/main/java/com/casic/birmm/inspect/base/BaseActivity.kt
+++ b/app/src/main/java/com/casic/birmm/inspect/base/BaseActivity.kt
@@ -4,6 +4,9 @@
import androidx.appcompat.app.AppCompatActivity
import com.qmuiteam.qmui.util.QMUIStatusBarHelper
+/**
+ * 无网络请求等普通页面的基础类
+ * */
abstract class BaseActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
diff --git a/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModel.kt b/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModel.kt
new file mode 100644
index 0000000..968b877
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModel.kt
@@ -0,0 +1,9 @@
+package com.casic.birmm.inspect.base
+
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.ViewModel
+import com.casic.birmm.inspect.utils.LoadState
+
+abstract class BaseViewModel : ViewModel() {
+ val loadState = MutableLiveData()
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModelActivity.kt b/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModelActivity.kt
new file mode 100644
index 0000000..ee93c84
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModelActivity.kt
@@ -0,0 +1,61 @@
+package com.casic.birmm.inspect.base
+
+import android.os.Bundle
+import androidx.appcompat.app.AppCompatActivity
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.ViewModelProvider
+import com.qmuiteam.qmui.util.QMUIStatusBarHelper
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.MainScope
+import kotlinx.coroutines.cancel
+
+/**
+ * MV ViewModel 架构
+ *
+ * 有网络请求等普通页面的基础类
+ */
+abstract class BaseViewModelActivity : AppCompatActivity(),
+ CoroutineScope by MainScope() {
+
+ protected lateinit var viewModel: VM
+
+ /**
+ * 初始化xml布局
+ */
+ protected abstract fun initLayoutView(): Int
+
+ /**
+ * 特定页面定制沉浸式状态栏
+ */
+ protected abstract fun setupTopBarLayout()
+
+ /**
+ * 初始化默认数据
+ */
+ abstract fun initData()
+
+ /**
+ * 初始化业务逻辑
+ */
+ abstract fun initEvent()
+
+ /**
+ * 提供ViewModel类
+ */
+ protected abstract fun createViewModelByClass(): Class?
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(initLayoutView())
+ createViewModelByClass()?.let { viewModel = ViewModelProvider(this).get(it) }
+ QMUIStatusBarHelper.translucent(this) //沉浸式状态栏
+ setupTopBarLayout()
+ initData()
+ initEvent()
+ }
+
+ override fun onDestroy() {
+ cancel()// 取消协程
+ super.onDestroy()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/model/PublicKeyBean.kt b/app/src/main/java/com/casic/birmm/inspect/model/PublicKeyBean.kt
new file mode 100644
index 0000000..25c5436
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/model/PublicKeyBean.kt
@@ -0,0 +1,18 @@
+package com.casic.birmm.inspect.model
+
+/**
+ * PublicKey 登录校验Key
+ */
+class PublicKeyBean {
+ var code = 0
+ var data: DataBean? = null
+ var message: String? = null
+ var isSuccess = false
+
+ class DataBean {
+ var isAppKaptcha = false
+ var isKaptcha = false
+ var publicKey: String? = null
+ var sid: String? = null
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/ui/GuideActivity.kt b/app/src/main/java/com/casic/birmm/inspect/ui/GuideActivity.kt
deleted file mode 100644
index ddc160a..0000000
--- a/app/src/main/java/com/casic/birmm/inspect/ui/GuideActivity.kt
+++ /dev/null
@@ -1,56 +0,0 @@
-package com.casic.birmm.inspect.ui
-
-import android.annotation.SuppressLint
-import android.content.Intent
-import android.os.CountDownTimer
-import android.view.ViewGroup.MarginLayoutParams
-import com.casic.birmm.inspect.R
-import com.casic.birmm.inspect.base.BaseActivity
-import com.qmuiteam.qmui.util.QMUIDisplayHelper
-import kotlinx.android.synthetic.main.activity_guide.*
-
-@SuppressLint("SetTextI18n")
-class GuideActivity : BaseActivity() {
-
- private lateinit var countDownTimer: CountDownTimer
-
- override fun initLayoutView(): Int = R.layout.activity_guide
-
- override fun setupTopBarLayout() {
-
- }
-
- override fun initData() {
- //根据不同设备状态栏高度设置"跳过"按钮的Margin值
- val statusBarHeight = QMUIDisplayHelper.getStatusBarHeight(this)
- val rightMargin = QMUIDisplayHelper.dp2px(this, 10)
- if (skipButton.layoutParams is MarginLayoutParams) {
- val params = skipButton.layoutParams as MarginLayoutParams
- params.setMargins(skipButton.width, statusBarHeight, rightMargin, 0)
- skipButton.requestLayout()
- }
-
- countDownTimer = object : CountDownTimer(4000, 1000) {
- override fun onFinish() {
- startLoginActivity()
- }
-
- override fun onTick(millisUntilFinished: Long) {
- skipButton.text = "跳过\u3000${(millisUntilFinished / 1000)}s"
- }
- }
- }
-
- override fun initEvent() {
- countDownTimer.start()
- skipButton.setOnClickListener {
- countDownTimer.cancel()
- startLoginActivity()
- }
- }
-
- fun startLoginActivity() {
- startActivity(Intent(this, LoginActivity::class.java))
- finish()
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/ui/LoginActivity.kt b/app/src/main/java/com/casic/birmm/inspect/ui/LoginActivity.kt
deleted file mode 100644
index 6ef4548..0000000
--- a/app/src/main/java/com/casic/birmm/inspect/ui/LoginActivity.kt
+++ /dev/null
@@ -1,81 +0,0 @@
-package com.casic.birmm.inspect.ui
-
-import android.text.Editable
-import android.text.TextWatcher
-import android.view.KeyEvent
-import android.view.inputmethod.EditorInfo
-import android.widget.EditText
-import android.widget.TextView
-import com.casic.birmm.inspect.R
-import com.casic.birmm.inspect.base.BaseActivity
-import com.casic.birmm.inspect.utils.Constant
-import com.casic.birmm.inspect.utils.SaveKeyValues
-import com.casic.birmm.inspect.widgets.InputDialog
-import kotlinx.android.synthetic.main.activity_login.*
-
-
-class LoginActivity : BaseActivity() {
-
- companion object {
- private const val Tag = "LoginActivity"
- }
-
- override fun initLayoutView(): Int = R.layout.activity_login
-
- override fun setupTopBarLayout() {
-
- }
-
- override fun initData() {
-
- }
-
- override fun initEvent() {
- loginButton.setChangeAlphaWhenPress(true)
- val editText: EditText? = inputLayout.editText
- editText?.addTextChangedListener(object : TextWatcher {
- override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
-
- }
-
- override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
-
- }
-
- override fun afterTextChanged(s: Editable) {
- if (s.toString().trim { it <= ' ' }.length > 12) {
- inputLayout.error = "密码长度超出限制"
- } else {
- inputLayout.error = null
- }
- }
- })
- //点击输入法键盘"完成"
- editText?.setOnEditorActionListener { _: TextView?, actionId: Int, _: KeyEvent? ->
- if (actionId == EditorInfo.IME_ACTION_DONE) {
-// authenticatePresenter.onReadyRetrofitRequest()
- return@setOnEditorActionListener true
- }
- false
- }
-
- //修改服务器配置
- changeServerConfigView.setOnClickListener {
- val defaultValue = SaveKeyValues.getValue(
- Constant.DEFAULT_SERVER_CONFIG,
- "http://139.198.6.177:8093/"
- ) as String
- InputDialog.Builder().setContext(this)
- .setTitle("请输入后台服务器地址")
- .setDefaultValue(defaultValue)
- .setNegativeButton("取消")
- .setPositiveButton("保存")
- .setOnDialogClickListener(object : InputDialog.OnDialogButtonClickListener {
- override fun onButtonClick(input: String) {
- SaveKeyValues.putValue(Constant.DEFAULT_SERVER_CONFIG, input)
- }
- })
- .build().show()
- }
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/ui/MainActivity.kt b/app/src/main/java/com/casic/birmm/inspect/ui/MainActivity.kt
deleted file mode 100644
index 0e97af7..0000000
--- a/app/src/main/java/com/casic/birmm/inspect/ui/MainActivity.kt
+++ /dev/null
@@ -1,21 +0,0 @@
-package com.casic.birmm.inspect.ui
-
-import com.casic.birmm.inspect.R
-import com.casic.birmm.inspect.base.BaseActivity
-
-class MainActivity : BaseActivity() {
-
- override fun initLayoutView(): Int = R.layout.activity_main
-
- override fun setupTopBarLayout() {
-
- }
-
- override fun initData() {
-
- }
-
- override fun initEvent() {
-
- }
-}
diff --git a/app/src/main/java/com/casic/birmm/inspect/ui/PermissionActivity.kt b/app/src/main/java/com/casic/birmm/inspect/ui/PermissionActivity.kt
deleted file mode 100644
index 21fbba2..0000000
--- a/app/src/main/java/com/casic/birmm/inspect/ui/PermissionActivity.kt
+++ /dev/null
@@ -1,58 +0,0 @@
-package com.casic.birmm.inspect.ui
-
-import android.content.Intent
-import android.os.Build
-import android.os.Bundle
-import android.util.Log
-import androidx.appcompat.app.AppCompatActivity
-import com.casic.birmm.inspect.utils.Constant
-import pub.devrel.easypermissions.EasyPermissions
-import pub.devrel.easypermissions.EasyPermissions.PermissionCallbacks
-
-class PermissionActivity : AppCompatActivity(), PermissionCallbacks {
-
- companion object {
- private const val TAG = "PermissionActivity"
- }
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- //判断是否有权限,如果版本大于5.1才需要判断(即6.0以上),其他则不需要判断。
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
- if (EasyPermissions.hasPermissions(this, *Constant.USER_PERMISSIONS)) {
- startGuideActivity()
- } else {
- EasyPermissions.requestPermissions(
- this,
- "需要获取相关权限",
- Constant.PERMISSIONS_CODE,
- *Constant.USER_PERMISSIONS
- )
- }
- } else {
- startGuideActivity()
- }
- }
-
- private fun startGuideActivity() {
- startActivity(Intent(this, GuideActivity::class.java))
- finish()
- }
-
- override fun onRequestPermissionsResult(
- requestCode: Int,
- permissions: Array,
- grantResults: IntArray
- ) {
- super.onRequestPermissionsResult(requestCode, permissions, grantResults)
- EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this)
- }
-
- override fun onPermissionsGranted(requestCode: Int, perms: List) {
- startGuideActivity()
- }
-
- override fun onPermissionsDenied(requestCode: Int, perms: List) {
- Log.e(TAG, "onPermissionsDenied: $perms")
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/ExtensionViewModel.kt b/app/src/main/java/com/casic/birmm/inspect/utils/ExtensionViewModel.kt
new file mode 100644
index 0000000..2259965
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/utils/ExtensionViewModel.kt
@@ -0,0 +1,33 @@
+package com.casic.birmm.inspect.utils
+
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import kotlinx.coroutines.CoroutineExceptionHandler
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.launch
+
+/**
+ * ViewModel扩展方法:启动协程
+ * @param block 协程逻辑
+ * @param onError 错误回调方法
+ * @param onComplete 完成回调方法
+ */
+fun ViewModel.launch(
+ block: suspend CoroutineScope.() -> Unit,
+ onError: (e: Throwable) -> Unit = {},
+ onComplete: () -> Unit = {}
+) {
+ viewModelScope.launch(
+ CoroutineExceptionHandler { _, throwable ->
+ run {
+ onError(throwable)
+ }
+ }
+ ) {
+ try {
+ block.invoke(this)
+ } finally {
+ onComplete()
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/LoadState.kt b/app/src/main/java/com/casic/birmm/inspect/utils/LoadState.kt
new file mode 100644
index 0000000..9c83224
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/utils/LoadState.kt
@@ -0,0 +1,22 @@
+package com.casic.birmm.inspect.utils
+
+/**
+ * 加载状态
+ * sealed 关键字表示此类仅内部继承
+ */
+sealed class LoadState(val msg: String) {
+ /**
+ * 加载中
+ */
+ class Loading(msg: String = "") : LoadState(msg)
+
+ /**
+ * 成功
+ */
+ class Success(msg: String = "") : LoadState(msg)
+
+ /**
+ * 失败
+ */
+ class Fail(msg: String = "") : LoadState(msg)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/OtherUtils.kt b/app/src/main/java/com/casic/birmm/inspect/utils/OtherUtils.kt
index 4c38241..ff63747 100644
--- a/app/src/main/java/com/casic/birmm/inspect/utils/OtherUtils.kt
+++ b/app/src/main/java/com/casic/birmm/inspect/utils/OtherUtils.kt
@@ -6,6 +6,8 @@
object OtherUtils {
+ private var loadingDialog: QMUITipDialog? = null
+
//替换Toast
fun showTipsDialog(context: Context, message: String, view: View) {
val tipDialog = QMUITipDialog.Builder(context)
@@ -16,4 +18,20 @@
tipDialog.dismiss()
}, 2000)
}
+
+ fun showLoadingDialog(context: Context?, message: String?) {
+ loadingDialog = QMUITipDialog.Builder(context)
+ .setIconType(QMUITipDialog.Builder.ICON_TYPE_LOADING)
+ .setTipWord(message)
+ .create()
+ loadingDialog!!.show()
+ }
+
+ fun dismissLoadingDialog() {
+ if (loadingDialog != null) {
+ if (loadingDialog!!.isShowing) {
+ loadingDialog!!.dismiss()
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/RSAUtils.kt b/app/src/main/java/com/casic/birmm/inspect/utils/RSAUtils.kt
new file mode 100644
index 0000000..b93983b
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/utils/RSAUtils.kt
@@ -0,0 +1,61 @@
+package com.casic.birmm.inspect.utils
+
+import android.util.Base64
+import java.security.*
+import java.security.spec.InvalidKeySpecException
+import java.security.spec.X509EncodedKeySpec
+import javax.crypto.BadPaddingException
+import javax.crypto.Cipher
+import javax.crypto.IllegalBlockSizeException
+import javax.crypto.NoSuchPaddingException
+
+/**
+ * Created by W530 on 2019/9/26.
+ */
+object RSAUtils {
+ //构建Cipher实例时所传入的的字符串,默认为"RSA/NONE/PKCS1Padding"
+ private fun processData(srcData: ByteArray, key: Key, mode: Int): ByteArray? { //用来保存处理结果
+ var resultBytes: ByteArray? = null
+ try { //获取Cipher实例
+ val cipher = Cipher.getInstance("RSA/None/PKCS1Padding")
+ //初始化Cipher,mode指定是加密还是解密,key为公钥或私钥
+ cipher.init(mode, key)
+ //处理数据
+ resultBytes = cipher.doFinal(srcData)
+ } catch (e: NoSuchAlgorithmException) {
+ e.printStackTrace()
+ } catch (e: NoSuchPaddingException) {
+ e.printStackTrace()
+ } catch (e: InvalidKeyException) {
+ e.printStackTrace()
+ } catch (e: BadPaddingException) {
+ e.printStackTrace()
+ } catch (e: IllegalBlockSizeException) {
+ e.printStackTrace()
+ }
+ return resultBytes
+ }
+
+ fun encryptDataByPublicKey(srcData: ByteArray, publicKey: PublicKey): String {
+ val resultBytes =
+ processData(srcData, publicKey, Cipher.ENCRYPT_MODE)
+ return Base64.encodeToString(resultBytes, Base64.DEFAULT)
+ }
+
+ fun keyStrToPublicKey(publicKeyStr: String?): PublicKey? {
+ var publicKey: PublicKey? = null
+ val keyBytes =
+ Base64.decode(publicKeyStr, Base64.DEFAULT)
+ val keySpec =
+ X509EncodedKeySpec(keyBytes)
+ try {
+ val keyFactory = KeyFactory.getInstance("RSA")
+ publicKey = keyFactory.generatePublic(keySpec)
+ } catch (e: NoSuchAlgorithmException) {
+ e.printStackTrace()
+ } catch (e: InvalidKeySpecException) {
+ e.printStackTrace()
+ }
+ return publicKey
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitFactory.kt b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitFactory.kt
new file mode 100644
index 0000000..0dd341f
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitFactory.kt
@@ -0,0 +1,48 @@
+package com.casic.birmm.inspect.utils.retrofit;
+
+import android.util.Log
+import com.casic.birmm.inspect.utils.Constant
+import com.casic.birmm.inspect.utils.SaveKeyValues
+import com.jakewharton.retrofit2.adapter.kotlin.coroutines.CoroutineCallAdapterFactory
+import okhttp3.OkHttpClient
+import okhttp3.logging.HttpLoggingInterceptor
+import org.jetbrains.annotations.NotNull
+import retrofit2.Retrofit
+import retrofit2.converter.gson.GsonConverterFactory
+import retrofit2.converter.scalars.ScalarsConverterFactory
+import java.util.concurrent.TimeUnit
+
+object RetrofitFactory {
+ private const val Tag = "RetrofitFactory"
+
+ private val client: OkHttpClient by lazy { createOKHttpClient() }
+
+ fun createRetrofit(clazz: Class): T {
+ val defaultValue = SaveKeyValues.getValue(
+ Constant.DEFAULT_SERVER_CONFIG,
+ "http://111.198.10.15:12204"
+ ) as String
+ return Retrofit.Builder()
+ .baseUrl(defaultValue)
+ .addConverterFactory(ScalarsConverterFactory.create()) //字符串转换器
+ .addConverterFactory(GsonConverterFactory.create()) //Gson转换器
+ .addCallAdapterFactory(CoroutineCallAdapterFactory.invoke()) //协程请求适配器
+ .client(client) //log拦截器
+ .build().create(clazz)
+ }
+
+ private fun createOKHttpClient(): OkHttpClient { //日志显示级别
+ val interceptor =
+ HttpLoggingInterceptor(object : HttpLoggingInterceptor.Logger {
+ override fun log(@NotNull message: String) {
+ Log.d(Tag, "log: $message")
+ }
+ })
+ interceptor.setLevel(HttpLoggingInterceptor.Level.BODY)
+ val builder = OkHttpClient.Builder()
+ .connectTimeout(30, TimeUnit.SECONDS)// 连接时间:30s超时
+ .readTimeout(10, TimeUnit.SECONDS)// 读取时间:10s超时
+ .writeTimeout(10, TimeUnit.SECONDS)// 写入时间:10s超时
+ return builder.addInterceptor(interceptor).build()
+ }
+}
diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt
new file mode 100644
index 0000000..41348ab
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt
@@ -0,0 +1,16 @@
+package com.casic.birmm.inspect.utils.retrofit
+
+import com.casic.birmm.inspect.model.PublicKeyBean
+import retrofit2.http.GET
+
+/**
+ * @JvmSuppressWildcards 用来注解类和方法,使得被标记元素的泛型参数不会被编译成通配符?
+ * */
+@JvmSuppressWildcards
+interface RetrofitService {
+ /**
+ * PublicKey校验
+ */
+ @GET("/pan-tilt/config/baseConfig")
+ suspend fun obtainPublicKeyAsync(): PublicKeyBean
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitServiceManager.kt
new file mode 100644
index 0000000..fe9869b
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitServiceManager.kt
@@ -0,0 +1,16 @@
+package com.casic.birmm.inspect.utils.retrofit
+
+import com.casic.birmm.inspect.model.PublicKeyBean
+
+
+object RetrofitServiceManager {
+
+ private val api by lazy { RetrofitFactory.createRetrofit(RetrofitService::class.java) }
+
+ /**
+ * 验证PublicKey
+ */
+ suspend fun authenticate(): PublicKeyBean {
+ return api.obtainPublicKeyAsync()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/view/GuideActivity.kt b/app/src/main/java/com/casic/birmm/inspect/view/GuideActivity.kt
new file mode 100644
index 0000000..a5578c3
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/view/GuideActivity.kt
@@ -0,0 +1,56 @@
+package com.casic.birmm.inspect.view
+
+import android.annotation.SuppressLint
+import android.content.Intent
+import android.os.CountDownTimer
+import android.view.ViewGroup.MarginLayoutParams
+import com.casic.birmm.inspect.R
+import com.casic.birmm.inspect.base.BaseActivity
+import com.qmuiteam.qmui.util.QMUIDisplayHelper
+import kotlinx.android.synthetic.main.activity_guide.*
+
+@SuppressLint("SetTextI18n")
+class GuideActivity : BaseActivity() {
+
+ private lateinit var countDownTimer: CountDownTimer
+
+ override fun initLayoutView(): Int = R.layout.activity_guide
+
+ override fun setupTopBarLayout() {
+
+ }
+
+ override fun initData() {
+ //根据不同设备状态栏高度设置"跳过"按钮的Margin值
+ val statusBarHeight = QMUIDisplayHelper.getStatusBarHeight(this)
+ val rightMargin = QMUIDisplayHelper.dp2px(this, 10)
+ if (skipButton.layoutParams is MarginLayoutParams) {
+ val params = skipButton.layoutParams as MarginLayoutParams
+ params.setMargins(skipButton.width, statusBarHeight, rightMargin, 0)
+ skipButton.requestLayout()
+ }
+
+ countDownTimer = object : CountDownTimer(4000, 1000) {
+ override fun onFinish() {
+ startLoginActivity()
+ }
+
+ override fun onTick(millisUntilFinished: Long) {
+ skipButton.text = "跳过\u3000${(millisUntilFinished / 1000)}s"
+ }
+ }
+ }
+
+ override fun initEvent() {
+ countDownTimer.start()
+ skipButton.setOnClickListener {
+ countDownTimer.cancel()
+ startLoginActivity()
+ }
+ }
+
+ fun startLoginActivity() {
+ startActivity(Intent(this, LoginActivity::class.java))
+ finish()
+ }
+}
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..35eb1dd
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
index 4ca4a9f..0002b4a 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -27,6 +27,12 @@
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
+
+ kotlin {
+ experimental {
+ coroutines 'enable'
+ }
+ }
}
dependencies {
@@ -47,19 +53,24 @@
implementation 'com.gyf.immersionbar:immersionbar:3.0.0'
//fragment快速实现
implementation 'com.gyf.immersionbar:immersionbar-components:3.0.0'
+ //MVVM
+ implementation "androidx.lifecycle:lifecycle-livedata:2.2.0"
+ implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0"
+ implementation "androidx.lifecycle:lifecycle-extensions:2.2.0"
+ //Kotlin协程
+ implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.0'
+ implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.0'
+ //返回值转换器
+ implementation 'com.jakewharton.retrofit:retrofit2-kotlin-coroutines-adapter:0.9.2'
+ implementation 'com.squareup.retrofit2:converter-scalars:2.0.0'
+ implementation 'com.squareup.retrofit2:converter-gson:2.8.1'
+ //okhttp3日志拦截器
+ implementation 'com.squareup.okhttp3:logging-interceptor:4.6.0'
- //MVP网络请求框架retrofit2+rxjava
- implementation 'io.reactivex:rxjava:1.3.8'
- implementation 'io.reactivex:rxandroid:1.2.1'
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.okhttp3:okhttp:4.6.0'
- implementation 'com.squareup.retrofit2:converter-gson:2.8.1'
- implementation 'com.squareup.retrofit2:adapter-rxjava:2.8.1'
- implementation 'com.squareup.okhttp3:logging-interceptor:4.6.0'
//官方Json解析库
implementation 'com.google.code.gson:gson:2.8.6'
- //Toast提示
- implementation 'com.sdsmdg.tastytoast:tastytoast:0.1.1'
//图片选择框架
implementation 'com.github.LuckSiege.PictureSelector:picture_library:v2.6.0'
//上拉加载下拉刷新
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 7096527..be35467 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -23,16 +23,16 @@
android:theme="@style/QMUI.Compat.NoActionBar"
android:usesCleartextTraffic="true"
tools:targetApi="m">
-
+
-
-
-
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/base/BaseActivity.kt b/app/src/main/java/com/casic/birmm/inspect/base/BaseActivity.kt
index aefdbb6..b6b9f53 100644
--- a/app/src/main/java/com/casic/birmm/inspect/base/BaseActivity.kt
+++ b/app/src/main/java/com/casic/birmm/inspect/base/BaseActivity.kt
@@ -4,6 +4,9 @@
import androidx.appcompat.app.AppCompatActivity
import com.qmuiteam.qmui.util.QMUIStatusBarHelper
+/**
+ * 无网络请求等普通页面的基础类
+ * */
abstract class BaseActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
diff --git a/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModel.kt b/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModel.kt
new file mode 100644
index 0000000..968b877
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModel.kt
@@ -0,0 +1,9 @@
+package com.casic.birmm.inspect.base
+
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.ViewModel
+import com.casic.birmm.inspect.utils.LoadState
+
+abstract class BaseViewModel : ViewModel() {
+ val loadState = MutableLiveData()
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModelActivity.kt b/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModelActivity.kt
new file mode 100644
index 0000000..ee93c84
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModelActivity.kt
@@ -0,0 +1,61 @@
+package com.casic.birmm.inspect.base
+
+import android.os.Bundle
+import androidx.appcompat.app.AppCompatActivity
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.ViewModelProvider
+import com.qmuiteam.qmui.util.QMUIStatusBarHelper
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.MainScope
+import kotlinx.coroutines.cancel
+
+/**
+ * MV ViewModel 架构
+ *
+ * 有网络请求等普通页面的基础类
+ */
+abstract class BaseViewModelActivity : AppCompatActivity(),
+ CoroutineScope by MainScope() {
+
+ protected lateinit var viewModel: VM
+
+ /**
+ * 初始化xml布局
+ */
+ protected abstract fun initLayoutView(): Int
+
+ /**
+ * 特定页面定制沉浸式状态栏
+ */
+ protected abstract fun setupTopBarLayout()
+
+ /**
+ * 初始化默认数据
+ */
+ abstract fun initData()
+
+ /**
+ * 初始化业务逻辑
+ */
+ abstract fun initEvent()
+
+ /**
+ * 提供ViewModel类
+ */
+ protected abstract fun createViewModelByClass(): Class?
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(initLayoutView())
+ createViewModelByClass()?.let { viewModel = ViewModelProvider(this).get(it) }
+ QMUIStatusBarHelper.translucent(this) //沉浸式状态栏
+ setupTopBarLayout()
+ initData()
+ initEvent()
+ }
+
+ override fun onDestroy() {
+ cancel()// 取消协程
+ super.onDestroy()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/model/PublicKeyBean.kt b/app/src/main/java/com/casic/birmm/inspect/model/PublicKeyBean.kt
new file mode 100644
index 0000000..25c5436
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/model/PublicKeyBean.kt
@@ -0,0 +1,18 @@
+package com.casic.birmm.inspect.model
+
+/**
+ * PublicKey 登录校验Key
+ */
+class PublicKeyBean {
+ var code = 0
+ var data: DataBean? = null
+ var message: String? = null
+ var isSuccess = false
+
+ class DataBean {
+ var isAppKaptcha = false
+ var isKaptcha = false
+ var publicKey: String? = null
+ var sid: String? = null
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/ui/GuideActivity.kt b/app/src/main/java/com/casic/birmm/inspect/ui/GuideActivity.kt
deleted file mode 100644
index ddc160a..0000000
--- a/app/src/main/java/com/casic/birmm/inspect/ui/GuideActivity.kt
+++ /dev/null
@@ -1,56 +0,0 @@
-package com.casic.birmm.inspect.ui
-
-import android.annotation.SuppressLint
-import android.content.Intent
-import android.os.CountDownTimer
-import android.view.ViewGroup.MarginLayoutParams
-import com.casic.birmm.inspect.R
-import com.casic.birmm.inspect.base.BaseActivity
-import com.qmuiteam.qmui.util.QMUIDisplayHelper
-import kotlinx.android.synthetic.main.activity_guide.*
-
-@SuppressLint("SetTextI18n")
-class GuideActivity : BaseActivity() {
-
- private lateinit var countDownTimer: CountDownTimer
-
- override fun initLayoutView(): Int = R.layout.activity_guide
-
- override fun setupTopBarLayout() {
-
- }
-
- override fun initData() {
- //根据不同设备状态栏高度设置"跳过"按钮的Margin值
- val statusBarHeight = QMUIDisplayHelper.getStatusBarHeight(this)
- val rightMargin = QMUIDisplayHelper.dp2px(this, 10)
- if (skipButton.layoutParams is MarginLayoutParams) {
- val params = skipButton.layoutParams as MarginLayoutParams
- params.setMargins(skipButton.width, statusBarHeight, rightMargin, 0)
- skipButton.requestLayout()
- }
-
- countDownTimer = object : CountDownTimer(4000, 1000) {
- override fun onFinish() {
- startLoginActivity()
- }
-
- override fun onTick(millisUntilFinished: Long) {
- skipButton.text = "跳过\u3000${(millisUntilFinished / 1000)}s"
- }
- }
- }
-
- override fun initEvent() {
- countDownTimer.start()
- skipButton.setOnClickListener {
- countDownTimer.cancel()
- startLoginActivity()
- }
- }
-
- fun startLoginActivity() {
- startActivity(Intent(this, LoginActivity::class.java))
- finish()
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/ui/LoginActivity.kt b/app/src/main/java/com/casic/birmm/inspect/ui/LoginActivity.kt
deleted file mode 100644
index 6ef4548..0000000
--- a/app/src/main/java/com/casic/birmm/inspect/ui/LoginActivity.kt
+++ /dev/null
@@ -1,81 +0,0 @@
-package com.casic.birmm.inspect.ui
-
-import android.text.Editable
-import android.text.TextWatcher
-import android.view.KeyEvent
-import android.view.inputmethod.EditorInfo
-import android.widget.EditText
-import android.widget.TextView
-import com.casic.birmm.inspect.R
-import com.casic.birmm.inspect.base.BaseActivity
-import com.casic.birmm.inspect.utils.Constant
-import com.casic.birmm.inspect.utils.SaveKeyValues
-import com.casic.birmm.inspect.widgets.InputDialog
-import kotlinx.android.synthetic.main.activity_login.*
-
-
-class LoginActivity : BaseActivity() {
-
- companion object {
- private const val Tag = "LoginActivity"
- }
-
- override fun initLayoutView(): Int = R.layout.activity_login
-
- override fun setupTopBarLayout() {
-
- }
-
- override fun initData() {
-
- }
-
- override fun initEvent() {
- loginButton.setChangeAlphaWhenPress(true)
- val editText: EditText? = inputLayout.editText
- editText?.addTextChangedListener(object : TextWatcher {
- override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
-
- }
-
- override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
-
- }
-
- override fun afterTextChanged(s: Editable) {
- if (s.toString().trim { it <= ' ' }.length > 12) {
- inputLayout.error = "密码长度超出限制"
- } else {
- inputLayout.error = null
- }
- }
- })
- //点击输入法键盘"完成"
- editText?.setOnEditorActionListener { _: TextView?, actionId: Int, _: KeyEvent? ->
- if (actionId == EditorInfo.IME_ACTION_DONE) {
-// authenticatePresenter.onReadyRetrofitRequest()
- return@setOnEditorActionListener true
- }
- false
- }
-
- //修改服务器配置
- changeServerConfigView.setOnClickListener {
- val defaultValue = SaveKeyValues.getValue(
- Constant.DEFAULT_SERVER_CONFIG,
- "http://139.198.6.177:8093/"
- ) as String
- InputDialog.Builder().setContext(this)
- .setTitle("请输入后台服务器地址")
- .setDefaultValue(defaultValue)
- .setNegativeButton("取消")
- .setPositiveButton("保存")
- .setOnDialogClickListener(object : InputDialog.OnDialogButtonClickListener {
- override fun onButtonClick(input: String) {
- SaveKeyValues.putValue(Constant.DEFAULT_SERVER_CONFIG, input)
- }
- })
- .build().show()
- }
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/ui/MainActivity.kt b/app/src/main/java/com/casic/birmm/inspect/ui/MainActivity.kt
deleted file mode 100644
index 0e97af7..0000000
--- a/app/src/main/java/com/casic/birmm/inspect/ui/MainActivity.kt
+++ /dev/null
@@ -1,21 +0,0 @@
-package com.casic.birmm.inspect.ui
-
-import com.casic.birmm.inspect.R
-import com.casic.birmm.inspect.base.BaseActivity
-
-class MainActivity : BaseActivity() {
-
- override fun initLayoutView(): Int = R.layout.activity_main
-
- override fun setupTopBarLayout() {
-
- }
-
- override fun initData() {
-
- }
-
- override fun initEvent() {
-
- }
-}
diff --git a/app/src/main/java/com/casic/birmm/inspect/ui/PermissionActivity.kt b/app/src/main/java/com/casic/birmm/inspect/ui/PermissionActivity.kt
deleted file mode 100644
index 21fbba2..0000000
--- a/app/src/main/java/com/casic/birmm/inspect/ui/PermissionActivity.kt
+++ /dev/null
@@ -1,58 +0,0 @@
-package com.casic.birmm.inspect.ui
-
-import android.content.Intent
-import android.os.Build
-import android.os.Bundle
-import android.util.Log
-import androidx.appcompat.app.AppCompatActivity
-import com.casic.birmm.inspect.utils.Constant
-import pub.devrel.easypermissions.EasyPermissions
-import pub.devrel.easypermissions.EasyPermissions.PermissionCallbacks
-
-class PermissionActivity : AppCompatActivity(), PermissionCallbacks {
-
- companion object {
- private const val TAG = "PermissionActivity"
- }
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- //判断是否有权限,如果版本大于5.1才需要判断(即6.0以上),其他则不需要判断。
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
- if (EasyPermissions.hasPermissions(this, *Constant.USER_PERMISSIONS)) {
- startGuideActivity()
- } else {
- EasyPermissions.requestPermissions(
- this,
- "需要获取相关权限",
- Constant.PERMISSIONS_CODE,
- *Constant.USER_PERMISSIONS
- )
- }
- } else {
- startGuideActivity()
- }
- }
-
- private fun startGuideActivity() {
- startActivity(Intent(this, GuideActivity::class.java))
- finish()
- }
-
- override fun onRequestPermissionsResult(
- requestCode: Int,
- permissions: Array,
- grantResults: IntArray
- ) {
- super.onRequestPermissionsResult(requestCode, permissions, grantResults)
- EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this)
- }
-
- override fun onPermissionsGranted(requestCode: Int, perms: List) {
- startGuideActivity()
- }
-
- override fun onPermissionsDenied(requestCode: Int, perms: List) {
- Log.e(TAG, "onPermissionsDenied: $perms")
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/ExtensionViewModel.kt b/app/src/main/java/com/casic/birmm/inspect/utils/ExtensionViewModel.kt
new file mode 100644
index 0000000..2259965
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/utils/ExtensionViewModel.kt
@@ -0,0 +1,33 @@
+package com.casic.birmm.inspect.utils
+
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import kotlinx.coroutines.CoroutineExceptionHandler
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.launch
+
+/**
+ * ViewModel扩展方法:启动协程
+ * @param block 协程逻辑
+ * @param onError 错误回调方法
+ * @param onComplete 完成回调方法
+ */
+fun ViewModel.launch(
+ block: suspend CoroutineScope.() -> Unit,
+ onError: (e: Throwable) -> Unit = {},
+ onComplete: () -> Unit = {}
+) {
+ viewModelScope.launch(
+ CoroutineExceptionHandler { _, throwable ->
+ run {
+ onError(throwable)
+ }
+ }
+ ) {
+ try {
+ block.invoke(this)
+ } finally {
+ onComplete()
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/LoadState.kt b/app/src/main/java/com/casic/birmm/inspect/utils/LoadState.kt
new file mode 100644
index 0000000..9c83224
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/utils/LoadState.kt
@@ -0,0 +1,22 @@
+package com.casic.birmm.inspect.utils
+
+/**
+ * 加载状态
+ * sealed 关键字表示此类仅内部继承
+ */
+sealed class LoadState(val msg: String) {
+ /**
+ * 加载中
+ */
+ class Loading(msg: String = "") : LoadState(msg)
+
+ /**
+ * 成功
+ */
+ class Success(msg: String = "") : LoadState(msg)
+
+ /**
+ * 失败
+ */
+ class Fail(msg: String = "") : LoadState(msg)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/OtherUtils.kt b/app/src/main/java/com/casic/birmm/inspect/utils/OtherUtils.kt
index 4c38241..ff63747 100644
--- a/app/src/main/java/com/casic/birmm/inspect/utils/OtherUtils.kt
+++ b/app/src/main/java/com/casic/birmm/inspect/utils/OtherUtils.kt
@@ -6,6 +6,8 @@
object OtherUtils {
+ private var loadingDialog: QMUITipDialog? = null
+
//替换Toast
fun showTipsDialog(context: Context, message: String, view: View) {
val tipDialog = QMUITipDialog.Builder(context)
@@ -16,4 +18,20 @@
tipDialog.dismiss()
}, 2000)
}
+
+ fun showLoadingDialog(context: Context?, message: String?) {
+ loadingDialog = QMUITipDialog.Builder(context)
+ .setIconType(QMUITipDialog.Builder.ICON_TYPE_LOADING)
+ .setTipWord(message)
+ .create()
+ loadingDialog!!.show()
+ }
+
+ fun dismissLoadingDialog() {
+ if (loadingDialog != null) {
+ if (loadingDialog!!.isShowing) {
+ loadingDialog!!.dismiss()
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/RSAUtils.kt b/app/src/main/java/com/casic/birmm/inspect/utils/RSAUtils.kt
new file mode 100644
index 0000000..b93983b
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/utils/RSAUtils.kt
@@ -0,0 +1,61 @@
+package com.casic.birmm.inspect.utils
+
+import android.util.Base64
+import java.security.*
+import java.security.spec.InvalidKeySpecException
+import java.security.spec.X509EncodedKeySpec
+import javax.crypto.BadPaddingException
+import javax.crypto.Cipher
+import javax.crypto.IllegalBlockSizeException
+import javax.crypto.NoSuchPaddingException
+
+/**
+ * Created by W530 on 2019/9/26.
+ */
+object RSAUtils {
+ //构建Cipher实例时所传入的的字符串,默认为"RSA/NONE/PKCS1Padding"
+ private fun processData(srcData: ByteArray, key: Key, mode: Int): ByteArray? { //用来保存处理结果
+ var resultBytes: ByteArray? = null
+ try { //获取Cipher实例
+ val cipher = Cipher.getInstance("RSA/None/PKCS1Padding")
+ //初始化Cipher,mode指定是加密还是解密,key为公钥或私钥
+ cipher.init(mode, key)
+ //处理数据
+ resultBytes = cipher.doFinal(srcData)
+ } catch (e: NoSuchAlgorithmException) {
+ e.printStackTrace()
+ } catch (e: NoSuchPaddingException) {
+ e.printStackTrace()
+ } catch (e: InvalidKeyException) {
+ e.printStackTrace()
+ } catch (e: BadPaddingException) {
+ e.printStackTrace()
+ } catch (e: IllegalBlockSizeException) {
+ e.printStackTrace()
+ }
+ return resultBytes
+ }
+
+ fun encryptDataByPublicKey(srcData: ByteArray, publicKey: PublicKey): String {
+ val resultBytes =
+ processData(srcData, publicKey, Cipher.ENCRYPT_MODE)
+ return Base64.encodeToString(resultBytes, Base64.DEFAULT)
+ }
+
+ fun keyStrToPublicKey(publicKeyStr: String?): PublicKey? {
+ var publicKey: PublicKey? = null
+ val keyBytes =
+ Base64.decode(publicKeyStr, Base64.DEFAULT)
+ val keySpec =
+ X509EncodedKeySpec(keyBytes)
+ try {
+ val keyFactory = KeyFactory.getInstance("RSA")
+ publicKey = keyFactory.generatePublic(keySpec)
+ } catch (e: NoSuchAlgorithmException) {
+ e.printStackTrace()
+ } catch (e: InvalidKeySpecException) {
+ e.printStackTrace()
+ }
+ return publicKey
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitFactory.kt b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitFactory.kt
new file mode 100644
index 0000000..0dd341f
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitFactory.kt
@@ -0,0 +1,48 @@
+package com.casic.birmm.inspect.utils.retrofit;
+
+import android.util.Log
+import com.casic.birmm.inspect.utils.Constant
+import com.casic.birmm.inspect.utils.SaveKeyValues
+import com.jakewharton.retrofit2.adapter.kotlin.coroutines.CoroutineCallAdapterFactory
+import okhttp3.OkHttpClient
+import okhttp3.logging.HttpLoggingInterceptor
+import org.jetbrains.annotations.NotNull
+import retrofit2.Retrofit
+import retrofit2.converter.gson.GsonConverterFactory
+import retrofit2.converter.scalars.ScalarsConverterFactory
+import java.util.concurrent.TimeUnit
+
+object RetrofitFactory {
+ private const val Tag = "RetrofitFactory"
+
+ private val client: OkHttpClient by lazy { createOKHttpClient() }
+
+ fun createRetrofit(clazz: Class): T {
+ val defaultValue = SaveKeyValues.getValue(
+ Constant.DEFAULT_SERVER_CONFIG,
+ "http://111.198.10.15:12204"
+ ) as String
+ return Retrofit.Builder()
+ .baseUrl(defaultValue)
+ .addConverterFactory(ScalarsConverterFactory.create()) //字符串转换器
+ .addConverterFactory(GsonConverterFactory.create()) //Gson转换器
+ .addCallAdapterFactory(CoroutineCallAdapterFactory.invoke()) //协程请求适配器
+ .client(client) //log拦截器
+ .build().create(clazz)
+ }
+
+ private fun createOKHttpClient(): OkHttpClient { //日志显示级别
+ val interceptor =
+ HttpLoggingInterceptor(object : HttpLoggingInterceptor.Logger {
+ override fun log(@NotNull message: String) {
+ Log.d(Tag, "log: $message")
+ }
+ })
+ interceptor.setLevel(HttpLoggingInterceptor.Level.BODY)
+ val builder = OkHttpClient.Builder()
+ .connectTimeout(30, TimeUnit.SECONDS)// 连接时间:30s超时
+ .readTimeout(10, TimeUnit.SECONDS)// 读取时间:10s超时
+ .writeTimeout(10, TimeUnit.SECONDS)// 写入时间:10s超时
+ return builder.addInterceptor(interceptor).build()
+ }
+}
diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt
new file mode 100644
index 0000000..41348ab
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt
@@ -0,0 +1,16 @@
+package com.casic.birmm.inspect.utils.retrofit
+
+import com.casic.birmm.inspect.model.PublicKeyBean
+import retrofit2.http.GET
+
+/**
+ * @JvmSuppressWildcards 用来注解类和方法,使得被标记元素的泛型参数不会被编译成通配符?
+ * */
+@JvmSuppressWildcards
+interface RetrofitService {
+ /**
+ * PublicKey校验
+ */
+ @GET("/pan-tilt/config/baseConfig")
+ suspend fun obtainPublicKeyAsync(): PublicKeyBean
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitServiceManager.kt
new file mode 100644
index 0000000..fe9869b
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitServiceManager.kt
@@ -0,0 +1,16 @@
+package com.casic.birmm.inspect.utils.retrofit
+
+import com.casic.birmm.inspect.model.PublicKeyBean
+
+
+object RetrofitServiceManager {
+
+ private val api by lazy { RetrofitFactory.createRetrofit(RetrofitService::class.java) }
+
+ /**
+ * 验证PublicKey
+ */
+ suspend fun authenticate(): PublicKeyBean {
+ return api.obtainPublicKeyAsync()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/view/GuideActivity.kt b/app/src/main/java/com/casic/birmm/inspect/view/GuideActivity.kt
new file mode 100644
index 0000000..a5578c3
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/view/GuideActivity.kt
@@ -0,0 +1,56 @@
+package com.casic.birmm.inspect.view
+
+import android.annotation.SuppressLint
+import android.content.Intent
+import android.os.CountDownTimer
+import android.view.ViewGroup.MarginLayoutParams
+import com.casic.birmm.inspect.R
+import com.casic.birmm.inspect.base.BaseActivity
+import com.qmuiteam.qmui.util.QMUIDisplayHelper
+import kotlinx.android.synthetic.main.activity_guide.*
+
+@SuppressLint("SetTextI18n")
+class GuideActivity : BaseActivity() {
+
+ private lateinit var countDownTimer: CountDownTimer
+
+ override fun initLayoutView(): Int = R.layout.activity_guide
+
+ override fun setupTopBarLayout() {
+
+ }
+
+ override fun initData() {
+ //根据不同设备状态栏高度设置"跳过"按钮的Margin值
+ val statusBarHeight = QMUIDisplayHelper.getStatusBarHeight(this)
+ val rightMargin = QMUIDisplayHelper.dp2px(this, 10)
+ if (skipButton.layoutParams is MarginLayoutParams) {
+ val params = skipButton.layoutParams as MarginLayoutParams
+ params.setMargins(skipButton.width, statusBarHeight, rightMargin, 0)
+ skipButton.requestLayout()
+ }
+
+ countDownTimer = object : CountDownTimer(4000, 1000) {
+ override fun onFinish() {
+ startLoginActivity()
+ }
+
+ override fun onTick(millisUntilFinished: Long) {
+ skipButton.text = "跳过\u3000${(millisUntilFinished / 1000)}s"
+ }
+ }
+ }
+
+ override fun initEvent() {
+ countDownTimer.start()
+ skipButton.setOnClickListener {
+ countDownTimer.cancel()
+ startLoginActivity()
+ }
+ }
+
+ fun startLoginActivity() {
+ startActivity(Intent(this, LoginActivity::class.java))
+ finish()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/view/LoginActivity.kt b/app/src/main/java/com/casic/birmm/inspect/view/LoginActivity.kt
new file mode 100644
index 0000000..bdb3f2d
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/view/LoginActivity.kt
@@ -0,0 +1,110 @@
+package com.casic.birmm.inspect.view
+
+import android.text.Editable
+import android.text.TextWatcher
+import android.util.Log
+import android.view.KeyEvent
+import android.view.inputmethod.EditorInfo
+import android.widget.EditText
+import android.widget.TextView
+import androidx.lifecycle.Observer
+import com.casic.birmm.inspect.R
+import com.casic.birmm.inspect.base.BaseViewModelActivity
+import com.casic.birmm.inspect.utils.*
+import com.casic.birmm.inspect.vm.AuthenticateViewModel
+import com.casic.birmm.inspect.widgets.InputDialog
+import kotlinx.android.synthetic.main.activity_login.*
+
+
+class LoginActivity : BaseViewModelActivity() {
+
+ companion object {
+ private const val Tag = "LoginActivity"
+ }
+
+ override fun createViewModelByClass(): Class? =
+ AuthenticateViewModel::class.java
+
+ override fun initLayoutView(): Int = R.layout.activity_login
+
+ override fun setupTopBarLayout() {
+
+ }
+
+ override fun initData() {
+ // 监听数据变化,从而显示数据在页面
+ viewModel.keyBean.observe(this, Observer {
+ if (it.isSuccess) {
+ Log.d(Tag, "${it.data!!.publicKey}")
+ val keyString = it.data!!.publicKey
+ val publicKey = RSAUtils.keyStrToPublicKey(keyString)
+ val account = userNameView.text.toString()
+ val userPassword = userPasswordView.text.toString()
+ } else {
+ OtherUtils.showTipsDialog(this, it.message!!, loginButton)
+ }
+ })
+ // 监听加载状态变化 从而改变页面
+ viewModel.loadState.observe(this, Observer {
+ when (it) {
+ is LoadState.Loading -> {
+ OtherUtils.showLoadingDialog(this, "登录中,请稍后")
+ }
+ else -> OtherUtils.dismissLoadingDialog()
+ }
+ })
+ }
+
+ override fun initEvent() {
+ val editText: EditText? = inputLayout.editText
+ editText?.addTextChangedListener(object : TextWatcher {
+ override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
+
+ }
+
+ override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
+
+ }
+
+ override fun afterTextChanged(s: Editable) {
+ if (s.toString().trim { it <= ' ' }.length > 12) {
+ inputLayout.error = "密码长度超出限制"
+ } else {
+ inputLayout.error = null
+ }
+ }
+ })
+ //点击输入法键盘"完成"
+ editText?.setOnEditorActionListener { _: TextView?, actionId: Int, _: KeyEvent? ->
+ if (actionId == EditorInfo.IME_ACTION_DONE) {
+ viewModel.obtainPublicKey()
+ return@setOnEditorActionListener true
+ }
+ false
+ }
+
+ loginButton.setChangeAlphaWhenPress(true)
+ loginButton.setOnClickListener {
+ viewModel.obtainPublicKey()
+ }
+
+ //修改服务器配置
+ changeServerConfigView.setOnClickListener {
+ val defaultValue = SaveKeyValues.getValue(
+ Constant.DEFAULT_SERVER_CONFIG,
+ "http://111.198.10.15:12204"
+ ) as String
+ InputDialog.Builder().setContext(this)
+ .setTitle("请输入后台服务器地址")
+ .setDefaultValue(defaultValue)
+ .setNegativeButton("取消")
+ .setPositiveButton("保存")
+ .setOnDialogClickListener(object : InputDialog.OnDialogButtonClickListener {
+ override fun onButtonClick(input: String) {
+ SaveKeyValues.putValue(Constant.DEFAULT_SERVER_CONFIG, input)
+ }
+ })
+ .build().show()
+ }
+ }
+}
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..35eb1dd
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
index 4ca4a9f..0002b4a 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -27,6 +27,12 @@
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
+
+ kotlin {
+ experimental {
+ coroutines 'enable'
+ }
+ }
}
dependencies {
@@ -47,19 +53,24 @@
implementation 'com.gyf.immersionbar:immersionbar:3.0.0'
//fragment快速实现
implementation 'com.gyf.immersionbar:immersionbar-components:3.0.0'
+ //MVVM
+ implementation "androidx.lifecycle:lifecycle-livedata:2.2.0"
+ implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0"
+ implementation "androidx.lifecycle:lifecycle-extensions:2.2.0"
+ //Kotlin协程
+ implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.0'
+ implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.0'
+ //返回值转换器
+ implementation 'com.jakewharton.retrofit:retrofit2-kotlin-coroutines-adapter:0.9.2'
+ implementation 'com.squareup.retrofit2:converter-scalars:2.0.0'
+ implementation 'com.squareup.retrofit2:converter-gson:2.8.1'
+ //okhttp3日志拦截器
+ implementation 'com.squareup.okhttp3:logging-interceptor:4.6.0'
- //MVP网络请求框架retrofit2+rxjava
- implementation 'io.reactivex:rxjava:1.3.8'
- implementation 'io.reactivex:rxandroid:1.2.1'
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.okhttp3:okhttp:4.6.0'
- implementation 'com.squareup.retrofit2:converter-gson:2.8.1'
- implementation 'com.squareup.retrofit2:adapter-rxjava:2.8.1'
- implementation 'com.squareup.okhttp3:logging-interceptor:4.6.0'
//官方Json解析库
implementation 'com.google.code.gson:gson:2.8.6'
- //Toast提示
- implementation 'com.sdsmdg.tastytoast:tastytoast:0.1.1'
//图片选择框架
implementation 'com.github.LuckSiege.PictureSelector:picture_library:v2.6.0'
//上拉加载下拉刷新
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 7096527..be35467 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -23,16 +23,16 @@
android:theme="@style/QMUI.Compat.NoActionBar"
android:usesCleartextTraffic="true"
tools:targetApi="m">
-
+
-
-
-
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/base/BaseActivity.kt b/app/src/main/java/com/casic/birmm/inspect/base/BaseActivity.kt
index aefdbb6..b6b9f53 100644
--- a/app/src/main/java/com/casic/birmm/inspect/base/BaseActivity.kt
+++ b/app/src/main/java/com/casic/birmm/inspect/base/BaseActivity.kt
@@ -4,6 +4,9 @@
import androidx.appcompat.app.AppCompatActivity
import com.qmuiteam.qmui.util.QMUIStatusBarHelper
+/**
+ * 无网络请求等普通页面的基础类
+ * */
abstract class BaseActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
diff --git a/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModel.kt b/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModel.kt
new file mode 100644
index 0000000..968b877
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModel.kt
@@ -0,0 +1,9 @@
+package com.casic.birmm.inspect.base
+
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.ViewModel
+import com.casic.birmm.inspect.utils.LoadState
+
+abstract class BaseViewModel : ViewModel() {
+ val loadState = MutableLiveData()
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModelActivity.kt b/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModelActivity.kt
new file mode 100644
index 0000000..ee93c84
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModelActivity.kt
@@ -0,0 +1,61 @@
+package com.casic.birmm.inspect.base
+
+import android.os.Bundle
+import androidx.appcompat.app.AppCompatActivity
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.ViewModelProvider
+import com.qmuiteam.qmui.util.QMUIStatusBarHelper
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.MainScope
+import kotlinx.coroutines.cancel
+
+/**
+ * MV ViewModel 架构
+ *
+ * 有网络请求等普通页面的基础类
+ */
+abstract class BaseViewModelActivity : AppCompatActivity(),
+ CoroutineScope by MainScope() {
+
+ protected lateinit var viewModel: VM
+
+ /**
+ * 初始化xml布局
+ */
+ protected abstract fun initLayoutView(): Int
+
+ /**
+ * 特定页面定制沉浸式状态栏
+ */
+ protected abstract fun setupTopBarLayout()
+
+ /**
+ * 初始化默认数据
+ */
+ abstract fun initData()
+
+ /**
+ * 初始化业务逻辑
+ */
+ abstract fun initEvent()
+
+ /**
+ * 提供ViewModel类
+ */
+ protected abstract fun createViewModelByClass(): Class?
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(initLayoutView())
+ createViewModelByClass()?.let { viewModel = ViewModelProvider(this).get(it) }
+ QMUIStatusBarHelper.translucent(this) //沉浸式状态栏
+ setupTopBarLayout()
+ initData()
+ initEvent()
+ }
+
+ override fun onDestroy() {
+ cancel()// 取消协程
+ super.onDestroy()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/model/PublicKeyBean.kt b/app/src/main/java/com/casic/birmm/inspect/model/PublicKeyBean.kt
new file mode 100644
index 0000000..25c5436
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/model/PublicKeyBean.kt
@@ -0,0 +1,18 @@
+package com.casic.birmm.inspect.model
+
+/**
+ * PublicKey 登录校验Key
+ */
+class PublicKeyBean {
+ var code = 0
+ var data: DataBean? = null
+ var message: String? = null
+ var isSuccess = false
+
+ class DataBean {
+ var isAppKaptcha = false
+ var isKaptcha = false
+ var publicKey: String? = null
+ var sid: String? = null
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/ui/GuideActivity.kt b/app/src/main/java/com/casic/birmm/inspect/ui/GuideActivity.kt
deleted file mode 100644
index ddc160a..0000000
--- a/app/src/main/java/com/casic/birmm/inspect/ui/GuideActivity.kt
+++ /dev/null
@@ -1,56 +0,0 @@
-package com.casic.birmm.inspect.ui
-
-import android.annotation.SuppressLint
-import android.content.Intent
-import android.os.CountDownTimer
-import android.view.ViewGroup.MarginLayoutParams
-import com.casic.birmm.inspect.R
-import com.casic.birmm.inspect.base.BaseActivity
-import com.qmuiteam.qmui.util.QMUIDisplayHelper
-import kotlinx.android.synthetic.main.activity_guide.*
-
-@SuppressLint("SetTextI18n")
-class GuideActivity : BaseActivity() {
-
- private lateinit var countDownTimer: CountDownTimer
-
- override fun initLayoutView(): Int = R.layout.activity_guide
-
- override fun setupTopBarLayout() {
-
- }
-
- override fun initData() {
- //根据不同设备状态栏高度设置"跳过"按钮的Margin值
- val statusBarHeight = QMUIDisplayHelper.getStatusBarHeight(this)
- val rightMargin = QMUIDisplayHelper.dp2px(this, 10)
- if (skipButton.layoutParams is MarginLayoutParams) {
- val params = skipButton.layoutParams as MarginLayoutParams
- params.setMargins(skipButton.width, statusBarHeight, rightMargin, 0)
- skipButton.requestLayout()
- }
-
- countDownTimer = object : CountDownTimer(4000, 1000) {
- override fun onFinish() {
- startLoginActivity()
- }
-
- override fun onTick(millisUntilFinished: Long) {
- skipButton.text = "跳过\u3000${(millisUntilFinished / 1000)}s"
- }
- }
- }
-
- override fun initEvent() {
- countDownTimer.start()
- skipButton.setOnClickListener {
- countDownTimer.cancel()
- startLoginActivity()
- }
- }
-
- fun startLoginActivity() {
- startActivity(Intent(this, LoginActivity::class.java))
- finish()
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/ui/LoginActivity.kt b/app/src/main/java/com/casic/birmm/inspect/ui/LoginActivity.kt
deleted file mode 100644
index 6ef4548..0000000
--- a/app/src/main/java/com/casic/birmm/inspect/ui/LoginActivity.kt
+++ /dev/null
@@ -1,81 +0,0 @@
-package com.casic.birmm.inspect.ui
-
-import android.text.Editable
-import android.text.TextWatcher
-import android.view.KeyEvent
-import android.view.inputmethod.EditorInfo
-import android.widget.EditText
-import android.widget.TextView
-import com.casic.birmm.inspect.R
-import com.casic.birmm.inspect.base.BaseActivity
-import com.casic.birmm.inspect.utils.Constant
-import com.casic.birmm.inspect.utils.SaveKeyValues
-import com.casic.birmm.inspect.widgets.InputDialog
-import kotlinx.android.synthetic.main.activity_login.*
-
-
-class LoginActivity : BaseActivity() {
-
- companion object {
- private const val Tag = "LoginActivity"
- }
-
- override fun initLayoutView(): Int = R.layout.activity_login
-
- override fun setupTopBarLayout() {
-
- }
-
- override fun initData() {
-
- }
-
- override fun initEvent() {
- loginButton.setChangeAlphaWhenPress(true)
- val editText: EditText? = inputLayout.editText
- editText?.addTextChangedListener(object : TextWatcher {
- override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
-
- }
-
- override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
-
- }
-
- override fun afterTextChanged(s: Editable) {
- if (s.toString().trim { it <= ' ' }.length > 12) {
- inputLayout.error = "密码长度超出限制"
- } else {
- inputLayout.error = null
- }
- }
- })
- //点击输入法键盘"完成"
- editText?.setOnEditorActionListener { _: TextView?, actionId: Int, _: KeyEvent? ->
- if (actionId == EditorInfo.IME_ACTION_DONE) {
-// authenticatePresenter.onReadyRetrofitRequest()
- return@setOnEditorActionListener true
- }
- false
- }
-
- //修改服务器配置
- changeServerConfigView.setOnClickListener {
- val defaultValue = SaveKeyValues.getValue(
- Constant.DEFAULT_SERVER_CONFIG,
- "http://139.198.6.177:8093/"
- ) as String
- InputDialog.Builder().setContext(this)
- .setTitle("请输入后台服务器地址")
- .setDefaultValue(defaultValue)
- .setNegativeButton("取消")
- .setPositiveButton("保存")
- .setOnDialogClickListener(object : InputDialog.OnDialogButtonClickListener {
- override fun onButtonClick(input: String) {
- SaveKeyValues.putValue(Constant.DEFAULT_SERVER_CONFIG, input)
- }
- })
- .build().show()
- }
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/ui/MainActivity.kt b/app/src/main/java/com/casic/birmm/inspect/ui/MainActivity.kt
deleted file mode 100644
index 0e97af7..0000000
--- a/app/src/main/java/com/casic/birmm/inspect/ui/MainActivity.kt
+++ /dev/null
@@ -1,21 +0,0 @@
-package com.casic.birmm.inspect.ui
-
-import com.casic.birmm.inspect.R
-import com.casic.birmm.inspect.base.BaseActivity
-
-class MainActivity : BaseActivity() {
-
- override fun initLayoutView(): Int = R.layout.activity_main
-
- override fun setupTopBarLayout() {
-
- }
-
- override fun initData() {
-
- }
-
- override fun initEvent() {
-
- }
-}
diff --git a/app/src/main/java/com/casic/birmm/inspect/ui/PermissionActivity.kt b/app/src/main/java/com/casic/birmm/inspect/ui/PermissionActivity.kt
deleted file mode 100644
index 21fbba2..0000000
--- a/app/src/main/java/com/casic/birmm/inspect/ui/PermissionActivity.kt
+++ /dev/null
@@ -1,58 +0,0 @@
-package com.casic.birmm.inspect.ui
-
-import android.content.Intent
-import android.os.Build
-import android.os.Bundle
-import android.util.Log
-import androidx.appcompat.app.AppCompatActivity
-import com.casic.birmm.inspect.utils.Constant
-import pub.devrel.easypermissions.EasyPermissions
-import pub.devrel.easypermissions.EasyPermissions.PermissionCallbacks
-
-class PermissionActivity : AppCompatActivity(), PermissionCallbacks {
-
- companion object {
- private const val TAG = "PermissionActivity"
- }
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- //判断是否有权限,如果版本大于5.1才需要判断(即6.0以上),其他则不需要判断。
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
- if (EasyPermissions.hasPermissions(this, *Constant.USER_PERMISSIONS)) {
- startGuideActivity()
- } else {
- EasyPermissions.requestPermissions(
- this,
- "需要获取相关权限",
- Constant.PERMISSIONS_CODE,
- *Constant.USER_PERMISSIONS
- )
- }
- } else {
- startGuideActivity()
- }
- }
-
- private fun startGuideActivity() {
- startActivity(Intent(this, GuideActivity::class.java))
- finish()
- }
-
- override fun onRequestPermissionsResult(
- requestCode: Int,
- permissions: Array,
- grantResults: IntArray
- ) {
- super.onRequestPermissionsResult(requestCode, permissions, grantResults)
- EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this)
- }
-
- override fun onPermissionsGranted(requestCode: Int, perms: List) {
- startGuideActivity()
- }
-
- override fun onPermissionsDenied(requestCode: Int, perms: List) {
- Log.e(TAG, "onPermissionsDenied: $perms")
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/ExtensionViewModel.kt b/app/src/main/java/com/casic/birmm/inspect/utils/ExtensionViewModel.kt
new file mode 100644
index 0000000..2259965
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/utils/ExtensionViewModel.kt
@@ -0,0 +1,33 @@
+package com.casic.birmm.inspect.utils
+
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import kotlinx.coroutines.CoroutineExceptionHandler
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.launch
+
+/**
+ * ViewModel扩展方法:启动协程
+ * @param block 协程逻辑
+ * @param onError 错误回调方法
+ * @param onComplete 完成回调方法
+ */
+fun ViewModel.launch(
+ block: suspend CoroutineScope.() -> Unit,
+ onError: (e: Throwable) -> Unit = {},
+ onComplete: () -> Unit = {}
+) {
+ viewModelScope.launch(
+ CoroutineExceptionHandler { _, throwable ->
+ run {
+ onError(throwable)
+ }
+ }
+ ) {
+ try {
+ block.invoke(this)
+ } finally {
+ onComplete()
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/LoadState.kt b/app/src/main/java/com/casic/birmm/inspect/utils/LoadState.kt
new file mode 100644
index 0000000..9c83224
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/utils/LoadState.kt
@@ -0,0 +1,22 @@
+package com.casic.birmm.inspect.utils
+
+/**
+ * 加载状态
+ * sealed 关键字表示此类仅内部继承
+ */
+sealed class LoadState(val msg: String) {
+ /**
+ * 加载中
+ */
+ class Loading(msg: String = "") : LoadState(msg)
+
+ /**
+ * 成功
+ */
+ class Success(msg: String = "") : LoadState(msg)
+
+ /**
+ * 失败
+ */
+ class Fail(msg: String = "") : LoadState(msg)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/OtherUtils.kt b/app/src/main/java/com/casic/birmm/inspect/utils/OtherUtils.kt
index 4c38241..ff63747 100644
--- a/app/src/main/java/com/casic/birmm/inspect/utils/OtherUtils.kt
+++ b/app/src/main/java/com/casic/birmm/inspect/utils/OtherUtils.kt
@@ -6,6 +6,8 @@
object OtherUtils {
+ private var loadingDialog: QMUITipDialog? = null
+
//替换Toast
fun showTipsDialog(context: Context, message: String, view: View) {
val tipDialog = QMUITipDialog.Builder(context)
@@ -16,4 +18,20 @@
tipDialog.dismiss()
}, 2000)
}
+
+ fun showLoadingDialog(context: Context?, message: String?) {
+ loadingDialog = QMUITipDialog.Builder(context)
+ .setIconType(QMUITipDialog.Builder.ICON_TYPE_LOADING)
+ .setTipWord(message)
+ .create()
+ loadingDialog!!.show()
+ }
+
+ fun dismissLoadingDialog() {
+ if (loadingDialog != null) {
+ if (loadingDialog!!.isShowing) {
+ loadingDialog!!.dismiss()
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/RSAUtils.kt b/app/src/main/java/com/casic/birmm/inspect/utils/RSAUtils.kt
new file mode 100644
index 0000000..b93983b
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/utils/RSAUtils.kt
@@ -0,0 +1,61 @@
+package com.casic.birmm.inspect.utils
+
+import android.util.Base64
+import java.security.*
+import java.security.spec.InvalidKeySpecException
+import java.security.spec.X509EncodedKeySpec
+import javax.crypto.BadPaddingException
+import javax.crypto.Cipher
+import javax.crypto.IllegalBlockSizeException
+import javax.crypto.NoSuchPaddingException
+
+/**
+ * Created by W530 on 2019/9/26.
+ */
+object RSAUtils {
+ //构建Cipher实例时所传入的的字符串,默认为"RSA/NONE/PKCS1Padding"
+ private fun processData(srcData: ByteArray, key: Key, mode: Int): ByteArray? { //用来保存处理结果
+ var resultBytes: ByteArray? = null
+ try { //获取Cipher实例
+ val cipher = Cipher.getInstance("RSA/None/PKCS1Padding")
+ //初始化Cipher,mode指定是加密还是解密,key为公钥或私钥
+ cipher.init(mode, key)
+ //处理数据
+ resultBytes = cipher.doFinal(srcData)
+ } catch (e: NoSuchAlgorithmException) {
+ e.printStackTrace()
+ } catch (e: NoSuchPaddingException) {
+ e.printStackTrace()
+ } catch (e: InvalidKeyException) {
+ e.printStackTrace()
+ } catch (e: BadPaddingException) {
+ e.printStackTrace()
+ } catch (e: IllegalBlockSizeException) {
+ e.printStackTrace()
+ }
+ return resultBytes
+ }
+
+ fun encryptDataByPublicKey(srcData: ByteArray, publicKey: PublicKey): String {
+ val resultBytes =
+ processData(srcData, publicKey, Cipher.ENCRYPT_MODE)
+ return Base64.encodeToString(resultBytes, Base64.DEFAULT)
+ }
+
+ fun keyStrToPublicKey(publicKeyStr: String?): PublicKey? {
+ var publicKey: PublicKey? = null
+ val keyBytes =
+ Base64.decode(publicKeyStr, Base64.DEFAULT)
+ val keySpec =
+ X509EncodedKeySpec(keyBytes)
+ try {
+ val keyFactory = KeyFactory.getInstance("RSA")
+ publicKey = keyFactory.generatePublic(keySpec)
+ } catch (e: NoSuchAlgorithmException) {
+ e.printStackTrace()
+ } catch (e: InvalidKeySpecException) {
+ e.printStackTrace()
+ }
+ return publicKey
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitFactory.kt b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitFactory.kt
new file mode 100644
index 0000000..0dd341f
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitFactory.kt
@@ -0,0 +1,48 @@
+package com.casic.birmm.inspect.utils.retrofit;
+
+import android.util.Log
+import com.casic.birmm.inspect.utils.Constant
+import com.casic.birmm.inspect.utils.SaveKeyValues
+import com.jakewharton.retrofit2.adapter.kotlin.coroutines.CoroutineCallAdapterFactory
+import okhttp3.OkHttpClient
+import okhttp3.logging.HttpLoggingInterceptor
+import org.jetbrains.annotations.NotNull
+import retrofit2.Retrofit
+import retrofit2.converter.gson.GsonConverterFactory
+import retrofit2.converter.scalars.ScalarsConverterFactory
+import java.util.concurrent.TimeUnit
+
+object RetrofitFactory {
+ private const val Tag = "RetrofitFactory"
+
+ private val client: OkHttpClient by lazy { createOKHttpClient() }
+
+ fun createRetrofit(clazz: Class): T {
+ val defaultValue = SaveKeyValues.getValue(
+ Constant.DEFAULT_SERVER_CONFIG,
+ "http://111.198.10.15:12204"
+ ) as String
+ return Retrofit.Builder()
+ .baseUrl(defaultValue)
+ .addConverterFactory(ScalarsConverterFactory.create()) //字符串转换器
+ .addConverterFactory(GsonConverterFactory.create()) //Gson转换器
+ .addCallAdapterFactory(CoroutineCallAdapterFactory.invoke()) //协程请求适配器
+ .client(client) //log拦截器
+ .build().create(clazz)
+ }
+
+ private fun createOKHttpClient(): OkHttpClient { //日志显示级别
+ val interceptor =
+ HttpLoggingInterceptor(object : HttpLoggingInterceptor.Logger {
+ override fun log(@NotNull message: String) {
+ Log.d(Tag, "log: $message")
+ }
+ })
+ interceptor.setLevel(HttpLoggingInterceptor.Level.BODY)
+ val builder = OkHttpClient.Builder()
+ .connectTimeout(30, TimeUnit.SECONDS)// 连接时间:30s超时
+ .readTimeout(10, TimeUnit.SECONDS)// 读取时间:10s超时
+ .writeTimeout(10, TimeUnit.SECONDS)// 写入时间:10s超时
+ return builder.addInterceptor(interceptor).build()
+ }
+}
diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt
new file mode 100644
index 0000000..41348ab
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt
@@ -0,0 +1,16 @@
+package com.casic.birmm.inspect.utils.retrofit
+
+import com.casic.birmm.inspect.model.PublicKeyBean
+import retrofit2.http.GET
+
+/**
+ * @JvmSuppressWildcards 用来注解类和方法,使得被标记元素的泛型参数不会被编译成通配符?
+ * */
+@JvmSuppressWildcards
+interface RetrofitService {
+ /**
+ * PublicKey校验
+ */
+ @GET("/pan-tilt/config/baseConfig")
+ suspend fun obtainPublicKeyAsync(): PublicKeyBean
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitServiceManager.kt
new file mode 100644
index 0000000..fe9869b
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitServiceManager.kt
@@ -0,0 +1,16 @@
+package com.casic.birmm.inspect.utils.retrofit
+
+import com.casic.birmm.inspect.model.PublicKeyBean
+
+
+object RetrofitServiceManager {
+
+ private val api by lazy { RetrofitFactory.createRetrofit(RetrofitService::class.java) }
+
+ /**
+ * 验证PublicKey
+ */
+ suspend fun authenticate(): PublicKeyBean {
+ return api.obtainPublicKeyAsync()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/view/GuideActivity.kt b/app/src/main/java/com/casic/birmm/inspect/view/GuideActivity.kt
new file mode 100644
index 0000000..a5578c3
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/view/GuideActivity.kt
@@ -0,0 +1,56 @@
+package com.casic.birmm.inspect.view
+
+import android.annotation.SuppressLint
+import android.content.Intent
+import android.os.CountDownTimer
+import android.view.ViewGroup.MarginLayoutParams
+import com.casic.birmm.inspect.R
+import com.casic.birmm.inspect.base.BaseActivity
+import com.qmuiteam.qmui.util.QMUIDisplayHelper
+import kotlinx.android.synthetic.main.activity_guide.*
+
+@SuppressLint("SetTextI18n")
+class GuideActivity : BaseActivity() {
+
+ private lateinit var countDownTimer: CountDownTimer
+
+ override fun initLayoutView(): Int = R.layout.activity_guide
+
+ override fun setupTopBarLayout() {
+
+ }
+
+ override fun initData() {
+ //根据不同设备状态栏高度设置"跳过"按钮的Margin值
+ val statusBarHeight = QMUIDisplayHelper.getStatusBarHeight(this)
+ val rightMargin = QMUIDisplayHelper.dp2px(this, 10)
+ if (skipButton.layoutParams is MarginLayoutParams) {
+ val params = skipButton.layoutParams as MarginLayoutParams
+ params.setMargins(skipButton.width, statusBarHeight, rightMargin, 0)
+ skipButton.requestLayout()
+ }
+
+ countDownTimer = object : CountDownTimer(4000, 1000) {
+ override fun onFinish() {
+ startLoginActivity()
+ }
+
+ override fun onTick(millisUntilFinished: Long) {
+ skipButton.text = "跳过\u3000${(millisUntilFinished / 1000)}s"
+ }
+ }
+ }
+
+ override fun initEvent() {
+ countDownTimer.start()
+ skipButton.setOnClickListener {
+ countDownTimer.cancel()
+ startLoginActivity()
+ }
+ }
+
+ fun startLoginActivity() {
+ startActivity(Intent(this, LoginActivity::class.java))
+ finish()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/view/LoginActivity.kt b/app/src/main/java/com/casic/birmm/inspect/view/LoginActivity.kt
new file mode 100644
index 0000000..bdb3f2d
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/view/LoginActivity.kt
@@ -0,0 +1,110 @@
+package com.casic.birmm.inspect.view
+
+import android.text.Editable
+import android.text.TextWatcher
+import android.util.Log
+import android.view.KeyEvent
+import android.view.inputmethod.EditorInfo
+import android.widget.EditText
+import android.widget.TextView
+import androidx.lifecycle.Observer
+import com.casic.birmm.inspect.R
+import com.casic.birmm.inspect.base.BaseViewModelActivity
+import com.casic.birmm.inspect.utils.*
+import com.casic.birmm.inspect.vm.AuthenticateViewModel
+import com.casic.birmm.inspect.widgets.InputDialog
+import kotlinx.android.synthetic.main.activity_login.*
+
+
+class LoginActivity : BaseViewModelActivity() {
+
+ companion object {
+ private const val Tag = "LoginActivity"
+ }
+
+ override fun createViewModelByClass(): Class? =
+ AuthenticateViewModel::class.java
+
+ override fun initLayoutView(): Int = R.layout.activity_login
+
+ override fun setupTopBarLayout() {
+
+ }
+
+ override fun initData() {
+ // 监听数据变化,从而显示数据在页面
+ viewModel.keyBean.observe(this, Observer {
+ if (it.isSuccess) {
+ Log.d(Tag, "${it.data!!.publicKey}")
+ val keyString = it.data!!.publicKey
+ val publicKey = RSAUtils.keyStrToPublicKey(keyString)
+ val account = userNameView.text.toString()
+ val userPassword = userPasswordView.text.toString()
+ } else {
+ OtherUtils.showTipsDialog(this, it.message!!, loginButton)
+ }
+ })
+ // 监听加载状态变化 从而改变页面
+ viewModel.loadState.observe(this, Observer {
+ when (it) {
+ is LoadState.Loading -> {
+ OtherUtils.showLoadingDialog(this, "登录中,请稍后")
+ }
+ else -> OtherUtils.dismissLoadingDialog()
+ }
+ })
+ }
+
+ override fun initEvent() {
+ val editText: EditText? = inputLayout.editText
+ editText?.addTextChangedListener(object : TextWatcher {
+ override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
+
+ }
+
+ override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
+
+ }
+
+ override fun afterTextChanged(s: Editable) {
+ if (s.toString().trim { it <= ' ' }.length > 12) {
+ inputLayout.error = "密码长度超出限制"
+ } else {
+ inputLayout.error = null
+ }
+ }
+ })
+ //点击输入法键盘"完成"
+ editText?.setOnEditorActionListener { _: TextView?, actionId: Int, _: KeyEvent? ->
+ if (actionId == EditorInfo.IME_ACTION_DONE) {
+ viewModel.obtainPublicKey()
+ return@setOnEditorActionListener true
+ }
+ false
+ }
+
+ loginButton.setChangeAlphaWhenPress(true)
+ loginButton.setOnClickListener {
+ viewModel.obtainPublicKey()
+ }
+
+ //修改服务器配置
+ changeServerConfigView.setOnClickListener {
+ val defaultValue = SaveKeyValues.getValue(
+ Constant.DEFAULT_SERVER_CONFIG,
+ "http://111.198.10.15:12204"
+ ) as String
+ InputDialog.Builder().setContext(this)
+ .setTitle("请输入后台服务器地址")
+ .setDefaultValue(defaultValue)
+ .setNegativeButton("取消")
+ .setPositiveButton("保存")
+ .setOnDialogClickListener(object : InputDialog.OnDialogButtonClickListener {
+ override fun onButtonClick(input: String) {
+ SaveKeyValues.putValue(Constant.DEFAULT_SERVER_CONFIG, input)
+ }
+ })
+ .build().show()
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/view/MainActivity.kt b/app/src/main/java/com/casic/birmm/inspect/view/MainActivity.kt
new file mode 100644
index 0000000..98b9e9a
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/view/MainActivity.kt
@@ -0,0 +1,21 @@
+package com.casic.birmm.inspect.view
+
+import com.casic.birmm.inspect.R
+import com.casic.birmm.inspect.base.BaseActivity
+
+class MainActivity : BaseActivity() {
+
+ override fun initLayoutView(): Int = R.layout.activity_main
+
+ override fun setupTopBarLayout() {
+
+ }
+
+ override fun initData() {
+
+ }
+
+ override fun initEvent() {
+
+ }
+}
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..35eb1dd
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
index 4ca4a9f..0002b4a 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -27,6 +27,12 @@
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
+
+ kotlin {
+ experimental {
+ coroutines 'enable'
+ }
+ }
}
dependencies {
@@ -47,19 +53,24 @@
implementation 'com.gyf.immersionbar:immersionbar:3.0.0'
//fragment快速实现
implementation 'com.gyf.immersionbar:immersionbar-components:3.0.0'
+ //MVVM
+ implementation "androidx.lifecycle:lifecycle-livedata:2.2.0"
+ implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0"
+ implementation "androidx.lifecycle:lifecycle-extensions:2.2.0"
+ //Kotlin协程
+ implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.0'
+ implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.0'
+ //返回值转换器
+ implementation 'com.jakewharton.retrofit:retrofit2-kotlin-coroutines-adapter:0.9.2'
+ implementation 'com.squareup.retrofit2:converter-scalars:2.0.0'
+ implementation 'com.squareup.retrofit2:converter-gson:2.8.1'
+ //okhttp3日志拦截器
+ implementation 'com.squareup.okhttp3:logging-interceptor:4.6.0'
- //MVP网络请求框架retrofit2+rxjava
- implementation 'io.reactivex:rxjava:1.3.8'
- implementation 'io.reactivex:rxandroid:1.2.1'
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.okhttp3:okhttp:4.6.0'
- implementation 'com.squareup.retrofit2:converter-gson:2.8.1'
- implementation 'com.squareup.retrofit2:adapter-rxjava:2.8.1'
- implementation 'com.squareup.okhttp3:logging-interceptor:4.6.0'
//官方Json解析库
implementation 'com.google.code.gson:gson:2.8.6'
- //Toast提示
- implementation 'com.sdsmdg.tastytoast:tastytoast:0.1.1'
//图片选择框架
implementation 'com.github.LuckSiege.PictureSelector:picture_library:v2.6.0'
//上拉加载下拉刷新
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 7096527..be35467 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -23,16 +23,16 @@
android:theme="@style/QMUI.Compat.NoActionBar"
android:usesCleartextTraffic="true"
tools:targetApi="m">
-
+
-
-
-
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/base/BaseActivity.kt b/app/src/main/java/com/casic/birmm/inspect/base/BaseActivity.kt
index aefdbb6..b6b9f53 100644
--- a/app/src/main/java/com/casic/birmm/inspect/base/BaseActivity.kt
+++ b/app/src/main/java/com/casic/birmm/inspect/base/BaseActivity.kt
@@ -4,6 +4,9 @@
import androidx.appcompat.app.AppCompatActivity
import com.qmuiteam.qmui.util.QMUIStatusBarHelper
+/**
+ * 无网络请求等普通页面的基础类
+ * */
abstract class BaseActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
diff --git a/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModel.kt b/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModel.kt
new file mode 100644
index 0000000..968b877
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModel.kt
@@ -0,0 +1,9 @@
+package com.casic.birmm.inspect.base
+
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.ViewModel
+import com.casic.birmm.inspect.utils.LoadState
+
+abstract class BaseViewModel : ViewModel() {
+ val loadState = MutableLiveData()
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModelActivity.kt b/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModelActivity.kt
new file mode 100644
index 0000000..ee93c84
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModelActivity.kt
@@ -0,0 +1,61 @@
+package com.casic.birmm.inspect.base
+
+import android.os.Bundle
+import androidx.appcompat.app.AppCompatActivity
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.ViewModelProvider
+import com.qmuiteam.qmui.util.QMUIStatusBarHelper
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.MainScope
+import kotlinx.coroutines.cancel
+
+/**
+ * MV ViewModel 架构
+ *
+ * 有网络请求等普通页面的基础类
+ */
+abstract class BaseViewModelActivity : AppCompatActivity(),
+ CoroutineScope by MainScope() {
+
+ protected lateinit var viewModel: VM
+
+ /**
+ * 初始化xml布局
+ */
+ protected abstract fun initLayoutView(): Int
+
+ /**
+ * 特定页面定制沉浸式状态栏
+ */
+ protected abstract fun setupTopBarLayout()
+
+ /**
+ * 初始化默认数据
+ */
+ abstract fun initData()
+
+ /**
+ * 初始化业务逻辑
+ */
+ abstract fun initEvent()
+
+ /**
+ * 提供ViewModel类
+ */
+ protected abstract fun createViewModelByClass(): Class?
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(initLayoutView())
+ createViewModelByClass()?.let { viewModel = ViewModelProvider(this).get(it) }
+ QMUIStatusBarHelper.translucent(this) //沉浸式状态栏
+ setupTopBarLayout()
+ initData()
+ initEvent()
+ }
+
+ override fun onDestroy() {
+ cancel()// 取消协程
+ super.onDestroy()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/model/PublicKeyBean.kt b/app/src/main/java/com/casic/birmm/inspect/model/PublicKeyBean.kt
new file mode 100644
index 0000000..25c5436
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/model/PublicKeyBean.kt
@@ -0,0 +1,18 @@
+package com.casic.birmm.inspect.model
+
+/**
+ * PublicKey 登录校验Key
+ */
+class PublicKeyBean {
+ var code = 0
+ var data: DataBean? = null
+ var message: String? = null
+ var isSuccess = false
+
+ class DataBean {
+ var isAppKaptcha = false
+ var isKaptcha = false
+ var publicKey: String? = null
+ var sid: String? = null
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/ui/GuideActivity.kt b/app/src/main/java/com/casic/birmm/inspect/ui/GuideActivity.kt
deleted file mode 100644
index ddc160a..0000000
--- a/app/src/main/java/com/casic/birmm/inspect/ui/GuideActivity.kt
+++ /dev/null
@@ -1,56 +0,0 @@
-package com.casic.birmm.inspect.ui
-
-import android.annotation.SuppressLint
-import android.content.Intent
-import android.os.CountDownTimer
-import android.view.ViewGroup.MarginLayoutParams
-import com.casic.birmm.inspect.R
-import com.casic.birmm.inspect.base.BaseActivity
-import com.qmuiteam.qmui.util.QMUIDisplayHelper
-import kotlinx.android.synthetic.main.activity_guide.*
-
-@SuppressLint("SetTextI18n")
-class GuideActivity : BaseActivity() {
-
- private lateinit var countDownTimer: CountDownTimer
-
- override fun initLayoutView(): Int = R.layout.activity_guide
-
- override fun setupTopBarLayout() {
-
- }
-
- override fun initData() {
- //根据不同设备状态栏高度设置"跳过"按钮的Margin值
- val statusBarHeight = QMUIDisplayHelper.getStatusBarHeight(this)
- val rightMargin = QMUIDisplayHelper.dp2px(this, 10)
- if (skipButton.layoutParams is MarginLayoutParams) {
- val params = skipButton.layoutParams as MarginLayoutParams
- params.setMargins(skipButton.width, statusBarHeight, rightMargin, 0)
- skipButton.requestLayout()
- }
-
- countDownTimer = object : CountDownTimer(4000, 1000) {
- override fun onFinish() {
- startLoginActivity()
- }
-
- override fun onTick(millisUntilFinished: Long) {
- skipButton.text = "跳过\u3000${(millisUntilFinished / 1000)}s"
- }
- }
- }
-
- override fun initEvent() {
- countDownTimer.start()
- skipButton.setOnClickListener {
- countDownTimer.cancel()
- startLoginActivity()
- }
- }
-
- fun startLoginActivity() {
- startActivity(Intent(this, LoginActivity::class.java))
- finish()
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/ui/LoginActivity.kt b/app/src/main/java/com/casic/birmm/inspect/ui/LoginActivity.kt
deleted file mode 100644
index 6ef4548..0000000
--- a/app/src/main/java/com/casic/birmm/inspect/ui/LoginActivity.kt
+++ /dev/null
@@ -1,81 +0,0 @@
-package com.casic.birmm.inspect.ui
-
-import android.text.Editable
-import android.text.TextWatcher
-import android.view.KeyEvent
-import android.view.inputmethod.EditorInfo
-import android.widget.EditText
-import android.widget.TextView
-import com.casic.birmm.inspect.R
-import com.casic.birmm.inspect.base.BaseActivity
-import com.casic.birmm.inspect.utils.Constant
-import com.casic.birmm.inspect.utils.SaveKeyValues
-import com.casic.birmm.inspect.widgets.InputDialog
-import kotlinx.android.synthetic.main.activity_login.*
-
-
-class LoginActivity : BaseActivity() {
-
- companion object {
- private const val Tag = "LoginActivity"
- }
-
- override fun initLayoutView(): Int = R.layout.activity_login
-
- override fun setupTopBarLayout() {
-
- }
-
- override fun initData() {
-
- }
-
- override fun initEvent() {
- loginButton.setChangeAlphaWhenPress(true)
- val editText: EditText? = inputLayout.editText
- editText?.addTextChangedListener(object : TextWatcher {
- override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
-
- }
-
- override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
-
- }
-
- override fun afterTextChanged(s: Editable) {
- if (s.toString().trim { it <= ' ' }.length > 12) {
- inputLayout.error = "密码长度超出限制"
- } else {
- inputLayout.error = null
- }
- }
- })
- //点击输入法键盘"完成"
- editText?.setOnEditorActionListener { _: TextView?, actionId: Int, _: KeyEvent? ->
- if (actionId == EditorInfo.IME_ACTION_DONE) {
-// authenticatePresenter.onReadyRetrofitRequest()
- return@setOnEditorActionListener true
- }
- false
- }
-
- //修改服务器配置
- changeServerConfigView.setOnClickListener {
- val defaultValue = SaveKeyValues.getValue(
- Constant.DEFAULT_SERVER_CONFIG,
- "http://139.198.6.177:8093/"
- ) as String
- InputDialog.Builder().setContext(this)
- .setTitle("请输入后台服务器地址")
- .setDefaultValue(defaultValue)
- .setNegativeButton("取消")
- .setPositiveButton("保存")
- .setOnDialogClickListener(object : InputDialog.OnDialogButtonClickListener {
- override fun onButtonClick(input: String) {
- SaveKeyValues.putValue(Constant.DEFAULT_SERVER_CONFIG, input)
- }
- })
- .build().show()
- }
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/ui/MainActivity.kt b/app/src/main/java/com/casic/birmm/inspect/ui/MainActivity.kt
deleted file mode 100644
index 0e97af7..0000000
--- a/app/src/main/java/com/casic/birmm/inspect/ui/MainActivity.kt
+++ /dev/null
@@ -1,21 +0,0 @@
-package com.casic.birmm.inspect.ui
-
-import com.casic.birmm.inspect.R
-import com.casic.birmm.inspect.base.BaseActivity
-
-class MainActivity : BaseActivity() {
-
- override fun initLayoutView(): Int = R.layout.activity_main
-
- override fun setupTopBarLayout() {
-
- }
-
- override fun initData() {
-
- }
-
- override fun initEvent() {
-
- }
-}
diff --git a/app/src/main/java/com/casic/birmm/inspect/ui/PermissionActivity.kt b/app/src/main/java/com/casic/birmm/inspect/ui/PermissionActivity.kt
deleted file mode 100644
index 21fbba2..0000000
--- a/app/src/main/java/com/casic/birmm/inspect/ui/PermissionActivity.kt
+++ /dev/null
@@ -1,58 +0,0 @@
-package com.casic.birmm.inspect.ui
-
-import android.content.Intent
-import android.os.Build
-import android.os.Bundle
-import android.util.Log
-import androidx.appcompat.app.AppCompatActivity
-import com.casic.birmm.inspect.utils.Constant
-import pub.devrel.easypermissions.EasyPermissions
-import pub.devrel.easypermissions.EasyPermissions.PermissionCallbacks
-
-class PermissionActivity : AppCompatActivity(), PermissionCallbacks {
-
- companion object {
- private const val TAG = "PermissionActivity"
- }
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- //判断是否有权限,如果版本大于5.1才需要判断(即6.0以上),其他则不需要判断。
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
- if (EasyPermissions.hasPermissions(this, *Constant.USER_PERMISSIONS)) {
- startGuideActivity()
- } else {
- EasyPermissions.requestPermissions(
- this,
- "需要获取相关权限",
- Constant.PERMISSIONS_CODE,
- *Constant.USER_PERMISSIONS
- )
- }
- } else {
- startGuideActivity()
- }
- }
-
- private fun startGuideActivity() {
- startActivity(Intent(this, GuideActivity::class.java))
- finish()
- }
-
- override fun onRequestPermissionsResult(
- requestCode: Int,
- permissions: Array,
- grantResults: IntArray
- ) {
- super.onRequestPermissionsResult(requestCode, permissions, grantResults)
- EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this)
- }
-
- override fun onPermissionsGranted(requestCode: Int, perms: List) {
- startGuideActivity()
- }
-
- override fun onPermissionsDenied(requestCode: Int, perms: List) {
- Log.e(TAG, "onPermissionsDenied: $perms")
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/ExtensionViewModel.kt b/app/src/main/java/com/casic/birmm/inspect/utils/ExtensionViewModel.kt
new file mode 100644
index 0000000..2259965
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/utils/ExtensionViewModel.kt
@@ -0,0 +1,33 @@
+package com.casic.birmm.inspect.utils
+
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import kotlinx.coroutines.CoroutineExceptionHandler
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.launch
+
+/**
+ * ViewModel扩展方法:启动协程
+ * @param block 协程逻辑
+ * @param onError 错误回调方法
+ * @param onComplete 完成回调方法
+ */
+fun ViewModel.launch(
+ block: suspend CoroutineScope.() -> Unit,
+ onError: (e: Throwable) -> Unit = {},
+ onComplete: () -> Unit = {}
+) {
+ viewModelScope.launch(
+ CoroutineExceptionHandler { _, throwable ->
+ run {
+ onError(throwable)
+ }
+ }
+ ) {
+ try {
+ block.invoke(this)
+ } finally {
+ onComplete()
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/LoadState.kt b/app/src/main/java/com/casic/birmm/inspect/utils/LoadState.kt
new file mode 100644
index 0000000..9c83224
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/utils/LoadState.kt
@@ -0,0 +1,22 @@
+package com.casic.birmm.inspect.utils
+
+/**
+ * 加载状态
+ * sealed 关键字表示此类仅内部继承
+ */
+sealed class LoadState(val msg: String) {
+ /**
+ * 加载中
+ */
+ class Loading(msg: String = "") : LoadState(msg)
+
+ /**
+ * 成功
+ */
+ class Success(msg: String = "") : LoadState(msg)
+
+ /**
+ * 失败
+ */
+ class Fail(msg: String = "") : LoadState(msg)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/OtherUtils.kt b/app/src/main/java/com/casic/birmm/inspect/utils/OtherUtils.kt
index 4c38241..ff63747 100644
--- a/app/src/main/java/com/casic/birmm/inspect/utils/OtherUtils.kt
+++ b/app/src/main/java/com/casic/birmm/inspect/utils/OtherUtils.kt
@@ -6,6 +6,8 @@
object OtherUtils {
+ private var loadingDialog: QMUITipDialog? = null
+
//替换Toast
fun showTipsDialog(context: Context, message: String, view: View) {
val tipDialog = QMUITipDialog.Builder(context)
@@ -16,4 +18,20 @@
tipDialog.dismiss()
}, 2000)
}
+
+ fun showLoadingDialog(context: Context?, message: String?) {
+ loadingDialog = QMUITipDialog.Builder(context)
+ .setIconType(QMUITipDialog.Builder.ICON_TYPE_LOADING)
+ .setTipWord(message)
+ .create()
+ loadingDialog!!.show()
+ }
+
+ fun dismissLoadingDialog() {
+ if (loadingDialog != null) {
+ if (loadingDialog!!.isShowing) {
+ loadingDialog!!.dismiss()
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/RSAUtils.kt b/app/src/main/java/com/casic/birmm/inspect/utils/RSAUtils.kt
new file mode 100644
index 0000000..b93983b
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/utils/RSAUtils.kt
@@ -0,0 +1,61 @@
+package com.casic.birmm.inspect.utils
+
+import android.util.Base64
+import java.security.*
+import java.security.spec.InvalidKeySpecException
+import java.security.spec.X509EncodedKeySpec
+import javax.crypto.BadPaddingException
+import javax.crypto.Cipher
+import javax.crypto.IllegalBlockSizeException
+import javax.crypto.NoSuchPaddingException
+
+/**
+ * Created by W530 on 2019/9/26.
+ */
+object RSAUtils {
+ //构建Cipher实例时所传入的的字符串,默认为"RSA/NONE/PKCS1Padding"
+ private fun processData(srcData: ByteArray, key: Key, mode: Int): ByteArray? { //用来保存处理结果
+ var resultBytes: ByteArray? = null
+ try { //获取Cipher实例
+ val cipher = Cipher.getInstance("RSA/None/PKCS1Padding")
+ //初始化Cipher,mode指定是加密还是解密,key为公钥或私钥
+ cipher.init(mode, key)
+ //处理数据
+ resultBytes = cipher.doFinal(srcData)
+ } catch (e: NoSuchAlgorithmException) {
+ e.printStackTrace()
+ } catch (e: NoSuchPaddingException) {
+ e.printStackTrace()
+ } catch (e: InvalidKeyException) {
+ e.printStackTrace()
+ } catch (e: BadPaddingException) {
+ e.printStackTrace()
+ } catch (e: IllegalBlockSizeException) {
+ e.printStackTrace()
+ }
+ return resultBytes
+ }
+
+ fun encryptDataByPublicKey(srcData: ByteArray, publicKey: PublicKey): String {
+ val resultBytes =
+ processData(srcData, publicKey, Cipher.ENCRYPT_MODE)
+ return Base64.encodeToString(resultBytes, Base64.DEFAULT)
+ }
+
+ fun keyStrToPublicKey(publicKeyStr: String?): PublicKey? {
+ var publicKey: PublicKey? = null
+ val keyBytes =
+ Base64.decode(publicKeyStr, Base64.DEFAULT)
+ val keySpec =
+ X509EncodedKeySpec(keyBytes)
+ try {
+ val keyFactory = KeyFactory.getInstance("RSA")
+ publicKey = keyFactory.generatePublic(keySpec)
+ } catch (e: NoSuchAlgorithmException) {
+ e.printStackTrace()
+ } catch (e: InvalidKeySpecException) {
+ e.printStackTrace()
+ }
+ return publicKey
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitFactory.kt b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitFactory.kt
new file mode 100644
index 0000000..0dd341f
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitFactory.kt
@@ -0,0 +1,48 @@
+package com.casic.birmm.inspect.utils.retrofit;
+
+import android.util.Log
+import com.casic.birmm.inspect.utils.Constant
+import com.casic.birmm.inspect.utils.SaveKeyValues
+import com.jakewharton.retrofit2.adapter.kotlin.coroutines.CoroutineCallAdapterFactory
+import okhttp3.OkHttpClient
+import okhttp3.logging.HttpLoggingInterceptor
+import org.jetbrains.annotations.NotNull
+import retrofit2.Retrofit
+import retrofit2.converter.gson.GsonConverterFactory
+import retrofit2.converter.scalars.ScalarsConverterFactory
+import java.util.concurrent.TimeUnit
+
+object RetrofitFactory {
+ private const val Tag = "RetrofitFactory"
+
+ private val client: OkHttpClient by lazy { createOKHttpClient() }
+
+ fun createRetrofit(clazz: Class): T {
+ val defaultValue = SaveKeyValues.getValue(
+ Constant.DEFAULT_SERVER_CONFIG,
+ "http://111.198.10.15:12204"
+ ) as String
+ return Retrofit.Builder()
+ .baseUrl(defaultValue)
+ .addConverterFactory(ScalarsConverterFactory.create()) //字符串转换器
+ .addConverterFactory(GsonConverterFactory.create()) //Gson转换器
+ .addCallAdapterFactory(CoroutineCallAdapterFactory.invoke()) //协程请求适配器
+ .client(client) //log拦截器
+ .build().create(clazz)
+ }
+
+ private fun createOKHttpClient(): OkHttpClient { //日志显示级别
+ val interceptor =
+ HttpLoggingInterceptor(object : HttpLoggingInterceptor.Logger {
+ override fun log(@NotNull message: String) {
+ Log.d(Tag, "log: $message")
+ }
+ })
+ interceptor.setLevel(HttpLoggingInterceptor.Level.BODY)
+ val builder = OkHttpClient.Builder()
+ .connectTimeout(30, TimeUnit.SECONDS)// 连接时间:30s超时
+ .readTimeout(10, TimeUnit.SECONDS)// 读取时间:10s超时
+ .writeTimeout(10, TimeUnit.SECONDS)// 写入时间:10s超时
+ return builder.addInterceptor(interceptor).build()
+ }
+}
diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt
new file mode 100644
index 0000000..41348ab
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt
@@ -0,0 +1,16 @@
+package com.casic.birmm.inspect.utils.retrofit
+
+import com.casic.birmm.inspect.model.PublicKeyBean
+import retrofit2.http.GET
+
+/**
+ * @JvmSuppressWildcards 用来注解类和方法,使得被标记元素的泛型参数不会被编译成通配符?
+ * */
+@JvmSuppressWildcards
+interface RetrofitService {
+ /**
+ * PublicKey校验
+ */
+ @GET("/pan-tilt/config/baseConfig")
+ suspend fun obtainPublicKeyAsync(): PublicKeyBean
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitServiceManager.kt
new file mode 100644
index 0000000..fe9869b
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitServiceManager.kt
@@ -0,0 +1,16 @@
+package com.casic.birmm.inspect.utils.retrofit
+
+import com.casic.birmm.inspect.model.PublicKeyBean
+
+
+object RetrofitServiceManager {
+
+ private val api by lazy { RetrofitFactory.createRetrofit(RetrofitService::class.java) }
+
+ /**
+ * 验证PublicKey
+ */
+ suspend fun authenticate(): PublicKeyBean {
+ return api.obtainPublicKeyAsync()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/view/GuideActivity.kt b/app/src/main/java/com/casic/birmm/inspect/view/GuideActivity.kt
new file mode 100644
index 0000000..a5578c3
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/view/GuideActivity.kt
@@ -0,0 +1,56 @@
+package com.casic.birmm.inspect.view
+
+import android.annotation.SuppressLint
+import android.content.Intent
+import android.os.CountDownTimer
+import android.view.ViewGroup.MarginLayoutParams
+import com.casic.birmm.inspect.R
+import com.casic.birmm.inspect.base.BaseActivity
+import com.qmuiteam.qmui.util.QMUIDisplayHelper
+import kotlinx.android.synthetic.main.activity_guide.*
+
+@SuppressLint("SetTextI18n")
+class GuideActivity : BaseActivity() {
+
+ private lateinit var countDownTimer: CountDownTimer
+
+ override fun initLayoutView(): Int = R.layout.activity_guide
+
+ override fun setupTopBarLayout() {
+
+ }
+
+ override fun initData() {
+ //根据不同设备状态栏高度设置"跳过"按钮的Margin值
+ val statusBarHeight = QMUIDisplayHelper.getStatusBarHeight(this)
+ val rightMargin = QMUIDisplayHelper.dp2px(this, 10)
+ if (skipButton.layoutParams is MarginLayoutParams) {
+ val params = skipButton.layoutParams as MarginLayoutParams
+ params.setMargins(skipButton.width, statusBarHeight, rightMargin, 0)
+ skipButton.requestLayout()
+ }
+
+ countDownTimer = object : CountDownTimer(4000, 1000) {
+ override fun onFinish() {
+ startLoginActivity()
+ }
+
+ override fun onTick(millisUntilFinished: Long) {
+ skipButton.text = "跳过\u3000${(millisUntilFinished / 1000)}s"
+ }
+ }
+ }
+
+ override fun initEvent() {
+ countDownTimer.start()
+ skipButton.setOnClickListener {
+ countDownTimer.cancel()
+ startLoginActivity()
+ }
+ }
+
+ fun startLoginActivity() {
+ startActivity(Intent(this, LoginActivity::class.java))
+ finish()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/view/LoginActivity.kt b/app/src/main/java/com/casic/birmm/inspect/view/LoginActivity.kt
new file mode 100644
index 0000000..bdb3f2d
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/view/LoginActivity.kt
@@ -0,0 +1,110 @@
+package com.casic.birmm.inspect.view
+
+import android.text.Editable
+import android.text.TextWatcher
+import android.util.Log
+import android.view.KeyEvent
+import android.view.inputmethod.EditorInfo
+import android.widget.EditText
+import android.widget.TextView
+import androidx.lifecycle.Observer
+import com.casic.birmm.inspect.R
+import com.casic.birmm.inspect.base.BaseViewModelActivity
+import com.casic.birmm.inspect.utils.*
+import com.casic.birmm.inspect.vm.AuthenticateViewModel
+import com.casic.birmm.inspect.widgets.InputDialog
+import kotlinx.android.synthetic.main.activity_login.*
+
+
+class LoginActivity : BaseViewModelActivity() {
+
+ companion object {
+ private const val Tag = "LoginActivity"
+ }
+
+ override fun createViewModelByClass(): Class? =
+ AuthenticateViewModel::class.java
+
+ override fun initLayoutView(): Int = R.layout.activity_login
+
+ override fun setupTopBarLayout() {
+
+ }
+
+ override fun initData() {
+ // 监听数据变化,从而显示数据在页面
+ viewModel.keyBean.observe(this, Observer {
+ if (it.isSuccess) {
+ Log.d(Tag, "${it.data!!.publicKey}")
+ val keyString = it.data!!.publicKey
+ val publicKey = RSAUtils.keyStrToPublicKey(keyString)
+ val account = userNameView.text.toString()
+ val userPassword = userPasswordView.text.toString()
+ } else {
+ OtherUtils.showTipsDialog(this, it.message!!, loginButton)
+ }
+ })
+ // 监听加载状态变化 从而改变页面
+ viewModel.loadState.observe(this, Observer {
+ when (it) {
+ is LoadState.Loading -> {
+ OtherUtils.showLoadingDialog(this, "登录中,请稍后")
+ }
+ else -> OtherUtils.dismissLoadingDialog()
+ }
+ })
+ }
+
+ override fun initEvent() {
+ val editText: EditText? = inputLayout.editText
+ editText?.addTextChangedListener(object : TextWatcher {
+ override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
+
+ }
+
+ override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
+
+ }
+
+ override fun afterTextChanged(s: Editable) {
+ if (s.toString().trim { it <= ' ' }.length > 12) {
+ inputLayout.error = "密码长度超出限制"
+ } else {
+ inputLayout.error = null
+ }
+ }
+ })
+ //点击输入法键盘"完成"
+ editText?.setOnEditorActionListener { _: TextView?, actionId: Int, _: KeyEvent? ->
+ if (actionId == EditorInfo.IME_ACTION_DONE) {
+ viewModel.obtainPublicKey()
+ return@setOnEditorActionListener true
+ }
+ false
+ }
+
+ loginButton.setChangeAlphaWhenPress(true)
+ loginButton.setOnClickListener {
+ viewModel.obtainPublicKey()
+ }
+
+ //修改服务器配置
+ changeServerConfigView.setOnClickListener {
+ val defaultValue = SaveKeyValues.getValue(
+ Constant.DEFAULT_SERVER_CONFIG,
+ "http://111.198.10.15:12204"
+ ) as String
+ InputDialog.Builder().setContext(this)
+ .setTitle("请输入后台服务器地址")
+ .setDefaultValue(defaultValue)
+ .setNegativeButton("取消")
+ .setPositiveButton("保存")
+ .setOnDialogClickListener(object : InputDialog.OnDialogButtonClickListener {
+ override fun onButtonClick(input: String) {
+ SaveKeyValues.putValue(Constant.DEFAULT_SERVER_CONFIG, input)
+ }
+ })
+ .build().show()
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/view/MainActivity.kt b/app/src/main/java/com/casic/birmm/inspect/view/MainActivity.kt
new file mode 100644
index 0000000..98b9e9a
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/view/MainActivity.kt
@@ -0,0 +1,21 @@
+package com.casic.birmm.inspect.view
+
+import com.casic.birmm.inspect.R
+import com.casic.birmm.inspect.base.BaseActivity
+
+class MainActivity : BaseActivity() {
+
+ override fun initLayoutView(): Int = R.layout.activity_main
+
+ override fun setupTopBarLayout() {
+
+ }
+
+ override fun initData() {
+
+ }
+
+ override fun initEvent() {
+
+ }
+}
diff --git a/app/src/main/java/com/casic/birmm/inspect/view/PermissionActivity.kt b/app/src/main/java/com/casic/birmm/inspect/view/PermissionActivity.kt
new file mode 100644
index 0000000..07f48a5
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/view/PermissionActivity.kt
@@ -0,0 +1,53 @@
+package com.casic.birmm.inspect.view
+
+import android.content.Intent
+import android.os.Build
+import android.os.Bundle
+import androidx.appcompat.app.AppCompatActivity
+import com.casic.birmm.inspect.utils.Constant
+import pub.devrel.easypermissions.EasyPermissions
+import pub.devrel.easypermissions.EasyPermissions.PermissionCallbacks
+
+class PermissionActivity : AppCompatActivity(), PermissionCallbacks {
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ //判断是否有权限,如果版本大于5.1才需要判断(即6.0以上),其他则不需要判断。
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ if (EasyPermissions.hasPermissions(this, *Constant.USER_PERMISSIONS)) {
+ startGuideActivity()
+ } else {
+ EasyPermissions.requestPermissions(
+ this,
+ "需要获取相关权限",
+ Constant.PERMISSIONS_CODE,
+ *Constant.USER_PERMISSIONS
+ )
+ }
+ } else {
+ startGuideActivity()
+ }
+ }
+
+ private fun startGuideActivity() {
+ startActivity(Intent(this, GuideActivity::class.java))
+ finish()
+ }
+
+ override fun onRequestPermissionsResult(
+ requestCode: Int,
+ permissions: Array,
+ grantResults: IntArray
+ ) {
+ super.onRequestPermissionsResult(requestCode, permissions, grantResults)
+ EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this)
+ }
+
+ override fun onPermissionsGranted(requestCode: Int, perms: List) {
+ startGuideActivity()
+ }
+
+ override fun onPermissionsDenied(requestCode: Int, perms: List) {
+
+ }
+}
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..35eb1dd
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
index 4ca4a9f..0002b4a 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -27,6 +27,12 @@
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
+
+ kotlin {
+ experimental {
+ coroutines 'enable'
+ }
+ }
}
dependencies {
@@ -47,19 +53,24 @@
implementation 'com.gyf.immersionbar:immersionbar:3.0.0'
//fragment快速实现
implementation 'com.gyf.immersionbar:immersionbar-components:3.0.0'
+ //MVVM
+ implementation "androidx.lifecycle:lifecycle-livedata:2.2.0"
+ implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0"
+ implementation "androidx.lifecycle:lifecycle-extensions:2.2.0"
+ //Kotlin协程
+ implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.0'
+ implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.0'
+ //返回值转换器
+ implementation 'com.jakewharton.retrofit:retrofit2-kotlin-coroutines-adapter:0.9.2'
+ implementation 'com.squareup.retrofit2:converter-scalars:2.0.0'
+ implementation 'com.squareup.retrofit2:converter-gson:2.8.1'
+ //okhttp3日志拦截器
+ implementation 'com.squareup.okhttp3:logging-interceptor:4.6.0'
- //MVP网络请求框架retrofit2+rxjava
- implementation 'io.reactivex:rxjava:1.3.8'
- implementation 'io.reactivex:rxandroid:1.2.1'
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.okhttp3:okhttp:4.6.0'
- implementation 'com.squareup.retrofit2:converter-gson:2.8.1'
- implementation 'com.squareup.retrofit2:adapter-rxjava:2.8.1'
- implementation 'com.squareup.okhttp3:logging-interceptor:4.6.0'
//官方Json解析库
implementation 'com.google.code.gson:gson:2.8.6'
- //Toast提示
- implementation 'com.sdsmdg.tastytoast:tastytoast:0.1.1'
//图片选择框架
implementation 'com.github.LuckSiege.PictureSelector:picture_library:v2.6.0'
//上拉加载下拉刷新
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 7096527..be35467 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -23,16 +23,16 @@
android:theme="@style/QMUI.Compat.NoActionBar"
android:usesCleartextTraffic="true"
tools:targetApi="m">
-
+
-
-
-
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/base/BaseActivity.kt b/app/src/main/java/com/casic/birmm/inspect/base/BaseActivity.kt
index aefdbb6..b6b9f53 100644
--- a/app/src/main/java/com/casic/birmm/inspect/base/BaseActivity.kt
+++ b/app/src/main/java/com/casic/birmm/inspect/base/BaseActivity.kt
@@ -4,6 +4,9 @@
import androidx.appcompat.app.AppCompatActivity
import com.qmuiteam.qmui.util.QMUIStatusBarHelper
+/**
+ * 无网络请求等普通页面的基础类
+ * */
abstract class BaseActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
diff --git a/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModel.kt b/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModel.kt
new file mode 100644
index 0000000..968b877
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModel.kt
@@ -0,0 +1,9 @@
+package com.casic.birmm.inspect.base
+
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.ViewModel
+import com.casic.birmm.inspect.utils.LoadState
+
+abstract class BaseViewModel : ViewModel() {
+ val loadState = MutableLiveData()
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModelActivity.kt b/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModelActivity.kt
new file mode 100644
index 0000000..ee93c84
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/base/BaseViewModelActivity.kt
@@ -0,0 +1,61 @@
+package com.casic.birmm.inspect.base
+
+import android.os.Bundle
+import androidx.appcompat.app.AppCompatActivity
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.ViewModelProvider
+import com.qmuiteam.qmui.util.QMUIStatusBarHelper
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.MainScope
+import kotlinx.coroutines.cancel
+
+/**
+ * MV ViewModel 架构
+ *
+ * 有网络请求等普通页面的基础类
+ */
+abstract class BaseViewModelActivity : AppCompatActivity(),
+ CoroutineScope by MainScope() {
+
+ protected lateinit var viewModel: VM
+
+ /**
+ * 初始化xml布局
+ */
+ protected abstract fun initLayoutView(): Int
+
+ /**
+ * 特定页面定制沉浸式状态栏
+ */
+ protected abstract fun setupTopBarLayout()
+
+ /**
+ * 初始化默认数据
+ */
+ abstract fun initData()
+
+ /**
+ * 初始化业务逻辑
+ */
+ abstract fun initEvent()
+
+ /**
+ * 提供ViewModel类
+ */
+ protected abstract fun createViewModelByClass(): Class?
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(initLayoutView())
+ createViewModelByClass()?.let { viewModel = ViewModelProvider(this).get(it) }
+ QMUIStatusBarHelper.translucent(this) //沉浸式状态栏
+ setupTopBarLayout()
+ initData()
+ initEvent()
+ }
+
+ override fun onDestroy() {
+ cancel()// 取消协程
+ super.onDestroy()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/model/PublicKeyBean.kt b/app/src/main/java/com/casic/birmm/inspect/model/PublicKeyBean.kt
new file mode 100644
index 0000000..25c5436
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/model/PublicKeyBean.kt
@@ -0,0 +1,18 @@
+package com.casic.birmm.inspect.model
+
+/**
+ * PublicKey 登录校验Key
+ */
+class PublicKeyBean {
+ var code = 0
+ var data: DataBean? = null
+ var message: String? = null
+ var isSuccess = false
+
+ class DataBean {
+ var isAppKaptcha = false
+ var isKaptcha = false
+ var publicKey: String? = null
+ var sid: String? = null
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/ui/GuideActivity.kt b/app/src/main/java/com/casic/birmm/inspect/ui/GuideActivity.kt
deleted file mode 100644
index ddc160a..0000000
--- a/app/src/main/java/com/casic/birmm/inspect/ui/GuideActivity.kt
+++ /dev/null
@@ -1,56 +0,0 @@
-package com.casic.birmm.inspect.ui
-
-import android.annotation.SuppressLint
-import android.content.Intent
-import android.os.CountDownTimer
-import android.view.ViewGroup.MarginLayoutParams
-import com.casic.birmm.inspect.R
-import com.casic.birmm.inspect.base.BaseActivity
-import com.qmuiteam.qmui.util.QMUIDisplayHelper
-import kotlinx.android.synthetic.main.activity_guide.*
-
-@SuppressLint("SetTextI18n")
-class GuideActivity : BaseActivity() {
-
- private lateinit var countDownTimer: CountDownTimer
-
- override fun initLayoutView(): Int = R.layout.activity_guide
-
- override fun setupTopBarLayout() {
-
- }
-
- override fun initData() {
- //根据不同设备状态栏高度设置"跳过"按钮的Margin值
- val statusBarHeight = QMUIDisplayHelper.getStatusBarHeight(this)
- val rightMargin = QMUIDisplayHelper.dp2px(this, 10)
- if (skipButton.layoutParams is MarginLayoutParams) {
- val params = skipButton.layoutParams as MarginLayoutParams
- params.setMargins(skipButton.width, statusBarHeight, rightMargin, 0)
- skipButton.requestLayout()
- }
-
- countDownTimer = object : CountDownTimer(4000, 1000) {
- override fun onFinish() {
- startLoginActivity()
- }
-
- override fun onTick(millisUntilFinished: Long) {
- skipButton.text = "跳过\u3000${(millisUntilFinished / 1000)}s"
- }
- }
- }
-
- override fun initEvent() {
- countDownTimer.start()
- skipButton.setOnClickListener {
- countDownTimer.cancel()
- startLoginActivity()
- }
- }
-
- fun startLoginActivity() {
- startActivity(Intent(this, LoginActivity::class.java))
- finish()
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/ui/LoginActivity.kt b/app/src/main/java/com/casic/birmm/inspect/ui/LoginActivity.kt
deleted file mode 100644
index 6ef4548..0000000
--- a/app/src/main/java/com/casic/birmm/inspect/ui/LoginActivity.kt
+++ /dev/null
@@ -1,81 +0,0 @@
-package com.casic.birmm.inspect.ui
-
-import android.text.Editable
-import android.text.TextWatcher
-import android.view.KeyEvent
-import android.view.inputmethod.EditorInfo
-import android.widget.EditText
-import android.widget.TextView
-import com.casic.birmm.inspect.R
-import com.casic.birmm.inspect.base.BaseActivity
-import com.casic.birmm.inspect.utils.Constant
-import com.casic.birmm.inspect.utils.SaveKeyValues
-import com.casic.birmm.inspect.widgets.InputDialog
-import kotlinx.android.synthetic.main.activity_login.*
-
-
-class LoginActivity : BaseActivity() {
-
- companion object {
- private const val Tag = "LoginActivity"
- }
-
- override fun initLayoutView(): Int = R.layout.activity_login
-
- override fun setupTopBarLayout() {
-
- }
-
- override fun initData() {
-
- }
-
- override fun initEvent() {
- loginButton.setChangeAlphaWhenPress(true)
- val editText: EditText? = inputLayout.editText
- editText?.addTextChangedListener(object : TextWatcher {
- override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
-
- }
-
- override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
-
- }
-
- override fun afterTextChanged(s: Editable) {
- if (s.toString().trim { it <= ' ' }.length > 12) {
- inputLayout.error = "密码长度超出限制"
- } else {
- inputLayout.error = null
- }
- }
- })
- //点击输入法键盘"完成"
- editText?.setOnEditorActionListener { _: TextView?, actionId: Int, _: KeyEvent? ->
- if (actionId == EditorInfo.IME_ACTION_DONE) {
-// authenticatePresenter.onReadyRetrofitRequest()
- return@setOnEditorActionListener true
- }
- false
- }
-
- //修改服务器配置
- changeServerConfigView.setOnClickListener {
- val defaultValue = SaveKeyValues.getValue(
- Constant.DEFAULT_SERVER_CONFIG,
- "http://139.198.6.177:8093/"
- ) as String
- InputDialog.Builder().setContext(this)
- .setTitle("请输入后台服务器地址")
- .setDefaultValue(defaultValue)
- .setNegativeButton("取消")
- .setPositiveButton("保存")
- .setOnDialogClickListener(object : InputDialog.OnDialogButtonClickListener {
- override fun onButtonClick(input: String) {
- SaveKeyValues.putValue(Constant.DEFAULT_SERVER_CONFIG, input)
- }
- })
- .build().show()
- }
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/ui/MainActivity.kt b/app/src/main/java/com/casic/birmm/inspect/ui/MainActivity.kt
deleted file mode 100644
index 0e97af7..0000000
--- a/app/src/main/java/com/casic/birmm/inspect/ui/MainActivity.kt
+++ /dev/null
@@ -1,21 +0,0 @@
-package com.casic.birmm.inspect.ui
-
-import com.casic.birmm.inspect.R
-import com.casic.birmm.inspect.base.BaseActivity
-
-class MainActivity : BaseActivity() {
-
- override fun initLayoutView(): Int = R.layout.activity_main
-
- override fun setupTopBarLayout() {
-
- }
-
- override fun initData() {
-
- }
-
- override fun initEvent() {
-
- }
-}
diff --git a/app/src/main/java/com/casic/birmm/inspect/ui/PermissionActivity.kt b/app/src/main/java/com/casic/birmm/inspect/ui/PermissionActivity.kt
deleted file mode 100644
index 21fbba2..0000000
--- a/app/src/main/java/com/casic/birmm/inspect/ui/PermissionActivity.kt
+++ /dev/null
@@ -1,58 +0,0 @@
-package com.casic.birmm.inspect.ui
-
-import android.content.Intent
-import android.os.Build
-import android.os.Bundle
-import android.util.Log
-import androidx.appcompat.app.AppCompatActivity
-import com.casic.birmm.inspect.utils.Constant
-import pub.devrel.easypermissions.EasyPermissions
-import pub.devrel.easypermissions.EasyPermissions.PermissionCallbacks
-
-class PermissionActivity : AppCompatActivity(), PermissionCallbacks {
-
- companion object {
- private const val TAG = "PermissionActivity"
- }
-
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- //判断是否有权限,如果版本大于5.1才需要判断(即6.0以上),其他则不需要判断。
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
- if (EasyPermissions.hasPermissions(this, *Constant.USER_PERMISSIONS)) {
- startGuideActivity()
- } else {
- EasyPermissions.requestPermissions(
- this,
- "需要获取相关权限",
- Constant.PERMISSIONS_CODE,
- *Constant.USER_PERMISSIONS
- )
- }
- } else {
- startGuideActivity()
- }
- }
-
- private fun startGuideActivity() {
- startActivity(Intent(this, GuideActivity::class.java))
- finish()
- }
-
- override fun onRequestPermissionsResult(
- requestCode: Int,
- permissions: Array,
- grantResults: IntArray
- ) {
- super.onRequestPermissionsResult(requestCode, permissions, grantResults)
- EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this)
- }
-
- override fun onPermissionsGranted(requestCode: Int, perms: List) {
- startGuideActivity()
- }
-
- override fun onPermissionsDenied(requestCode: Int, perms: List) {
- Log.e(TAG, "onPermissionsDenied: $perms")
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/ExtensionViewModel.kt b/app/src/main/java/com/casic/birmm/inspect/utils/ExtensionViewModel.kt
new file mode 100644
index 0000000..2259965
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/utils/ExtensionViewModel.kt
@@ -0,0 +1,33 @@
+package com.casic.birmm.inspect.utils
+
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import kotlinx.coroutines.CoroutineExceptionHandler
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.launch
+
+/**
+ * ViewModel扩展方法:启动协程
+ * @param block 协程逻辑
+ * @param onError 错误回调方法
+ * @param onComplete 完成回调方法
+ */
+fun ViewModel.launch(
+ block: suspend CoroutineScope.() -> Unit,
+ onError: (e: Throwable) -> Unit = {},
+ onComplete: () -> Unit = {}
+) {
+ viewModelScope.launch(
+ CoroutineExceptionHandler { _, throwable ->
+ run {
+ onError(throwable)
+ }
+ }
+ ) {
+ try {
+ block.invoke(this)
+ } finally {
+ onComplete()
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/LoadState.kt b/app/src/main/java/com/casic/birmm/inspect/utils/LoadState.kt
new file mode 100644
index 0000000..9c83224
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/utils/LoadState.kt
@@ -0,0 +1,22 @@
+package com.casic.birmm.inspect.utils
+
+/**
+ * 加载状态
+ * sealed 关键字表示此类仅内部继承
+ */
+sealed class LoadState(val msg: String) {
+ /**
+ * 加载中
+ */
+ class Loading(msg: String = "") : LoadState(msg)
+
+ /**
+ * 成功
+ */
+ class Success(msg: String = "") : LoadState(msg)
+
+ /**
+ * 失败
+ */
+ class Fail(msg: String = "") : LoadState(msg)
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/OtherUtils.kt b/app/src/main/java/com/casic/birmm/inspect/utils/OtherUtils.kt
index 4c38241..ff63747 100644
--- a/app/src/main/java/com/casic/birmm/inspect/utils/OtherUtils.kt
+++ b/app/src/main/java/com/casic/birmm/inspect/utils/OtherUtils.kt
@@ -6,6 +6,8 @@
object OtherUtils {
+ private var loadingDialog: QMUITipDialog? = null
+
//替换Toast
fun showTipsDialog(context: Context, message: String, view: View) {
val tipDialog = QMUITipDialog.Builder(context)
@@ -16,4 +18,20 @@
tipDialog.dismiss()
}, 2000)
}
+
+ fun showLoadingDialog(context: Context?, message: String?) {
+ loadingDialog = QMUITipDialog.Builder(context)
+ .setIconType(QMUITipDialog.Builder.ICON_TYPE_LOADING)
+ .setTipWord(message)
+ .create()
+ loadingDialog!!.show()
+ }
+
+ fun dismissLoadingDialog() {
+ if (loadingDialog != null) {
+ if (loadingDialog!!.isShowing) {
+ loadingDialog!!.dismiss()
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/RSAUtils.kt b/app/src/main/java/com/casic/birmm/inspect/utils/RSAUtils.kt
new file mode 100644
index 0000000..b93983b
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/utils/RSAUtils.kt
@@ -0,0 +1,61 @@
+package com.casic.birmm.inspect.utils
+
+import android.util.Base64
+import java.security.*
+import java.security.spec.InvalidKeySpecException
+import java.security.spec.X509EncodedKeySpec
+import javax.crypto.BadPaddingException
+import javax.crypto.Cipher
+import javax.crypto.IllegalBlockSizeException
+import javax.crypto.NoSuchPaddingException
+
+/**
+ * Created by W530 on 2019/9/26.
+ */
+object RSAUtils {
+ //构建Cipher实例时所传入的的字符串,默认为"RSA/NONE/PKCS1Padding"
+ private fun processData(srcData: ByteArray, key: Key, mode: Int): ByteArray? { //用来保存处理结果
+ var resultBytes: ByteArray? = null
+ try { //获取Cipher实例
+ val cipher = Cipher.getInstance("RSA/None/PKCS1Padding")
+ //初始化Cipher,mode指定是加密还是解密,key为公钥或私钥
+ cipher.init(mode, key)
+ //处理数据
+ resultBytes = cipher.doFinal(srcData)
+ } catch (e: NoSuchAlgorithmException) {
+ e.printStackTrace()
+ } catch (e: NoSuchPaddingException) {
+ e.printStackTrace()
+ } catch (e: InvalidKeyException) {
+ e.printStackTrace()
+ } catch (e: BadPaddingException) {
+ e.printStackTrace()
+ } catch (e: IllegalBlockSizeException) {
+ e.printStackTrace()
+ }
+ return resultBytes
+ }
+
+ fun encryptDataByPublicKey(srcData: ByteArray, publicKey: PublicKey): String {
+ val resultBytes =
+ processData(srcData, publicKey, Cipher.ENCRYPT_MODE)
+ return Base64.encodeToString(resultBytes, Base64.DEFAULT)
+ }
+
+ fun keyStrToPublicKey(publicKeyStr: String?): PublicKey? {
+ var publicKey: PublicKey? = null
+ val keyBytes =
+ Base64.decode(publicKeyStr, Base64.DEFAULT)
+ val keySpec =
+ X509EncodedKeySpec(keyBytes)
+ try {
+ val keyFactory = KeyFactory.getInstance("RSA")
+ publicKey = keyFactory.generatePublic(keySpec)
+ } catch (e: NoSuchAlgorithmException) {
+ e.printStackTrace()
+ } catch (e: InvalidKeySpecException) {
+ e.printStackTrace()
+ }
+ return publicKey
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitFactory.kt b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitFactory.kt
new file mode 100644
index 0000000..0dd341f
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitFactory.kt
@@ -0,0 +1,48 @@
+package com.casic.birmm.inspect.utils.retrofit;
+
+import android.util.Log
+import com.casic.birmm.inspect.utils.Constant
+import com.casic.birmm.inspect.utils.SaveKeyValues
+import com.jakewharton.retrofit2.adapter.kotlin.coroutines.CoroutineCallAdapterFactory
+import okhttp3.OkHttpClient
+import okhttp3.logging.HttpLoggingInterceptor
+import org.jetbrains.annotations.NotNull
+import retrofit2.Retrofit
+import retrofit2.converter.gson.GsonConverterFactory
+import retrofit2.converter.scalars.ScalarsConverterFactory
+import java.util.concurrent.TimeUnit
+
+object RetrofitFactory {
+ private const val Tag = "RetrofitFactory"
+
+ private val client: OkHttpClient by lazy { createOKHttpClient() }
+
+ fun createRetrofit(clazz: Class): T {
+ val defaultValue = SaveKeyValues.getValue(
+ Constant.DEFAULT_SERVER_CONFIG,
+ "http://111.198.10.15:12204"
+ ) as String
+ return Retrofit.Builder()
+ .baseUrl(defaultValue)
+ .addConverterFactory(ScalarsConverterFactory.create()) //字符串转换器
+ .addConverterFactory(GsonConverterFactory.create()) //Gson转换器
+ .addCallAdapterFactory(CoroutineCallAdapterFactory.invoke()) //协程请求适配器
+ .client(client) //log拦截器
+ .build().create(clazz)
+ }
+
+ private fun createOKHttpClient(): OkHttpClient { //日志显示级别
+ val interceptor =
+ HttpLoggingInterceptor(object : HttpLoggingInterceptor.Logger {
+ override fun log(@NotNull message: String) {
+ Log.d(Tag, "log: $message")
+ }
+ })
+ interceptor.setLevel(HttpLoggingInterceptor.Level.BODY)
+ val builder = OkHttpClient.Builder()
+ .connectTimeout(30, TimeUnit.SECONDS)// 连接时间:30s超时
+ .readTimeout(10, TimeUnit.SECONDS)// 读取时间:10s超时
+ .writeTimeout(10, TimeUnit.SECONDS)// 写入时间:10s超时
+ return builder.addInterceptor(interceptor).build()
+ }
+}
diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt
new file mode 100644
index 0000000..41348ab
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitService.kt
@@ -0,0 +1,16 @@
+package com.casic.birmm.inspect.utils.retrofit
+
+import com.casic.birmm.inspect.model.PublicKeyBean
+import retrofit2.http.GET
+
+/**
+ * @JvmSuppressWildcards 用来注解类和方法,使得被标记元素的泛型参数不会被编译成通配符?
+ * */
+@JvmSuppressWildcards
+interface RetrofitService {
+ /**
+ * PublicKey校验
+ */
+ @GET("/pan-tilt/config/baseConfig")
+ suspend fun obtainPublicKeyAsync(): PublicKeyBean
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitServiceManager.kt
new file mode 100644
index 0000000..fe9869b
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/utils/retrofit/RetrofitServiceManager.kt
@@ -0,0 +1,16 @@
+package com.casic.birmm.inspect.utils.retrofit
+
+import com.casic.birmm.inspect.model.PublicKeyBean
+
+
+object RetrofitServiceManager {
+
+ private val api by lazy { RetrofitFactory.createRetrofit(RetrofitService::class.java) }
+
+ /**
+ * 验证PublicKey
+ */
+ suspend fun authenticate(): PublicKeyBean {
+ return api.obtainPublicKeyAsync()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/view/GuideActivity.kt b/app/src/main/java/com/casic/birmm/inspect/view/GuideActivity.kt
new file mode 100644
index 0000000..a5578c3
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/view/GuideActivity.kt
@@ -0,0 +1,56 @@
+package com.casic.birmm.inspect.view
+
+import android.annotation.SuppressLint
+import android.content.Intent
+import android.os.CountDownTimer
+import android.view.ViewGroup.MarginLayoutParams
+import com.casic.birmm.inspect.R
+import com.casic.birmm.inspect.base.BaseActivity
+import com.qmuiteam.qmui.util.QMUIDisplayHelper
+import kotlinx.android.synthetic.main.activity_guide.*
+
+@SuppressLint("SetTextI18n")
+class GuideActivity : BaseActivity() {
+
+ private lateinit var countDownTimer: CountDownTimer
+
+ override fun initLayoutView(): Int = R.layout.activity_guide
+
+ override fun setupTopBarLayout() {
+
+ }
+
+ override fun initData() {
+ //根据不同设备状态栏高度设置"跳过"按钮的Margin值
+ val statusBarHeight = QMUIDisplayHelper.getStatusBarHeight(this)
+ val rightMargin = QMUIDisplayHelper.dp2px(this, 10)
+ if (skipButton.layoutParams is MarginLayoutParams) {
+ val params = skipButton.layoutParams as MarginLayoutParams
+ params.setMargins(skipButton.width, statusBarHeight, rightMargin, 0)
+ skipButton.requestLayout()
+ }
+
+ countDownTimer = object : CountDownTimer(4000, 1000) {
+ override fun onFinish() {
+ startLoginActivity()
+ }
+
+ override fun onTick(millisUntilFinished: Long) {
+ skipButton.text = "跳过\u3000${(millisUntilFinished / 1000)}s"
+ }
+ }
+ }
+
+ override fun initEvent() {
+ countDownTimer.start()
+ skipButton.setOnClickListener {
+ countDownTimer.cancel()
+ startLoginActivity()
+ }
+ }
+
+ fun startLoginActivity() {
+ startActivity(Intent(this, LoginActivity::class.java))
+ finish()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/view/LoginActivity.kt b/app/src/main/java/com/casic/birmm/inspect/view/LoginActivity.kt
new file mode 100644
index 0000000..bdb3f2d
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/view/LoginActivity.kt
@@ -0,0 +1,110 @@
+package com.casic.birmm.inspect.view
+
+import android.text.Editable
+import android.text.TextWatcher
+import android.util.Log
+import android.view.KeyEvent
+import android.view.inputmethod.EditorInfo
+import android.widget.EditText
+import android.widget.TextView
+import androidx.lifecycle.Observer
+import com.casic.birmm.inspect.R
+import com.casic.birmm.inspect.base.BaseViewModelActivity
+import com.casic.birmm.inspect.utils.*
+import com.casic.birmm.inspect.vm.AuthenticateViewModel
+import com.casic.birmm.inspect.widgets.InputDialog
+import kotlinx.android.synthetic.main.activity_login.*
+
+
+class LoginActivity : BaseViewModelActivity() {
+
+ companion object {
+ private const val Tag = "LoginActivity"
+ }
+
+ override fun createViewModelByClass(): Class? =
+ AuthenticateViewModel::class.java
+
+ override fun initLayoutView(): Int = R.layout.activity_login
+
+ override fun setupTopBarLayout() {
+
+ }
+
+ override fun initData() {
+ // 监听数据变化,从而显示数据在页面
+ viewModel.keyBean.observe(this, Observer {
+ if (it.isSuccess) {
+ Log.d(Tag, "${it.data!!.publicKey}")
+ val keyString = it.data!!.publicKey
+ val publicKey = RSAUtils.keyStrToPublicKey(keyString)
+ val account = userNameView.text.toString()
+ val userPassword = userPasswordView.text.toString()
+ } else {
+ OtherUtils.showTipsDialog(this, it.message!!, loginButton)
+ }
+ })
+ // 监听加载状态变化 从而改变页面
+ viewModel.loadState.observe(this, Observer {
+ when (it) {
+ is LoadState.Loading -> {
+ OtherUtils.showLoadingDialog(this, "登录中,请稍后")
+ }
+ else -> OtherUtils.dismissLoadingDialog()
+ }
+ })
+ }
+
+ override fun initEvent() {
+ val editText: EditText? = inputLayout.editText
+ editText?.addTextChangedListener(object : TextWatcher {
+ override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
+
+ }
+
+ override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
+
+ }
+
+ override fun afterTextChanged(s: Editable) {
+ if (s.toString().trim { it <= ' ' }.length > 12) {
+ inputLayout.error = "密码长度超出限制"
+ } else {
+ inputLayout.error = null
+ }
+ }
+ })
+ //点击输入法键盘"完成"
+ editText?.setOnEditorActionListener { _: TextView?, actionId: Int, _: KeyEvent? ->
+ if (actionId == EditorInfo.IME_ACTION_DONE) {
+ viewModel.obtainPublicKey()
+ return@setOnEditorActionListener true
+ }
+ false
+ }
+
+ loginButton.setChangeAlphaWhenPress(true)
+ loginButton.setOnClickListener {
+ viewModel.obtainPublicKey()
+ }
+
+ //修改服务器配置
+ changeServerConfigView.setOnClickListener {
+ val defaultValue = SaveKeyValues.getValue(
+ Constant.DEFAULT_SERVER_CONFIG,
+ "http://111.198.10.15:12204"
+ ) as String
+ InputDialog.Builder().setContext(this)
+ .setTitle("请输入后台服务器地址")
+ .setDefaultValue(defaultValue)
+ .setNegativeButton("取消")
+ .setPositiveButton("保存")
+ .setOnDialogClickListener(object : InputDialog.OnDialogButtonClickListener {
+ override fun onButtonClick(input: String) {
+ SaveKeyValues.putValue(Constant.DEFAULT_SERVER_CONFIG, input)
+ }
+ })
+ .build().show()
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/view/MainActivity.kt b/app/src/main/java/com/casic/birmm/inspect/view/MainActivity.kt
new file mode 100644
index 0000000..98b9e9a
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/view/MainActivity.kt
@@ -0,0 +1,21 @@
+package com.casic.birmm.inspect.view
+
+import com.casic.birmm.inspect.R
+import com.casic.birmm.inspect.base.BaseActivity
+
+class MainActivity : BaseActivity() {
+
+ override fun initLayoutView(): Int = R.layout.activity_main
+
+ override fun setupTopBarLayout() {
+
+ }
+
+ override fun initData() {
+
+ }
+
+ override fun initEvent() {
+
+ }
+}
diff --git a/app/src/main/java/com/casic/birmm/inspect/view/PermissionActivity.kt b/app/src/main/java/com/casic/birmm/inspect/view/PermissionActivity.kt
new file mode 100644
index 0000000..07f48a5
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/view/PermissionActivity.kt
@@ -0,0 +1,53 @@
+package com.casic.birmm.inspect.view
+
+import android.content.Intent
+import android.os.Build
+import android.os.Bundle
+import androidx.appcompat.app.AppCompatActivity
+import com.casic.birmm.inspect.utils.Constant
+import pub.devrel.easypermissions.EasyPermissions
+import pub.devrel.easypermissions.EasyPermissions.PermissionCallbacks
+
+class PermissionActivity : AppCompatActivity(), PermissionCallbacks {
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ //判断是否有权限,如果版本大于5.1才需要判断(即6.0以上),其他则不需要判断。
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+ if (EasyPermissions.hasPermissions(this, *Constant.USER_PERMISSIONS)) {
+ startGuideActivity()
+ } else {
+ EasyPermissions.requestPermissions(
+ this,
+ "需要获取相关权限",
+ Constant.PERMISSIONS_CODE,
+ *Constant.USER_PERMISSIONS
+ )
+ }
+ } else {
+ startGuideActivity()
+ }
+ }
+
+ private fun startGuideActivity() {
+ startActivity(Intent(this, GuideActivity::class.java))
+ finish()
+ }
+
+ override fun onRequestPermissionsResult(
+ requestCode: Int,
+ permissions: Array,
+ grantResults: IntArray
+ ) {
+ super.onRequestPermissionsResult(requestCode, permissions, grantResults)
+ EasyPermissions.onRequestPermissionsResult(requestCode, permissions, grantResults, this)
+ }
+
+ override fun onPermissionsGranted(requestCode: Int, perms: List) {
+ startGuideActivity()
+ }
+
+ override fun onPermissionsDenied(requestCode: Int, perms: List) {
+
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/casic/birmm/inspect/vm/AuthenticateViewModel.kt b/app/src/main/java/com/casic/birmm/inspect/vm/AuthenticateViewModel.kt
new file mode 100644
index 0000000..7a64c46
--- /dev/null
+++ b/app/src/main/java/com/casic/birmm/inspect/vm/AuthenticateViewModel.kt
@@ -0,0 +1,20 @@
+package com.casic.birmm.inspect.vm
+
+import androidx.lifecycle.MutableLiveData
+import com.casic.birmm.inspect.base.BaseViewModel
+import com.casic.birmm.inspect.model.PublicKeyBean
+import com.casic.birmm.inspect.utils.LoadState
+import com.casic.birmm.inspect.utils.launch
+import com.casic.birmm.inspect.utils.retrofit.RetrofitServiceManager
+
+class AuthenticateViewModel : BaseViewModel() {
+ val keyBean = MutableLiveData()
+
+ fun obtainPublicKey() = launch({
+ loadState.value = LoadState.Loading()
+ keyBean.value = RetrofitServiceManager.authenticate()
+ loadState.value = LoadState.Success()
+ }, {
+ loadState.value = LoadState.Fail()
+ })
+}
\ No newline at end of file