diff --git a/app/build.gradle b/app/build.gradle index ca124d1..aec7047 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -99,4 +99,6 @@ implementation 'com.jzxiang.pickerview:TimePickerDialog:1.0.1' //Html解析,爬虫 implementation 'org.jsoup:jsoup:1.14.3' + //ZBar(综合Java和C++扫码),生成二维码 + implementation 'cn.bertsir.zbarLibary:zbarlibary:1.4.2' } \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index ca124d1..aec7047 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -99,4 +99,6 @@ implementation 'com.jzxiang.pickerview:TimePickerDialog:1.0.1' //Html解析,爬虫 implementation 'org.jsoup:jsoup:1.14.3' + //ZBar(综合Java和C++扫码),生成二维码 + implementation 'cn.bertsir.zbarLibary:zbarlibary:1.4.2' } \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/extensions/String.kt b/app/src/main/java/com/casic/qd/smartwell/extensions/String.kt index 19808ef..6c2525f 100644 --- a/app/src/main/java/com/casic/qd/smartwell/extensions/String.kt +++ b/app/src/main/java/com/casic/qd/smartwell/extensions/String.kt @@ -76,3 +76,16 @@ } return 0 } + +fun String.isLetterAndDigit(): Boolean { + var isDigit = false + var isLetter = false + for (i in this.indices) { + if (Character.isDigit(this[i])) { + isDigit = true + } else if (Character.isLetter(this[i])) { + isLetter = true + } + } + return isDigit && isLetter +} \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index ca124d1..aec7047 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -99,4 +99,6 @@ implementation 'com.jzxiang.pickerview:TimePickerDialog:1.0.1' //Html解析,爬虫 implementation 'org.jsoup:jsoup:1.14.3' + //ZBar(综合Java和C++扫码),生成二维码 + implementation 'cn.bertsir.zbarLibary:zbarlibary:1.4.2' } \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/extensions/String.kt b/app/src/main/java/com/casic/qd/smartwell/extensions/String.kt index 19808ef..6c2525f 100644 --- a/app/src/main/java/com/casic/qd/smartwell/extensions/String.kt +++ b/app/src/main/java/com/casic/qd/smartwell/extensions/String.kt @@ -76,3 +76,16 @@ } return 0 } + +fun String.isLetterAndDigit(): Boolean { + var isDigit = false + var isLetter = false + for (i in this.indices) { + if (Character.isDigit(this[i])) { + isDigit = true + } else if (Character.isLetter(this[i])) { + isLetter = true + } + } + return isDigit && isLetter +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitService.kt b/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitService.kt index 831f862..f133ef4 100644 --- a/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitService.kt +++ b/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitService.kt @@ -43,6 +43,21 @@ suspend fun obtainUserDetail(@Header("token") token: String): String /** + * 修改密码 + * + * @param oldPwd 旧密码 + * @param newPwd 新密码 + */ + @FormUrlEncoded + @POST("/mgr/changePwd") + suspend fun changePassword( + @Header("token") token: String, + @Field("oldPwd") oldPwd: String, + @Field("newPwd") newPwd: String + ): String + + + /** * 用水统计 */ @GET("/waterStatistic/overview") diff --git a/app/build.gradle b/app/build.gradle index ca124d1..aec7047 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -99,4 +99,6 @@ implementation 'com.jzxiang.pickerview:TimePickerDialog:1.0.1' //Html解析,爬虫 implementation 'org.jsoup:jsoup:1.14.3' + //ZBar(综合Java和C++扫码),生成二维码 + implementation 'cn.bertsir.zbarLibary:zbarlibary:1.4.2' } \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/extensions/String.kt b/app/src/main/java/com/casic/qd/smartwell/extensions/String.kt index 19808ef..6c2525f 100644 --- a/app/src/main/java/com/casic/qd/smartwell/extensions/String.kt +++ b/app/src/main/java/com/casic/qd/smartwell/extensions/String.kt @@ -76,3 +76,16 @@ } return 0 } + +fun String.isLetterAndDigit(): Boolean { + var isDigit = false + var isLetter = false + for (i in this.indices) { + if (Character.isDigit(this[i])) { + isDigit = true + } else if (Character.isLetter(this[i])) { + isLetter = true + } + } + return isDigit && isLetter +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitService.kt b/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitService.kt index 831f862..f133ef4 100644 --- a/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitService.kt +++ b/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitService.kt @@ -43,6 +43,21 @@ suspend fun obtainUserDetail(@Header("token") token: String): String /** + * 修改密码 + * + * @param oldPwd 旧密码 + * @param newPwd 新密码 + */ + @FormUrlEncoded + @POST("/mgr/changePwd") + suspend fun changePassword( + @Header("token") token: String, + @Field("oldPwd") oldPwd: String, + @Field("newPwd") newPwd: String + ): String + + + /** * 用水统计 */ @GET("/waterStatistic/overview") diff --git a/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitServiceManager.kt index e446f48..9ee4cc1 100644 --- a/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitServiceManager.kt @@ -38,6 +38,13 @@ } /** + * 修改密码 + */ + suspend fun changePassword(oldPwd: String, newPwd: String): String { + return api.changePassword(AuthenticationHelper.token!!, oldPwd, newPwd) + } + + /** * 用水统计 */ suspend fun waterStatistics(): String { diff --git a/app/build.gradle b/app/build.gradle index ca124d1..aec7047 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -99,4 +99,6 @@ implementation 'com.jzxiang.pickerview:TimePickerDialog:1.0.1' //Html解析,爬虫 implementation 'org.jsoup:jsoup:1.14.3' + //ZBar(综合Java和C++扫码),生成二维码 + implementation 'cn.bertsir.zbarLibary:zbarlibary:1.4.2' } \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/extensions/String.kt b/app/src/main/java/com/casic/qd/smartwell/extensions/String.kt index 19808ef..6c2525f 100644 --- a/app/src/main/java/com/casic/qd/smartwell/extensions/String.kt +++ b/app/src/main/java/com/casic/qd/smartwell/extensions/String.kt @@ -76,3 +76,16 @@ } return 0 } + +fun String.isLetterAndDigit(): Boolean { + var isDigit = false + var isLetter = false + for (i in this.indices) { + if (Character.isDigit(this[i])) { + isDigit = true + } else if (Character.isLetter(this[i])) { + isLetter = true + } + } + return isDigit && isLetter +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitService.kt b/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitService.kt index 831f862..f133ef4 100644 --- a/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitService.kt +++ b/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitService.kt @@ -43,6 +43,21 @@ suspend fun obtainUserDetail(@Header("token") token: String): String /** + * 修改密码 + * + * @param oldPwd 旧密码 + * @param newPwd 新密码 + */ + @FormUrlEncoded + @POST("/mgr/changePwd") + suspend fun changePassword( + @Header("token") token: String, + @Field("oldPwd") oldPwd: String, + @Field("newPwd") newPwd: String + ): String + + + /** * 用水统计 */ @GET("/waterStatistic/overview") diff --git a/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitServiceManager.kt index e446f48..9ee4cc1 100644 --- a/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitServiceManager.kt @@ -38,6 +38,13 @@ } /** + * 修改密码 + */ + suspend fun changePassword(oldPwd: String, newPwd: String): String { + return api.changePassword(AuthenticationHelper.token!!, oldPwd, newPwd) + } + + /** * 用水统计 */ suspend fun waterStatistics(): String { diff --git a/app/src/main/java/com/casic/qd/smartwell/view/MainActivity.kt b/app/src/main/java/com/casic/qd/smartwell/view/MainActivity.kt index 8f41c87..d8af9d8 100644 --- a/app/src/main/java/com/casic/qd/smartwell/view/MainActivity.kt +++ b/app/src/main/java/com/casic/qd/smartwell/view/MainActivity.kt @@ -1,11 +1,12 @@ package com.casic.qd.smartwell.view import android.content.Context -import android.os.Handler -import android.os.Looper -import android.os.Message import android.util.Log import android.view.KeyEvent +import android.view.MenuItem +import android.view.View +import androidx.core.view.GravityCompat +import androidx.drawerlayout.widget.DrawerLayout import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.GridLayoutManager @@ -16,10 +17,14 @@ import com.casic.qd.smartwell.extensions.* import com.casic.qd.smartwell.model.BannerImageModel import com.casic.qd.smartwell.model.LineChartEntryModel +import com.casic.qd.smartwell.model.UserDetailModel import com.casic.qd.smartwell.utils.* +import com.casic.qd.smartwell.vm.ChangePasswordViewModel import com.casic.qd.smartwell.vm.LoginViewModel import com.casic.qd.smartwell.vm.WaterStatisticsViewModel +import com.casic.qd.smartwell.widgets.ChangePasswordDialog import com.github.mikephil.charting.data.Entry +import com.google.android.material.navigation.NavigationView import com.google.gson.Gson import com.google.gson.reflect.TypeToken import com.pengxh.app.multilib.widget.dialog.AlertControlDialog @@ -29,22 +34,29 @@ import com.youth.banner.holder.BannerImageHolder import com.youth.banner.indicator.CircleIndicator import com.youth.banner.transformer.ScaleInTransformer +import kotlinx.android.synthetic.main.activity_data_search.* import kotlinx.android.synthetic.main.activity_main.* -import java.lang.ref.WeakReference +import kotlinx.android.synthetic.main.activity_main.rightOptionView +import kotlinx.android.synthetic.main.activity_main.titleView +import kotlinx.android.synthetic.main.activity_main.view.* +import kotlinx.android.synthetic.main.drawer_header_layout.* +import kotlinx.android.synthetic.main.drawer_header_layout.view.* +import java.nio.charset.StandardCharsets import java.util.* import kotlin.collections.ArrayList -class MainActivity : BaseActivity() { +class MainActivity : BaseActivity(), DrawerLayout.DrawerListener, + NavigationView.OnNavigationItemSelectedListener { private val kTag = "MainActivity" private val context: Context = this@MainActivity private var clickTime: Long = 0 private lateinit var loginViewModel: LoginViewModel private lateinit var waterViewModel: WaterStatisticsViewModel + private lateinit var changePwdViewModel: ChangePasswordViewModel private val xAxisDate: MutableList = ArrayList() private val entryModels: MutableList = ArrayList() private var imageModels: MutableList = ArrayList() - private lateinit var weakReferenceHandler: WeakReferenceHandler override fun initLayoutView(): Int = R.layout.activity_main @@ -53,10 +65,10 @@ } override fun initData() { - val bannerJsonModel = SaveKeyValues.getValue(Constant.BANNER_MODEL, "") as String - if (bannerJsonModel.isNotBlank()) { + val bannerJson = SaveKeyValues.getValue(Constant.BANNER_MODEL, "") as String + if (bannerJson.isNotBlank()) { imageModels = Gson().fromJson( - bannerJsonModel, object : TypeToken>() {}.type + bannerJson, object : TypeToken>() {}.type ) } else { Constant.NEWS_PAGE.forEach { @@ -127,26 +139,19 @@ //初始化vm loginViewModel = ViewModelProvider(this).get(LoginViewModel::class.java) waterViewModel = ViewModelProvider(this).get(WaterStatisticsViewModel::class.java) - weakReferenceHandler = WeakReferenceHandler(this) + changePwdViewModel = ViewModelProvider(this).get(ChangePasswordViewModel::class.java) } override fun initEvent() { leftOptionView.setOnClickListener { - AlertControlDialog.Builder() - .setContext(this) - .setTitle("退出登录") - .setMessage("确定要退出吗?") - .setNegativeButton("取消") - .setPositiveButton("确定") - .setOnDialogButtonClickListener(object : - AlertControlDialog.OnDialogButtonClickListener { - override fun onConfirmClick() { - loginViewModel.out() - } - - override fun onCancelClick() {} - }).build().show() + if (leftDrawerLayout.isDrawerOpen(GravityCompat.START)) { + leftDrawerLayout.closeDrawer(GravityCompat.START) + } else { + leftDrawerLayout.openDrawer(GravityCompat.START) + } } + leftDrawerLayout.addDrawerListener(this) + navigationView.setNavigationItemSelectedListener(this) loginViewModel.loadState.observe(this, { if (it == LoadState.Success) { AuthenticationHelper.removeToken() @@ -205,19 +210,108 @@ expandChartView.setOnClickListener { navigatePageTo(WaterExpandedActivity::class.java) } + + changePwdViewModel.loadState.observe(this, { + when (it) { + is LoadState.Loading -> { + DialogHelper.showLoadingDialog(this, "修改中,请稍后") + } + is LoadState.Success -> { + DialogHelper.dismissLoadingDialog() + AuthenticationHelper.removeToken() + this.navigatePageTo(LoginActivity::class.java) + PageNavigationManager.finishAllActivity() + } + else -> { + DialogHelper.dismissLoadingDialog() + } + } + }) } - private class WeakReferenceHandler(activity: MainActivity) : Handler(Looper.getMainLooper()) { + override fun onDrawerSlide(drawerView: View, slideOffset: Float) { - private val reference: WeakReference = WeakReference(activity) + } - override fun handleMessage(msg: Message) { - super.handleMessage(msg) - val activity = reference.get()!! - + override fun onDrawerOpened(drawerView: View) { + val userDetailJson = SaveKeyValues.getValue(Constant.USER_DETAIL_MODEL, "") as String + if (userDetailJson.isNotBlank()) { + val userDetail = Gson().fromJson( + userDetailJson, object : TypeToken() {}.type + ) + userNameView.text = userDetail.name + userDeptView.text = userDetail.deptName + userRoleView.text = userDetail.roleNames.toString() } } + override fun onDrawerClosed(drawerView: View) { + + } + + override fun onDrawerStateChanged(newState: Int) { + + } + + override fun onNavigationItemSelected(item: MenuItem): Boolean { + when (item.itemId) { + R.id.changePwdView -> { + ChangePasswordDialog.Builder() + .setContext(this) + .setOnDialogButtonClickListener(object : + ChangePasswordDialog.OnDialogButtonClickListener { + override fun onConfirmClick(oldPwd: String, newPwd: String) { + val publicKey = + RSAUtils.keyStrToPublicKey(AuthenticationHelper.publicKey)!! + val oldPassKey = RSAUtils.encryptDataByPublicKey( + oldPwd.toByteArray(StandardCharsets.UTF_8), + publicKey + ) + val newPassKey = RSAUtils.encryptDataByPublicKey( + newPwd.toByteArray(StandardCharsets.UTF_8), + publicKey + ) + changePwdViewModel.changePassword(oldPassKey, newPassKey) + } + }).build().show() + } + R.id.shareApkView -> { + //apk服务器下载地址 +// val downloadPath = "1111" +// val createCodeBitmap = QRUtils.getInstance().createQRCode( +// downloadPath, +// SizeUtil.dp2px(this, 300f), +// SizeUtil.dp2px(this, 300f) +// ) +// ShareDialog.Builder() +// .setContext(this) +// .setDialogTitle("扫以下二维码就可以下载本应用") +// .setDialogBitmap(createCodeBitmap).build().show() + "尽情期待~".show() + } + R.id.versionNameView -> { + "已是最新版本,无需更新".show() + } + R.id.loginOutView -> { + AlertControlDialog.Builder() + .setContext(this) + .setTitle("退出登录") + .setMessage("确定要退出吗?") + .setNegativeButton("取消") + .setPositiveButton("确定") + .setOnDialogButtonClickListener(object : + AlertControlDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + loginViewModel.out() + } + + override fun onCancelClick() {} + }).build().show() + } + } + return false + } + override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { return if (keyCode == KeyEvent.KEYCODE_BACK) { if (System.currentTimeMillis() - clickTime > 2000) { diff --git a/app/build.gradle b/app/build.gradle index ca124d1..aec7047 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -99,4 +99,6 @@ implementation 'com.jzxiang.pickerview:TimePickerDialog:1.0.1' //Html解析,爬虫 implementation 'org.jsoup:jsoup:1.14.3' + //ZBar(综合Java和C++扫码),生成二维码 + implementation 'cn.bertsir.zbarLibary:zbarlibary:1.4.2' } \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/extensions/String.kt b/app/src/main/java/com/casic/qd/smartwell/extensions/String.kt index 19808ef..6c2525f 100644 --- a/app/src/main/java/com/casic/qd/smartwell/extensions/String.kt +++ b/app/src/main/java/com/casic/qd/smartwell/extensions/String.kt @@ -76,3 +76,16 @@ } return 0 } + +fun String.isLetterAndDigit(): Boolean { + var isDigit = false + var isLetter = false + for (i in this.indices) { + if (Character.isDigit(this[i])) { + isDigit = true + } else if (Character.isLetter(this[i])) { + isLetter = true + } + } + return isDigit && isLetter +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitService.kt b/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitService.kt index 831f862..f133ef4 100644 --- a/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitService.kt +++ b/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitService.kt @@ -43,6 +43,21 @@ suspend fun obtainUserDetail(@Header("token") token: String): String /** + * 修改密码 + * + * @param oldPwd 旧密码 + * @param newPwd 新密码 + */ + @FormUrlEncoded + @POST("/mgr/changePwd") + suspend fun changePassword( + @Header("token") token: String, + @Field("oldPwd") oldPwd: String, + @Field("newPwd") newPwd: String + ): String + + + /** * 用水统计 */ @GET("/waterStatistic/overview") diff --git a/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitServiceManager.kt index e446f48..9ee4cc1 100644 --- a/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitServiceManager.kt @@ -38,6 +38,13 @@ } /** + * 修改密码 + */ + suspend fun changePassword(oldPwd: String, newPwd: String): String { + return api.changePassword(AuthenticationHelper.token!!, oldPwd, newPwd) + } + + /** * 用水统计 */ suspend fun waterStatistics(): String { diff --git a/app/src/main/java/com/casic/qd/smartwell/view/MainActivity.kt b/app/src/main/java/com/casic/qd/smartwell/view/MainActivity.kt index 8f41c87..d8af9d8 100644 --- a/app/src/main/java/com/casic/qd/smartwell/view/MainActivity.kt +++ b/app/src/main/java/com/casic/qd/smartwell/view/MainActivity.kt @@ -1,11 +1,12 @@ package com.casic.qd.smartwell.view import android.content.Context -import android.os.Handler -import android.os.Looper -import android.os.Message import android.util.Log import android.view.KeyEvent +import android.view.MenuItem +import android.view.View +import androidx.core.view.GravityCompat +import androidx.drawerlayout.widget.DrawerLayout import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.GridLayoutManager @@ -16,10 +17,14 @@ import com.casic.qd.smartwell.extensions.* import com.casic.qd.smartwell.model.BannerImageModel import com.casic.qd.smartwell.model.LineChartEntryModel +import com.casic.qd.smartwell.model.UserDetailModel import com.casic.qd.smartwell.utils.* +import com.casic.qd.smartwell.vm.ChangePasswordViewModel import com.casic.qd.smartwell.vm.LoginViewModel import com.casic.qd.smartwell.vm.WaterStatisticsViewModel +import com.casic.qd.smartwell.widgets.ChangePasswordDialog import com.github.mikephil.charting.data.Entry +import com.google.android.material.navigation.NavigationView import com.google.gson.Gson import com.google.gson.reflect.TypeToken import com.pengxh.app.multilib.widget.dialog.AlertControlDialog @@ -29,22 +34,29 @@ import com.youth.banner.holder.BannerImageHolder import com.youth.banner.indicator.CircleIndicator import com.youth.banner.transformer.ScaleInTransformer +import kotlinx.android.synthetic.main.activity_data_search.* import kotlinx.android.synthetic.main.activity_main.* -import java.lang.ref.WeakReference +import kotlinx.android.synthetic.main.activity_main.rightOptionView +import kotlinx.android.synthetic.main.activity_main.titleView +import kotlinx.android.synthetic.main.activity_main.view.* +import kotlinx.android.synthetic.main.drawer_header_layout.* +import kotlinx.android.synthetic.main.drawer_header_layout.view.* +import java.nio.charset.StandardCharsets import java.util.* import kotlin.collections.ArrayList -class MainActivity : BaseActivity() { +class MainActivity : BaseActivity(), DrawerLayout.DrawerListener, + NavigationView.OnNavigationItemSelectedListener { private val kTag = "MainActivity" private val context: Context = this@MainActivity private var clickTime: Long = 0 private lateinit var loginViewModel: LoginViewModel private lateinit var waterViewModel: WaterStatisticsViewModel + private lateinit var changePwdViewModel: ChangePasswordViewModel private val xAxisDate: MutableList = ArrayList() private val entryModels: MutableList = ArrayList() private var imageModels: MutableList = ArrayList() - private lateinit var weakReferenceHandler: WeakReferenceHandler override fun initLayoutView(): Int = R.layout.activity_main @@ -53,10 +65,10 @@ } override fun initData() { - val bannerJsonModel = SaveKeyValues.getValue(Constant.BANNER_MODEL, "") as String - if (bannerJsonModel.isNotBlank()) { + val bannerJson = SaveKeyValues.getValue(Constant.BANNER_MODEL, "") as String + if (bannerJson.isNotBlank()) { imageModels = Gson().fromJson( - bannerJsonModel, object : TypeToken>() {}.type + bannerJson, object : TypeToken>() {}.type ) } else { Constant.NEWS_PAGE.forEach { @@ -127,26 +139,19 @@ //初始化vm loginViewModel = ViewModelProvider(this).get(LoginViewModel::class.java) waterViewModel = ViewModelProvider(this).get(WaterStatisticsViewModel::class.java) - weakReferenceHandler = WeakReferenceHandler(this) + changePwdViewModel = ViewModelProvider(this).get(ChangePasswordViewModel::class.java) } override fun initEvent() { leftOptionView.setOnClickListener { - AlertControlDialog.Builder() - .setContext(this) - .setTitle("退出登录") - .setMessage("确定要退出吗?") - .setNegativeButton("取消") - .setPositiveButton("确定") - .setOnDialogButtonClickListener(object : - AlertControlDialog.OnDialogButtonClickListener { - override fun onConfirmClick() { - loginViewModel.out() - } - - override fun onCancelClick() {} - }).build().show() + if (leftDrawerLayout.isDrawerOpen(GravityCompat.START)) { + leftDrawerLayout.closeDrawer(GravityCompat.START) + } else { + leftDrawerLayout.openDrawer(GravityCompat.START) + } } + leftDrawerLayout.addDrawerListener(this) + navigationView.setNavigationItemSelectedListener(this) loginViewModel.loadState.observe(this, { if (it == LoadState.Success) { AuthenticationHelper.removeToken() @@ -205,19 +210,108 @@ expandChartView.setOnClickListener { navigatePageTo(WaterExpandedActivity::class.java) } + + changePwdViewModel.loadState.observe(this, { + when (it) { + is LoadState.Loading -> { + DialogHelper.showLoadingDialog(this, "修改中,请稍后") + } + is LoadState.Success -> { + DialogHelper.dismissLoadingDialog() + AuthenticationHelper.removeToken() + this.navigatePageTo(LoginActivity::class.java) + PageNavigationManager.finishAllActivity() + } + else -> { + DialogHelper.dismissLoadingDialog() + } + } + }) } - private class WeakReferenceHandler(activity: MainActivity) : Handler(Looper.getMainLooper()) { + override fun onDrawerSlide(drawerView: View, slideOffset: Float) { - private val reference: WeakReference = WeakReference(activity) + } - override fun handleMessage(msg: Message) { - super.handleMessage(msg) - val activity = reference.get()!! - + override fun onDrawerOpened(drawerView: View) { + val userDetailJson = SaveKeyValues.getValue(Constant.USER_DETAIL_MODEL, "") as String + if (userDetailJson.isNotBlank()) { + val userDetail = Gson().fromJson( + userDetailJson, object : TypeToken() {}.type + ) + userNameView.text = userDetail.name + userDeptView.text = userDetail.deptName + userRoleView.text = userDetail.roleNames.toString() } } + override fun onDrawerClosed(drawerView: View) { + + } + + override fun onDrawerStateChanged(newState: Int) { + + } + + override fun onNavigationItemSelected(item: MenuItem): Boolean { + when (item.itemId) { + R.id.changePwdView -> { + ChangePasswordDialog.Builder() + .setContext(this) + .setOnDialogButtonClickListener(object : + ChangePasswordDialog.OnDialogButtonClickListener { + override fun onConfirmClick(oldPwd: String, newPwd: String) { + val publicKey = + RSAUtils.keyStrToPublicKey(AuthenticationHelper.publicKey)!! + val oldPassKey = RSAUtils.encryptDataByPublicKey( + oldPwd.toByteArray(StandardCharsets.UTF_8), + publicKey + ) + val newPassKey = RSAUtils.encryptDataByPublicKey( + newPwd.toByteArray(StandardCharsets.UTF_8), + publicKey + ) + changePwdViewModel.changePassword(oldPassKey, newPassKey) + } + }).build().show() + } + R.id.shareApkView -> { + //apk服务器下载地址 +// val downloadPath = "1111" +// val createCodeBitmap = QRUtils.getInstance().createQRCode( +// downloadPath, +// SizeUtil.dp2px(this, 300f), +// SizeUtil.dp2px(this, 300f) +// ) +// ShareDialog.Builder() +// .setContext(this) +// .setDialogTitle("扫以下二维码就可以下载本应用") +// .setDialogBitmap(createCodeBitmap).build().show() + "尽情期待~".show() + } + R.id.versionNameView -> { + "已是最新版本,无需更新".show() + } + R.id.loginOutView -> { + AlertControlDialog.Builder() + .setContext(this) + .setTitle("退出登录") + .setMessage("确定要退出吗?") + .setNegativeButton("取消") + .setPositiveButton("确定") + .setOnDialogButtonClickListener(object : + AlertControlDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + loginViewModel.out() + } + + override fun onCancelClick() {} + }).build().show() + } + } + return false + } + override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { return if (keyCode == KeyEvent.KEYCODE_BACK) { if (System.currentTimeMillis() - clickTime > 2000) { diff --git a/app/src/main/java/com/casic/qd/smartwell/vm/ChangePasswordViewModel.kt b/app/src/main/java/com/casic/qd/smartwell/vm/ChangePasswordViewModel.kt new file mode 100644 index 0000000..751a5f4 --- /dev/null +++ b/app/src/main/java/com/casic/qd/smartwell/vm/ChangePasswordViewModel.kt @@ -0,0 +1,28 @@ +package com.casic.qd.smartwell.vm + +import com.casic.qd.smartwell.base.BaseViewModel +import com.casic.qd.smartwell.extensions.launch +import com.casic.qd.smartwell.extensions.separateResponseCode +import com.casic.qd.smartwell.extensions.show +import com.casic.qd.smartwell.extensions.toErrorMessage +import com.casic.qd.smartwell.utils.LoadState +import com.casic.qd.smartwell.utils.retrofit.RetrofitServiceManager + +class ChangePasswordViewModel : BaseViewModel() { + + fun changePassword(oldPwd: String, newPwd: String) = launch({ + loadState.value = LoadState.Loading + val response = RetrofitServiceManager.changePassword(oldPwd, newPwd) + val responseCode = response.separateResponseCode() + if (responseCode == 200) { + loadState.value = LoadState.Success + "修改成功,请重新登录".show() + } else { + loadState.value = LoadState.Fail + response.toErrorMessage().show() + } + }, { + loadState.value = LoadState.Fail + it.printStackTrace() + }) +} \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index ca124d1..aec7047 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -99,4 +99,6 @@ implementation 'com.jzxiang.pickerview:TimePickerDialog:1.0.1' //Html解析,爬虫 implementation 'org.jsoup:jsoup:1.14.3' + //ZBar(综合Java和C++扫码),生成二维码 + implementation 'cn.bertsir.zbarLibary:zbarlibary:1.4.2' } \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/extensions/String.kt b/app/src/main/java/com/casic/qd/smartwell/extensions/String.kt index 19808ef..6c2525f 100644 --- a/app/src/main/java/com/casic/qd/smartwell/extensions/String.kt +++ b/app/src/main/java/com/casic/qd/smartwell/extensions/String.kt @@ -76,3 +76,16 @@ } return 0 } + +fun String.isLetterAndDigit(): Boolean { + var isDigit = false + var isLetter = false + for (i in this.indices) { + if (Character.isDigit(this[i])) { + isDigit = true + } else if (Character.isLetter(this[i])) { + isLetter = true + } + } + return isDigit && isLetter +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitService.kt b/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitService.kt index 831f862..f133ef4 100644 --- a/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitService.kt +++ b/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitService.kt @@ -43,6 +43,21 @@ suspend fun obtainUserDetail(@Header("token") token: String): String /** + * 修改密码 + * + * @param oldPwd 旧密码 + * @param newPwd 新密码 + */ + @FormUrlEncoded + @POST("/mgr/changePwd") + suspend fun changePassword( + @Header("token") token: String, + @Field("oldPwd") oldPwd: String, + @Field("newPwd") newPwd: String + ): String + + + /** * 用水统计 */ @GET("/waterStatistic/overview") diff --git a/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitServiceManager.kt index e446f48..9ee4cc1 100644 --- a/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitServiceManager.kt @@ -38,6 +38,13 @@ } /** + * 修改密码 + */ + suspend fun changePassword(oldPwd: String, newPwd: String): String { + return api.changePassword(AuthenticationHelper.token!!, oldPwd, newPwd) + } + + /** * 用水统计 */ suspend fun waterStatistics(): String { diff --git a/app/src/main/java/com/casic/qd/smartwell/view/MainActivity.kt b/app/src/main/java/com/casic/qd/smartwell/view/MainActivity.kt index 8f41c87..d8af9d8 100644 --- a/app/src/main/java/com/casic/qd/smartwell/view/MainActivity.kt +++ b/app/src/main/java/com/casic/qd/smartwell/view/MainActivity.kt @@ -1,11 +1,12 @@ package com.casic.qd.smartwell.view import android.content.Context -import android.os.Handler -import android.os.Looper -import android.os.Message import android.util.Log import android.view.KeyEvent +import android.view.MenuItem +import android.view.View +import androidx.core.view.GravityCompat +import androidx.drawerlayout.widget.DrawerLayout import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.GridLayoutManager @@ -16,10 +17,14 @@ import com.casic.qd.smartwell.extensions.* import com.casic.qd.smartwell.model.BannerImageModel import com.casic.qd.smartwell.model.LineChartEntryModel +import com.casic.qd.smartwell.model.UserDetailModel import com.casic.qd.smartwell.utils.* +import com.casic.qd.smartwell.vm.ChangePasswordViewModel import com.casic.qd.smartwell.vm.LoginViewModel import com.casic.qd.smartwell.vm.WaterStatisticsViewModel +import com.casic.qd.smartwell.widgets.ChangePasswordDialog import com.github.mikephil.charting.data.Entry +import com.google.android.material.navigation.NavigationView import com.google.gson.Gson import com.google.gson.reflect.TypeToken import com.pengxh.app.multilib.widget.dialog.AlertControlDialog @@ -29,22 +34,29 @@ import com.youth.banner.holder.BannerImageHolder import com.youth.banner.indicator.CircleIndicator import com.youth.banner.transformer.ScaleInTransformer +import kotlinx.android.synthetic.main.activity_data_search.* import kotlinx.android.synthetic.main.activity_main.* -import java.lang.ref.WeakReference +import kotlinx.android.synthetic.main.activity_main.rightOptionView +import kotlinx.android.synthetic.main.activity_main.titleView +import kotlinx.android.synthetic.main.activity_main.view.* +import kotlinx.android.synthetic.main.drawer_header_layout.* +import kotlinx.android.synthetic.main.drawer_header_layout.view.* +import java.nio.charset.StandardCharsets import java.util.* import kotlin.collections.ArrayList -class MainActivity : BaseActivity() { +class MainActivity : BaseActivity(), DrawerLayout.DrawerListener, + NavigationView.OnNavigationItemSelectedListener { private val kTag = "MainActivity" private val context: Context = this@MainActivity private var clickTime: Long = 0 private lateinit var loginViewModel: LoginViewModel private lateinit var waterViewModel: WaterStatisticsViewModel + private lateinit var changePwdViewModel: ChangePasswordViewModel private val xAxisDate: MutableList = ArrayList() private val entryModels: MutableList = ArrayList() private var imageModels: MutableList = ArrayList() - private lateinit var weakReferenceHandler: WeakReferenceHandler override fun initLayoutView(): Int = R.layout.activity_main @@ -53,10 +65,10 @@ } override fun initData() { - val bannerJsonModel = SaveKeyValues.getValue(Constant.BANNER_MODEL, "") as String - if (bannerJsonModel.isNotBlank()) { + val bannerJson = SaveKeyValues.getValue(Constant.BANNER_MODEL, "") as String + if (bannerJson.isNotBlank()) { imageModels = Gson().fromJson( - bannerJsonModel, object : TypeToken>() {}.type + bannerJson, object : TypeToken>() {}.type ) } else { Constant.NEWS_PAGE.forEach { @@ -127,26 +139,19 @@ //初始化vm loginViewModel = ViewModelProvider(this).get(LoginViewModel::class.java) waterViewModel = ViewModelProvider(this).get(WaterStatisticsViewModel::class.java) - weakReferenceHandler = WeakReferenceHandler(this) + changePwdViewModel = ViewModelProvider(this).get(ChangePasswordViewModel::class.java) } override fun initEvent() { leftOptionView.setOnClickListener { - AlertControlDialog.Builder() - .setContext(this) - .setTitle("退出登录") - .setMessage("确定要退出吗?") - .setNegativeButton("取消") - .setPositiveButton("确定") - .setOnDialogButtonClickListener(object : - AlertControlDialog.OnDialogButtonClickListener { - override fun onConfirmClick() { - loginViewModel.out() - } - - override fun onCancelClick() {} - }).build().show() + if (leftDrawerLayout.isDrawerOpen(GravityCompat.START)) { + leftDrawerLayout.closeDrawer(GravityCompat.START) + } else { + leftDrawerLayout.openDrawer(GravityCompat.START) + } } + leftDrawerLayout.addDrawerListener(this) + navigationView.setNavigationItemSelectedListener(this) loginViewModel.loadState.observe(this, { if (it == LoadState.Success) { AuthenticationHelper.removeToken() @@ -205,19 +210,108 @@ expandChartView.setOnClickListener { navigatePageTo(WaterExpandedActivity::class.java) } + + changePwdViewModel.loadState.observe(this, { + when (it) { + is LoadState.Loading -> { + DialogHelper.showLoadingDialog(this, "修改中,请稍后") + } + is LoadState.Success -> { + DialogHelper.dismissLoadingDialog() + AuthenticationHelper.removeToken() + this.navigatePageTo(LoginActivity::class.java) + PageNavigationManager.finishAllActivity() + } + else -> { + DialogHelper.dismissLoadingDialog() + } + } + }) } - private class WeakReferenceHandler(activity: MainActivity) : Handler(Looper.getMainLooper()) { + override fun onDrawerSlide(drawerView: View, slideOffset: Float) { - private val reference: WeakReference = WeakReference(activity) + } - override fun handleMessage(msg: Message) { - super.handleMessage(msg) - val activity = reference.get()!! - + override fun onDrawerOpened(drawerView: View) { + val userDetailJson = SaveKeyValues.getValue(Constant.USER_DETAIL_MODEL, "") as String + if (userDetailJson.isNotBlank()) { + val userDetail = Gson().fromJson( + userDetailJson, object : TypeToken() {}.type + ) + userNameView.text = userDetail.name + userDeptView.text = userDetail.deptName + userRoleView.text = userDetail.roleNames.toString() } } + override fun onDrawerClosed(drawerView: View) { + + } + + override fun onDrawerStateChanged(newState: Int) { + + } + + override fun onNavigationItemSelected(item: MenuItem): Boolean { + when (item.itemId) { + R.id.changePwdView -> { + ChangePasswordDialog.Builder() + .setContext(this) + .setOnDialogButtonClickListener(object : + ChangePasswordDialog.OnDialogButtonClickListener { + override fun onConfirmClick(oldPwd: String, newPwd: String) { + val publicKey = + RSAUtils.keyStrToPublicKey(AuthenticationHelper.publicKey)!! + val oldPassKey = RSAUtils.encryptDataByPublicKey( + oldPwd.toByteArray(StandardCharsets.UTF_8), + publicKey + ) + val newPassKey = RSAUtils.encryptDataByPublicKey( + newPwd.toByteArray(StandardCharsets.UTF_8), + publicKey + ) + changePwdViewModel.changePassword(oldPassKey, newPassKey) + } + }).build().show() + } + R.id.shareApkView -> { + //apk服务器下载地址 +// val downloadPath = "1111" +// val createCodeBitmap = QRUtils.getInstance().createQRCode( +// downloadPath, +// SizeUtil.dp2px(this, 300f), +// SizeUtil.dp2px(this, 300f) +// ) +// ShareDialog.Builder() +// .setContext(this) +// .setDialogTitle("扫以下二维码就可以下载本应用") +// .setDialogBitmap(createCodeBitmap).build().show() + "尽情期待~".show() + } + R.id.versionNameView -> { + "已是最新版本,无需更新".show() + } + R.id.loginOutView -> { + AlertControlDialog.Builder() + .setContext(this) + .setTitle("退出登录") + .setMessage("确定要退出吗?") + .setNegativeButton("取消") + .setPositiveButton("确定") + .setOnDialogButtonClickListener(object : + AlertControlDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + loginViewModel.out() + } + + override fun onCancelClick() {} + }).build().show() + } + } + return false + } + override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { return if (keyCode == KeyEvent.KEYCODE_BACK) { if (System.currentTimeMillis() - clickTime > 2000) { diff --git a/app/src/main/java/com/casic/qd/smartwell/vm/ChangePasswordViewModel.kt b/app/src/main/java/com/casic/qd/smartwell/vm/ChangePasswordViewModel.kt new file mode 100644 index 0000000..751a5f4 --- /dev/null +++ b/app/src/main/java/com/casic/qd/smartwell/vm/ChangePasswordViewModel.kt @@ -0,0 +1,28 @@ +package com.casic.qd.smartwell.vm + +import com.casic.qd.smartwell.base.BaseViewModel +import com.casic.qd.smartwell.extensions.launch +import com.casic.qd.smartwell.extensions.separateResponseCode +import com.casic.qd.smartwell.extensions.show +import com.casic.qd.smartwell.extensions.toErrorMessage +import com.casic.qd.smartwell.utils.LoadState +import com.casic.qd.smartwell.utils.retrofit.RetrofitServiceManager + +class ChangePasswordViewModel : BaseViewModel() { + + fun changePassword(oldPwd: String, newPwd: String) = launch({ + loadState.value = LoadState.Loading + val response = RetrofitServiceManager.changePassword(oldPwd, newPwd) + val responseCode = response.separateResponseCode() + if (responseCode == 200) { + loadState.value = LoadState.Success + "修改成功,请重新登录".show() + } else { + loadState.value = LoadState.Fail + response.toErrorMessage().show() + } + }, { + loadState.value = LoadState.Fail + it.printStackTrace() + }) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/widgets/ChangePasswordDialog.kt b/app/src/main/java/com/casic/qd/smartwell/widgets/ChangePasswordDialog.kt new file mode 100644 index 0000000..98ff307 --- /dev/null +++ b/app/src/main/java/com/casic/qd/smartwell/widgets/ChangePasswordDialog.kt @@ -0,0 +1,81 @@ +package com.casic.qd.smartwell.widgets + +import android.app.Dialog +import android.content.Context +import android.os.Bundle +import android.view.Gravity +import com.casic.qd.smartwell.R +import com.casic.qd.smartwell.extensions.initDialogLayoutParams +import com.casic.qd.smartwell.extensions.isLetterAndDigit +import com.casic.qd.smartwell.extensions.show +import kotlinx.android.synthetic.main.dialog_change_pwd.* + + +/** + * @author: Pengxh + * @email: 290677893@qq.com + * @date: 2020/11/6 22:12 + */ +class ChangePasswordDialog private constructor(builder: Builder) : + Dialog(builder.context, R.style.UserDefinedDialogStyle) { + + private val listener: OnDialogButtonClickListener = builder.listener + + class Builder { + lateinit var context: Context + lateinit var listener: OnDialogButtonClickListener + + fun setContext(context: Context): Builder { + this.context = context + return this + } + + fun setOnDialogButtonClickListener(listener: OnDialogButtonClickListener): Builder { + this.listener = listener + return this + } + + fun build(): ChangePasswordDialog { + return ChangePasswordDialog(this) + } + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + this.initDialogLayoutParams(Gravity.CENTER, R.style.UserDefinedAnimation, 0.85f) + setContentView(R.layout.dialog_change_pwd) + setCancelable(true) + setCanceledOnTouchOutside(true) + + confirmButton.setChangeAlphaWhenPress(true) + confirmButton.setOnClickListener { + val oldPwd = oldPwdView.text.toString() + val newPwd = newPwdView.text.toString() + val confirmPwd = confirmPwdView.text.toString() + if (oldPwd.isBlank()) { + "请输入原密码".show() + return@setOnClickListener + } + if (newPwd.isBlank()) { + "请输入新密码".show() + return@setOnClickListener + } + if (confirmPwd.isBlank()) { + "请在此确认密码".show() + return@setOnClickListener + } + if (!newPwd.isLetterAndDigit()) { + "新密码需包含数字和字母".show() + } + if (newPwd != confirmPwd) { + "新密码和确认密码不一致,请检查".show() + return@setOnClickListener + } + listener.onConfirmClick(oldPwd, newPwd) + } + } + + interface OnDialogButtonClickListener { + fun onConfirmClick(oldPwd: String, newPwd: String) + } +} \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index ca124d1..aec7047 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -99,4 +99,6 @@ implementation 'com.jzxiang.pickerview:TimePickerDialog:1.0.1' //Html解析,爬虫 implementation 'org.jsoup:jsoup:1.14.3' + //ZBar(综合Java和C++扫码),生成二维码 + implementation 'cn.bertsir.zbarLibary:zbarlibary:1.4.2' } \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/extensions/String.kt b/app/src/main/java/com/casic/qd/smartwell/extensions/String.kt index 19808ef..6c2525f 100644 --- a/app/src/main/java/com/casic/qd/smartwell/extensions/String.kt +++ b/app/src/main/java/com/casic/qd/smartwell/extensions/String.kt @@ -76,3 +76,16 @@ } return 0 } + +fun String.isLetterAndDigit(): Boolean { + var isDigit = false + var isLetter = false + for (i in this.indices) { + if (Character.isDigit(this[i])) { + isDigit = true + } else if (Character.isLetter(this[i])) { + isLetter = true + } + } + return isDigit && isLetter +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitService.kt b/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitService.kt index 831f862..f133ef4 100644 --- a/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitService.kt +++ b/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitService.kt @@ -43,6 +43,21 @@ suspend fun obtainUserDetail(@Header("token") token: String): String /** + * 修改密码 + * + * @param oldPwd 旧密码 + * @param newPwd 新密码 + */ + @FormUrlEncoded + @POST("/mgr/changePwd") + suspend fun changePassword( + @Header("token") token: String, + @Field("oldPwd") oldPwd: String, + @Field("newPwd") newPwd: String + ): String + + + /** * 用水统计 */ @GET("/waterStatistic/overview") diff --git a/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitServiceManager.kt index e446f48..9ee4cc1 100644 --- a/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitServiceManager.kt @@ -38,6 +38,13 @@ } /** + * 修改密码 + */ + suspend fun changePassword(oldPwd: String, newPwd: String): String { + return api.changePassword(AuthenticationHelper.token!!, oldPwd, newPwd) + } + + /** * 用水统计 */ suspend fun waterStatistics(): String { diff --git a/app/src/main/java/com/casic/qd/smartwell/view/MainActivity.kt b/app/src/main/java/com/casic/qd/smartwell/view/MainActivity.kt index 8f41c87..d8af9d8 100644 --- a/app/src/main/java/com/casic/qd/smartwell/view/MainActivity.kt +++ b/app/src/main/java/com/casic/qd/smartwell/view/MainActivity.kt @@ -1,11 +1,12 @@ package com.casic.qd.smartwell.view import android.content.Context -import android.os.Handler -import android.os.Looper -import android.os.Message import android.util.Log import android.view.KeyEvent +import android.view.MenuItem +import android.view.View +import androidx.core.view.GravityCompat +import androidx.drawerlayout.widget.DrawerLayout import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.GridLayoutManager @@ -16,10 +17,14 @@ import com.casic.qd.smartwell.extensions.* import com.casic.qd.smartwell.model.BannerImageModel import com.casic.qd.smartwell.model.LineChartEntryModel +import com.casic.qd.smartwell.model.UserDetailModel import com.casic.qd.smartwell.utils.* +import com.casic.qd.smartwell.vm.ChangePasswordViewModel import com.casic.qd.smartwell.vm.LoginViewModel import com.casic.qd.smartwell.vm.WaterStatisticsViewModel +import com.casic.qd.smartwell.widgets.ChangePasswordDialog import com.github.mikephil.charting.data.Entry +import com.google.android.material.navigation.NavigationView import com.google.gson.Gson import com.google.gson.reflect.TypeToken import com.pengxh.app.multilib.widget.dialog.AlertControlDialog @@ -29,22 +34,29 @@ import com.youth.banner.holder.BannerImageHolder import com.youth.banner.indicator.CircleIndicator import com.youth.banner.transformer.ScaleInTransformer +import kotlinx.android.synthetic.main.activity_data_search.* import kotlinx.android.synthetic.main.activity_main.* -import java.lang.ref.WeakReference +import kotlinx.android.synthetic.main.activity_main.rightOptionView +import kotlinx.android.synthetic.main.activity_main.titleView +import kotlinx.android.synthetic.main.activity_main.view.* +import kotlinx.android.synthetic.main.drawer_header_layout.* +import kotlinx.android.synthetic.main.drawer_header_layout.view.* +import java.nio.charset.StandardCharsets import java.util.* import kotlin.collections.ArrayList -class MainActivity : BaseActivity() { +class MainActivity : BaseActivity(), DrawerLayout.DrawerListener, + NavigationView.OnNavigationItemSelectedListener { private val kTag = "MainActivity" private val context: Context = this@MainActivity private var clickTime: Long = 0 private lateinit var loginViewModel: LoginViewModel private lateinit var waterViewModel: WaterStatisticsViewModel + private lateinit var changePwdViewModel: ChangePasswordViewModel private val xAxisDate: MutableList = ArrayList() private val entryModels: MutableList = ArrayList() private var imageModels: MutableList = ArrayList() - private lateinit var weakReferenceHandler: WeakReferenceHandler override fun initLayoutView(): Int = R.layout.activity_main @@ -53,10 +65,10 @@ } override fun initData() { - val bannerJsonModel = SaveKeyValues.getValue(Constant.BANNER_MODEL, "") as String - if (bannerJsonModel.isNotBlank()) { + val bannerJson = SaveKeyValues.getValue(Constant.BANNER_MODEL, "") as String + if (bannerJson.isNotBlank()) { imageModels = Gson().fromJson( - bannerJsonModel, object : TypeToken>() {}.type + bannerJson, object : TypeToken>() {}.type ) } else { Constant.NEWS_PAGE.forEach { @@ -127,26 +139,19 @@ //初始化vm loginViewModel = ViewModelProvider(this).get(LoginViewModel::class.java) waterViewModel = ViewModelProvider(this).get(WaterStatisticsViewModel::class.java) - weakReferenceHandler = WeakReferenceHandler(this) + changePwdViewModel = ViewModelProvider(this).get(ChangePasswordViewModel::class.java) } override fun initEvent() { leftOptionView.setOnClickListener { - AlertControlDialog.Builder() - .setContext(this) - .setTitle("退出登录") - .setMessage("确定要退出吗?") - .setNegativeButton("取消") - .setPositiveButton("确定") - .setOnDialogButtonClickListener(object : - AlertControlDialog.OnDialogButtonClickListener { - override fun onConfirmClick() { - loginViewModel.out() - } - - override fun onCancelClick() {} - }).build().show() + if (leftDrawerLayout.isDrawerOpen(GravityCompat.START)) { + leftDrawerLayout.closeDrawer(GravityCompat.START) + } else { + leftDrawerLayout.openDrawer(GravityCompat.START) + } } + leftDrawerLayout.addDrawerListener(this) + navigationView.setNavigationItemSelectedListener(this) loginViewModel.loadState.observe(this, { if (it == LoadState.Success) { AuthenticationHelper.removeToken() @@ -205,19 +210,108 @@ expandChartView.setOnClickListener { navigatePageTo(WaterExpandedActivity::class.java) } + + changePwdViewModel.loadState.observe(this, { + when (it) { + is LoadState.Loading -> { + DialogHelper.showLoadingDialog(this, "修改中,请稍后") + } + is LoadState.Success -> { + DialogHelper.dismissLoadingDialog() + AuthenticationHelper.removeToken() + this.navigatePageTo(LoginActivity::class.java) + PageNavigationManager.finishAllActivity() + } + else -> { + DialogHelper.dismissLoadingDialog() + } + } + }) } - private class WeakReferenceHandler(activity: MainActivity) : Handler(Looper.getMainLooper()) { + override fun onDrawerSlide(drawerView: View, slideOffset: Float) { - private val reference: WeakReference = WeakReference(activity) + } - override fun handleMessage(msg: Message) { - super.handleMessage(msg) - val activity = reference.get()!! - + override fun onDrawerOpened(drawerView: View) { + val userDetailJson = SaveKeyValues.getValue(Constant.USER_DETAIL_MODEL, "") as String + if (userDetailJson.isNotBlank()) { + val userDetail = Gson().fromJson( + userDetailJson, object : TypeToken() {}.type + ) + userNameView.text = userDetail.name + userDeptView.text = userDetail.deptName + userRoleView.text = userDetail.roleNames.toString() } } + override fun onDrawerClosed(drawerView: View) { + + } + + override fun onDrawerStateChanged(newState: Int) { + + } + + override fun onNavigationItemSelected(item: MenuItem): Boolean { + when (item.itemId) { + R.id.changePwdView -> { + ChangePasswordDialog.Builder() + .setContext(this) + .setOnDialogButtonClickListener(object : + ChangePasswordDialog.OnDialogButtonClickListener { + override fun onConfirmClick(oldPwd: String, newPwd: String) { + val publicKey = + RSAUtils.keyStrToPublicKey(AuthenticationHelper.publicKey)!! + val oldPassKey = RSAUtils.encryptDataByPublicKey( + oldPwd.toByteArray(StandardCharsets.UTF_8), + publicKey + ) + val newPassKey = RSAUtils.encryptDataByPublicKey( + newPwd.toByteArray(StandardCharsets.UTF_8), + publicKey + ) + changePwdViewModel.changePassword(oldPassKey, newPassKey) + } + }).build().show() + } + R.id.shareApkView -> { + //apk服务器下载地址 +// val downloadPath = "1111" +// val createCodeBitmap = QRUtils.getInstance().createQRCode( +// downloadPath, +// SizeUtil.dp2px(this, 300f), +// SizeUtil.dp2px(this, 300f) +// ) +// ShareDialog.Builder() +// .setContext(this) +// .setDialogTitle("扫以下二维码就可以下载本应用") +// .setDialogBitmap(createCodeBitmap).build().show() + "尽情期待~".show() + } + R.id.versionNameView -> { + "已是最新版本,无需更新".show() + } + R.id.loginOutView -> { + AlertControlDialog.Builder() + .setContext(this) + .setTitle("退出登录") + .setMessage("确定要退出吗?") + .setNegativeButton("取消") + .setPositiveButton("确定") + .setOnDialogButtonClickListener(object : + AlertControlDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + loginViewModel.out() + } + + override fun onCancelClick() {} + }).build().show() + } + } + return false + } + override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { return if (keyCode == KeyEvent.KEYCODE_BACK) { if (System.currentTimeMillis() - clickTime > 2000) { diff --git a/app/src/main/java/com/casic/qd/smartwell/vm/ChangePasswordViewModel.kt b/app/src/main/java/com/casic/qd/smartwell/vm/ChangePasswordViewModel.kt new file mode 100644 index 0000000..751a5f4 --- /dev/null +++ b/app/src/main/java/com/casic/qd/smartwell/vm/ChangePasswordViewModel.kt @@ -0,0 +1,28 @@ +package com.casic.qd.smartwell.vm + +import com.casic.qd.smartwell.base.BaseViewModel +import com.casic.qd.smartwell.extensions.launch +import com.casic.qd.smartwell.extensions.separateResponseCode +import com.casic.qd.smartwell.extensions.show +import com.casic.qd.smartwell.extensions.toErrorMessage +import com.casic.qd.smartwell.utils.LoadState +import com.casic.qd.smartwell.utils.retrofit.RetrofitServiceManager + +class ChangePasswordViewModel : BaseViewModel() { + + fun changePassword(oldPwd: String, newPwd: String) = launch({ + loadState.value = LoadState.Loading + val response = RetrofitServiceManager.changePassword(oldPwd, newPwd) + val responseCode = response.separateResponseCode() + if (responseCode == 200) { + loadState.value = LoadState.Success + "修改成功,请重新登录".show() + } else { + loadState.value = LoadState.Fail + response.toErrorMessage().show() + } + }, { + loadState.value = LoadState.Fail + it.printStackTrace() + }) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/widgets/ChangePasswordDialog.kt b/app/src/main/java/com/casic/qd/smartwell/widgets/ChangePasswordDialog.kt new file mode 100644 index 0000000..98ff307 --- /dev/null +++ b/app/src/main/java/com/casic/qd/smartwell/widgets/ChangePasswordDialog.kt @@ -0,0 +1,81 @@ +package com.casic.qd.smartwell.widgets + +import android.app.Dialog +import android.content.Context +import android.os.Bundle +import android.view.Gravity +import com.casic.qd.smartwell.R +import com.casic.qd.smartwell.extensions.initDialogLayoutParams +import com.casic.qd.smartwell.extensions.isLetterAndDigit +import com.casic.qd.smartwell.extensions.show +import kotlinx.android.synthetic.main.dialog_change_pwd.* + + +/** + * @author: Pengxh + * @email: 290677893@qq.com + * @date: 2020/11/6 22:12 + */ +class ChangePasswordDialog private constructor(builder: Builder) : + Dialog(builder.context, R.style.UserDefinedDialogStyle) { + + private val listener: OnDialogButtonClickListener = builder.listener + + class Builder { + lateinit var context: Context + lateinit var listener: OnDialogButtonClickListener + + fun setContext(context: Context): Builder { + this.context = context + return this + } + + fun setOnDialogButtonClickListener(listener: OnDialogButtonClickListener): Builder { + this.listener = listener + return this + } + + fun build(): ChangePasswordDialog { + return ChangePasswordDialog(this) + } + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + this.initDialogLayoutParams(Gravity.CENTER, R.style.UserDefinedAnimation, 0.85f) + setContentView(R.layout.dialog_change_pwd) + setCancelable(true) + setCanceledOnTouchOutside(true) + + confirmButton.setChangeAlphaWhenPress(true) + confirmButton.setOnClickListener { + val oldPwd = oldPwdView.text.toString() + val newPwd = newPwdView.text.toString() + val confirmPwd = confirmPwdView.text.toString() + if (oldPwd.isBlank()) { + "请输入原密码".show() + return@setOnClickListener + } + if (newPwd.isBlank()) { + "请输入新密码".show() + return@setOnClickListener + } + if (confirmPwd.isBlank()) { + "请在此确认密码".show() + return@setOnClickListener + } + if (!newPwd.isLetterAndDigit()) { + "新密码需包含数字和字母".show() + } + if (newPwd != confirmPwd) { + "新密码和确认密码不一致,请检查".show() + return@setOnClickListener + } + listener.onConfirmClick(oldPwd, newPwd) + } + } + + interface OnDialogButtonClickListener { + fun onConfirmClick(oldPwd: String, newPwd: String) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/widgets/MarqueeTextView.kt b/app/src/main/java/com/casic/qd/smartwell/widgets/MarqueeTextView.kt new file mode 100644 index 0000000..520f6ae --- /dev/null +++ b/app/src/main/java/com/casic/qd/smartwell/widgets/MarqueeTextView.kt @@ -0,0 +1,13 @@ +package com.casic.qd.smartwell.widgets + +import android.content.Context +import android.util.AttributeSet +import androidx.appcompat.widget.AppCompatTextView + +class MarqueeTextView(context: Context, attrs: AttributeSet? = null) : + AppCompatTextView(context, attrs) { + + override fun isFocused(): Boolean { + return true //自动获取焦点 + } +} \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index ca124d1..aec7047 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -99,4 +99,6 @@ implementation 'com.jzxiang.pickerview:TimePickerDialog:1.0.1' //Html解析,爬虫 implementation 'org.jsoup:jsoup:1.14.3' + //ZBar(综合Java和C++扫码),生成二维码 + implementation 'cn.bertsir.zbarLibary:zbarlibary:1.4.2' } \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/extensions/String.kt b/app/src/main/java/com/casic/qd/smartwell/extensions/String.kt index 19808ef..6c2525f 100644 --- a/app/src/main/java/com/casic/qd/smartwell/extensions/String.kt +++ b/app/src/main/java/com/casic/qd/smartwell/extensions/String.kt @@ -76,3 +76,16 @@ } return 0 } + +fun String.isLetterAndDigit(): Boolean { + var isDigit = false + var isLetter = false + for (i in this.indices) { + if (Character.isDigit(this[i])) { + isDigit = true + } else if (Character.isLetter(this[i])) { + isLetter = true + } + } + return isDigit && isLetter +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitService.kt b/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitService.kt index 831f862..f133ef4 100644 --- a/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitService.kt +++ b/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitService.kt @@ -43,6 +43,21 @@ suspend fun obtainUserDetail(@Header("token") token: String): String /** + * 修改密码 + * + * @param oldPwd 旧密码 + * @param newPwd 新密码 + */ + @FormUrlEncoded + @POST("/mgr/changePwd") + suspend fun changePassword( + @Header("token") token: String, + @Field("oldPwd") oldPwd: String, + @Field("newPwd") newPwd: String + ): String + + + /** * 用水统计 */ @GET("/waterStatistic/overview") diff --git a/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitServiceManager.kt index e446f48..9ee4cc1 100644 --- a/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitServiceManager.kt @@ -38,6 +38,13 @@ } /** + * 修改密码 + */ + suspend fun changePassword(oldPwd: String, newPwd: String): String { + return api.changePassword(AuthenticationHelper.token!!, oldPwd, newPwd) + } + + /** * 用水统计 */ suspend fun waterStatistics(): String { diff --git a/app/src/main/java/com/casic/qd/smartwell/view/MainActivity.kt b/app/src/main/java/com/casic/qd/smartwell/view/MainActivity.kt index 8f41c87..d8af9d8 100644 --- a/app/src/main/java/com/casic/qd/smartwell/view/MainActivity.kt +++ b/app/src/main/java/com/casic/qd/smartwell/view/MainActivity.kt @@ -1,11 +1,12 @@ package com.casic.qd.smartwell.view import android.content.Context -import android.os.Handler -import android.os.Looper -import android.os.Message import android.util.Log import android.view.KeyEvent +import android.view.MenuItem +import android.view.View +import androidx.core.view.GravityCompat +import androidx.drawerlayout.widget.DrawerLayout import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.GridLayoutManager @@ -16,10 +17,14 @@ import com.casic.qd.smartwell.extensions.* import com.casic.qd.smartwell.model.BannerImageModel import com.casic.qd.smartwell.model.LineChartEntryModel +import com.casic.qd.smartwell.model.UserDetailModel import com.casic.qd.smartwell.utils.* +import com.casic.qd.smartwell.vm.ChangePasswordViewModel import com.casic.qd.smartwell.vm.LoginViewModel import com.casic.qd.smartwell.vm.WaterStatisticsViewModel +import com.casic.qd.smartwell.widgets.ChangePasswordDialog import com.github.mikephil.charting.data.Entry +import com.google.android.material.navigation.NavigationView import com.google.gson.Gson import com.google.gson.reflect.TypeToken import com.pengxh.app.multilib.widget.dialog.AlertControlDialog @@ -29,22 +34,29 @@ import com.youth.banner.holder.BannerImageHolder import com.youth.banner.indicator.CircleIndicator import com.youth.banner.transformer.ScaleInTransformer +import kotlinx.android.synthetic.main.activity_data_search.* import kotlinx.android.synthetic.main.activity_main.* -import java.lang.ref.WeakReference +import kotlinx.android.synthetic.main.activity_main.rightOptionView +import kotlinx.android.synthetic.main.activity_main.titleView +import kotlinx.android.synthetic.main.activity_main.view.* +import kotlinx.android.synthetic.main.drawer_header_layout.* +import kotlinx.android.synthetic.main.drawer_header_layout.view.* +import java.nio.charset.StandardCharsets import java.util.* import kotlin.collections.ArrayList -class MainActivity : BaseActivity() { +class MainActivity : BaseActivity(), DrawerLayout.DrawerListener, + NavigationView.OnNavigationItemSelectedListener { private val kTag = "MainActivity" private val context: Context = this@MainActivity private var clickTime: Long = 0 private lateinit var loginViewModel: LoginViewModel private lateinit var waterViewModel: WaterStatisticsViewModel + private lateinit var changePwdViewModel: ChangePasswordViewModel private val xAxisDate: MutableList = ArrayList() private val entryModels: MutableList = ArrayList() private var imageModels: MutableList = ArrayList() - private lateinit var weakReferenceHandler: WeakReferenceHandler override fun initLayoutView(): Int = R.layout.activity_main @@ -53,10 +65,10 @@ } override fun initData() { - val bannerJsonModel = SaveKeyValues.getValue(Constant.BANNER_MODEL, "") as String - if (bannerJsonModel.isNotBlank()) { + val bannerJson = SaveKeyValues.getValue(Constant.BANNER_MODEL, "") as String + if (bannerJson.isNotBlank()) { imageModels = Gson().fromJson( - bannerJsonModel, object : TypeToken>() {}.type + bannerJson, object : TypeToken>() {}.type ) } else { Constant.NEWS_PAGE.forEach { @@ -127,26 +139,19 @@ //初始化vm loginViewModel = ViewModelProvider(this).get(LoginViewModel::class.java) waterViewModel = ViewModelProvider(this).get(WaterStatisticsViewModel::class.java) - weakReferenceHandler = WeakReferenceHandler(this) + changePwdViewModel = ViewModelProvider(this).get(ChangePasswordViewModel::class.java) } override fun initEvent() { leftOptionView.setOnClickListener { - AlertControlDialog.Builder() - .setContext(this) - .setTitle("退出登录") - .setMessage("确定要退出吗?") - .setNegativeButton("取消") - .setPositiveButton("确定") - .setOnDialogButtonClickListener(object : - AlertControlDialog.OnDialogButtonClickListener { - override fun onConfirmClick() { - loginViewModel.out() - } - - override fun onCancelClick() {} - }).build().show() + if (leftDrawerLayout.isDrawerOpen(GravityCompat.START)) { + leftDrawerLayout.closeDrawer(GravityCompat.START) + } else { + leftDrawerLayout.openDrawer(GravityCompat.START) + } } + leftDrawerLayout.addDrawerListener(this) + navigationView.setNavigationItemSelectedListener(this) loginViewModel.loadState.observe(this, { if (it == LoadState.Success) { AuthenticationHelper.removeToken() @@ -205,19 +210,108 @@ expandChartView.setOnClickListener { navigatePageTo(WaterExpandedActivity::class.java) } + + changePwdViewModel.loadState.observe(this, { + when (it) { + is LoadState.Loading -> { + DialogHelper.showLoadingDialog(this, "修改中,请稍后") + } + is LoadState.Success -> { + DialogHelper.dismissLoadingDialog() + AuthenticationHelper.removeToken() + this.navigatePageTo(LoginActivity::class.java) + PageNavigationManager.finishAllActivity() + } + else -> { + DialogHelper.dismissLoadingDialog() + } + } + }) } - private class WeakReferenceHandler(activity: MainActivity) : Handler(Looper.getMainLooper()) { + override fun onDrawerSlide(drawerView: View, slideOffset: Float) { - private val reference: WeakReference = WeakReference(activity) + } - override fun handleMessage(msg: Message) { - super.handleMessage(msg) - val activity = reference.get()!! - + override fun onDrawerOpened(drawerView: View) { + val userDetailJson = SaveKeyValues.getValue(Constant.USER_DETAIL_MODEL, "") as String + if (userDetailJson.isNotBlank()) { + val userDetail = Gson().fromJson( + userDetailJson, object : TypeToken() {}.type + ) + userNameView.text = userDetail.name + userDeptView.text = userDetail.deptName + userRoleView.text = userDetail.roleNames.toString() } } + override fun onDrawerClosed(drawerView: View) { + + } + + override fun onDrawerStateChanged(newState: Int) { + + } + + override fun onNavigationItemSelected(item: MenuItem): Boolean { + when (item.itemId) { + R.id.changePwdView -> { + ChangePasswordDialog.Builder() + .setContext(this) + .setOnDialogButtonClickListener(object : + ChangePasswordDialog.OnDialogButtonClickListener { + override fun onConfirmClick(oldPwd: String, newPwd: String) { + val publicKey = + RSAUtils.keyStrToPublicKey(AuthenticationHelper.publicKey)!! + val oldPassKey = RSAUtils.encryptDataByPublicKey( + oldPwd.toByteArray(StandardCharsets.UTF_8), + publicKey + ) + val newPassKey = RSAUtils.encryptDataByPublicKey( + newPwd.toByteArray(StandardCharsets.UTF_8), + publicKey + ) + changePwdViewModel.changePassword(oldPassKey, newPassKey) + } + }).build().show() + } + R.id.shareApkView -> { + //apk服务器下载地址 +// val downloadPath = "1111" +// val createCodeBitmap = QRUtils.getInstance().createQRCode( +// downloadPath, +// SizeUtil.dp2px(this, 300f), +// SizeUtil.dp2px(this, 300f) +// ) +// ShareDialog.Builder() +// .setContext(this) +// .setDialogTitle("扫以下二维码就可以下载本应用") +// .setDialogBitmap(createCodeBitmap).build().show() + "尽情期待~".show() + } + R.id.versionNameView -> { + "已是最新版本,无需更新".show() + } + R.id.loginOutView -> { + AlertControlDialog.Builder() + .setContext(this) + .setTitle("退出登录") + .setMessage("确定要退出吗?") + .setNegativeButton("取消") + .setPositiveButton("确定") + .setOnDialogButtonClickListener(object : + AlertControlDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + loginViewModel.out() + } + + override fun onCancelClick() {} + }).build().show() + } + } + return false + } + override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { return if (keyCode == KeyEvent.KEYCODE_BACK) { if (System.currentTimeMillis() - clickTime > 2000) { diff --git a/app/src/main/java/com/casic/qd/smartwell/vm/ChangePasswordViewModel.kt b/app/src/main/java/com/casic/qd/smartwell/vm/ChangePasswordViewModel.kt new file mode 100644 index 0000000..751a5f4 --- /dev/null +++ b/app/src/main/java/com/casic/qd/smartwell/vm/ChangePasswordViewModel.kt @@ -0,0 +1,28 @@ +package com.casic.qd.smartwell.vm + +import com.casic.qd.smartwell.base.BaseViewModel +import com.casic.qd.smartwell.extensions.launch +import com.casic.qd.smartwell.extensions.separateResponseCode +import com.casic.qd.smartwell.extensions.show +import com.casic.qd.smartwell.extensions.toErrorMessage +import com.casic.qd.smartwell.utils.LoadState +import com.casic.qd.smartwell.utils.retrofit.RetrofitServiceManager + +class ChangePasswordViewModel : BaseViewModel() { + + fun changePassword(oldPwd: String, newPwd: String) = launch({ + loadState.value = LoadState.Loading + val response = RetrofitServiceManager.changePassword(oldPwd, newPwd) + val responseCode = response.separateResponseCode() + if (responseCode == 200) { + loadState.value = LoadState.Success + "修改成功,请重新登录".show() + } else { + loadState.value = LoadState.Fail + response.toErrorMessage().show() + } + }, { + loadState.value = LoadState.Fail + it.printStackTrace() + }) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/widgets/ChangePasswordDialog.kt b/app/src/main/java/com/casic/qd/smartwell/widgets/ChangePasswordDialog.kt new file mode 100644 index 0000000..98ff307 --- /dev/null +++ b/app/src/main/java/com/casic/qd/smartwell/widgets/ChangePasswordDialog.kt @@ -0,0 +1,81 @@ +package com.casic.qd.smartwell.widgets + +import android.app.Dialog +import android.content.Context +import android.os.Bundle +import android.view.Gravity +import com.casic.qd.smartwell.R +import com.casic.qd.smartwell.extensions.initDialogLayoutParams +import com.casic.qd.smartwell.extensions.isLetterAndDigit +import com.casic.qd.smartwell.extensions.show +import kotlinx.android.synthetic.main.dialog_change_pwd.* + + +/** + * @author: Pengxh + * @email: 290677893@qq.com + * @date: 2020/11/6 22:12 + */ +class ChangePasswordDialog private constructor(builder: Builder) : + Dialog(builder.context, R.style.UserDefinedDialogStyle) { + + private val listener: OnDialogButtonClickListener = builder.listener + + class Builder { + lateinit var context: Context + lateinit var listener: OnDialogButtonClickListener + + fun setContext(context: Context): Builder { + this.context = context + return this + } + + fun setOnDialogButtonClickListener(listener: OnDialogButtonClickListener): Builder { + this.listener = listener + return this + } + + fun build(): ChangePasswordDialog { + return ChangePasswordDialog(this) + } + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + this.initDialogLayoutParams(Gravity.CENTER, R.style.UserDefinedAnimation, 0.85f) + setContentView(R.layout.dialog_change_pwd) + setCancelable(true) + setCanceledOnTouchOutside(true) + + confirmButton.setChangeAlphaWhenPress(true) + confirmButton.setOnClickListener { + val oldPwd = oldPwdView.text.toString() + val newPwd = newPwdView.text.toString() + val confirmPwd = confirmPwdView.text.toString() + if (oldPwd.isBlank()) { + "请输入原密码".show() + return@setOnClickListener + } + if (newPwd.isBlank()) { + "请输入新密码".show() + return@setOnClickListener + } + if (confirmPwd.isBlank()) { + "请在此确认密码".show() + return@setOnClickListener + } + if (!newPwd.isLetterAndDigit()) { + "新密码需包含数字和字母".show() + } + if (newPwd != confirmPwd) { + "新密码和确认密码不一致,请检查".show() + return@setOnClickListener + } + listener.onConfirmClick(oldPwd, newPwd) + } + } + + interface OnDialogButtonClickListener { + fun onConfirmClick(oldPwd: String, newPwd: String) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/widgets/MarqueeTextView.kt b/app/src/main/java/com/casic/qd/smartwell/widgets/MarqueeTextView.kt new file mode 100644 index 0000000..520f6ae --- /dev/null +++ b/app/src/main/java/com/casic/qd/smartwell/widgets/MarqueeTextView.kt @@ -0,0 +1,13 @@ +package com.casic.qd.smartwell.widgets + +import android.content.Context +import android.util.AttributeSet +import androidx.appcompat.widget.AppCompatTextView + +class MarqueeTextView(context: Context, attrs: AttributeSet? = null) : + AppCompatTextView(context, attrs) { + + override fun isFocused(): Boolean { + return true //自动获取焦点 + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/widgets/ShareDialog.kt b/app/src/main/java/com/casic/qd/smartwell/widgets/ShareDialog.kt new file mode 100644 index 0000000..377febc --- /dev/null +++ b/app/src/main/java/com/casic/qd/smartwell/widgets/ShareDialog.kt @@ -0,0 +1,54 @@ +package com.casic.qd.smartwell.widgets + +import android.content.Context +import android.graphics.Bitmap +import android.os.Bundle +import androidx.appcompat.app.AlertDialog +import com.casic.qd.smartwell.R +import kotlinx.android.synthetic.main.dialog_share.* + +/** + * @author: Pengxh + * @email: 290677893@qq.com + */ +class ShareDialog private constructor(builder: Builder) : + AlertDialog(builder.context, R.style.UserDefinedDialogStyle) { + + private var title: String = builder.title + private var bitmap: Bitmap = builder.bitmap + + class Builder { + lateinit var context: Context + lateinit var title: String + lateinit var bitmap: Bitmap + + fun setContext(context: Context): Builder { + this.context = context + return this + } + + fun setDialogTitle(title: String): Builder { + this.title = title + return this + } + + fun setDialogBitmap(bitmap: Bitmap): Builder { + this.bitmap = bitmap + return this + } + + fun build(): ShareDialog { + return ShareDialog(this) + } + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.dialog_share) + setCanceledOnTouchOutside(true) + setCancelable(true) + + shareTitleView.text = title + codeView.setImageBitmap(bitmap) + } +} \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index ca124d1..aec7047 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -99,4 +99,6 @@ implementation 'com.jzxiang.pickerview:TimePickerDialog:1.0.1' //Html解析,爬虫 implementation 'org.jsoup:jsoup:1.14.3' + //ZBar(综合Java和C++扫码),生成二维码 + implementation 'cn.bertsir.zbarLibary:zbarlibary:1.4.2' } \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/extensions/String.kt b/app/src/main/java/com/casic/qd/smartwell/extensions/String.kt index 19808ef..6c2525f 100644 --- a/app/src/main/java/com/casic/qd/smartwell/extensions/String.kt +++ b/app/src/main/java/com/casic/qd/smartwell/extensions/String.kt @@ -76,3 +76,16 @@ } return 0 } + +fun String.isLetterAndDigit(): Boolean { + var isDigit = false + var isLetter = false + for (i in this.indices) { + if (Character.isDigit(this[i])) { + isDigit = true + } else if (Character.isLetter(this[i])) { + isLetter = true + } + } + return isDigit && isLetter +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitService.kt b/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitService.kt index 831f862..f133ef4 100644 --- a/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitService.kt +++ b/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitService.kt @@ -43,6 +43,21 @@ suspend fun obtainUserDetail(@Header("token") token: String): String /** + * 修改密码 + * + * @param oldPwd 旧密码 + * @param newPwd 新密码 + */ + @FormUrlEncoded + @POST("/mgr/changePwd") + suspend fun changePassword( + @Header("token") token: String, + @Field("oldPwd") oldPwd: String, + @Field("newPwd") newPwd: String + ): String + + + /** * 用水统计 */ @GET("/waterStatistic/overview") diff --git a/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitServiceManager.kt index e446f48..9ee4cc1 100644 --- a/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitServiceManager.kt @@ -38,6 +38,13 @@ } /** + * 修改密码 + */ + suspend fun changePassword(oldPwd: String, newPwd: String): String { + return api.changePassword(AuthenticationHelper.token!!, oldPwd, newPwd) + } + + /** * 用水统计 */ suspend fun waterStatistics(): String { diff --git a/app/src/main/java/com/casic/qd/smartwell/view/MainActivity.kt b/app/src/main/java/com/casic/qd/smartwell/view/MainActivity.kt index 8f41c87..d8af9d8 100644 --- a/app/src/main/java/com/casic/qd/smartwell/view/MainActivity.kt +++ b/app/src/main/java/com/casic/qd/smartwell/view/MainActivity.kt @@ -1,11 +1,12 @@ package com.casic.qd.smartwell.view import android.content.Context -import android.os.Handler -import android.os.Looper -import android.os.Message import android.util.Log import android.view.KeyEvent +import android.view.MenuItem +import android.view.View +import androidx.core.view.GravityCompat +import androidx.drawerlayout.widget.DrawerLayout import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.GridLayoutManager @@ -16,10 +17,14 @@ import com.casic.qd.smartwell.extensions.* import com.casic.qd.smartwell.model.BannerImageModel import com.casic.qd.smartwell.model.LineChartEntryModel +import com.casic.qd.smartwell.model.UserDetailModel import com.casic.qd.smartwell.utils.* +import com.casic.qd.smartwell.vm.ChangePasswordViewModel import com.casic.qd.smartwell.vm.LoginViewModel import com.casic.qd.smartwell.vm.WaterStatisticsViewModel +import com.casic.qd.smartwell.widgets.ChangePasswordDialog import com.github.mikephil.charting.data.Entry +import com.google.android.material.navigation.NavigationView import com.google.gson.Gson import com.google.gson.reflect.TypeToken import com.pengxh.app.multilib.widget.dialog.AlertControlDialog @@ -29,22 +34,29 @@ import com.youth.banner.holder.BannerImageHolder import com.youth.banner.indicator.CircleIndicator import com.youth.banner.transformer.ScaleInTransformer +import kotlinx.android.synthetic.main.activity_data_search.* import kotlinx.android.synthetic.main.activity_main.* -import java.lang.ref.WeakReference +import kotlinx.android.synthetic.main.activity_main.rightOptionView +import kotlinx.android.synthetic.main.activity_main.titleView +import kotlinx.android.synthetic.main.activity_main.view.* +import kotlinx.android.synthetic.main.drawer_header_layout.* +import kotlinx.android.synthetic.main.drawer_header_layout.view.* +import java.nio.charset.StandardCharsets import java.util.* import kotlin.collections.ArrayList -class MainActivity : BaseActivity() { +class MainActivity : BaseActivity(), DrawerLayout.DrawerListener, + NavigationView.OnNavigationItemSelectedListener { private val kTag = "MainActivity" private val context: Context = this@MainActivity private var clickTime: Long = 0 private lateinit var loginViewModel: LoginViewModel private lateinit var waterViewModel: WaterStatisticsViewModel + private lateinit var changePwdViewModel: ChangePasswordViewModel private val xAxisDate: MutableList = ArrayList() private val entryModels: MutableList = ArrayList() private var imageModels: MutableList = ArrayList() - private lateinit var weakReferenceHandler: WeakReferenceHandler override fun initLayoutView(): Int = R.layout.activity_main @@ -53,10 +65,10 @@ } override fun initData() { - val bannerJsonModel = SaveKeyValues.getValue(Constant.BANNER_MODEL, "") as String - if (bannerJsonModel.isNotBlank()) { + val bannerJson = SaveKeyValues.getValue(Constant.BANNER_MODEL, "") as String + if (bannerJson.isNotBlank()) { imageModels = Gson().fromJson( - bannerJsonModel, object : TypeToken>() {}.type + bannerJson, object : TypeToken>() {}.type ) } else { Constant.NEWS_PAGE.forEach { @@ -127,26 +139,19 @@ //初始化vm loginViewModel = ViewModelProvider(this).get(LoginViewModel::class.java) waterViewModel = ViewModelProvider(this).get(WaterStatisticsViewModel::class.java) - weakReferenceHandler = WeakReferenceHandler(this) + changePwdViewModel = ViewModelProvider(this).get(ChangePasswordViewModel::class.java) } override fun initEvent() { leftOptionView.setOnClickListener { - AlertControlDialog.Builder() - .setContext(this) - .setTitle("退出登录") - .setMessage("确定要退出吗?") - .setNegativeButton("取消") - .setPositiveButton("确定") - .setOnDialogButtonClickListener(object : - AlertControlDialog.OnDialogButtonClickListener { - override fun onConfirmClick() { - loginViewModel.out() - } - - override fun onCancelClick() {} - }).build().show() + if (leftDrawerLayout.isDrawerOpen(GravityCompat.START)) { + leftDrawerLayout.closeDrawer(GravityCompat.START) + } else { + leftDrawerLayout.openDrawer(GravityCompat.START) + } } + leftDrawerLayout.addDrawerListener(this) + navigationView.setNavigationItemSelectedListener(this) loginViewModel.loadState.observe(this, { if (it == LoadState.Success) { AuthenticationHelper.removeToken() @@ -205,19 +210,108 @@ expandChartView.setOnClickListener { navigatePageTo(WaterExpandedActivity::class.java) } + + changePwdViewModel.loadState.observe(this, { + when (it) { + is LoadState.Loading -> { + DialogHelper.showLoadingDialog(this, "修改中,请稍后") + } + is LoadState.Success -> { + DialogHelper.dismissLoadingDialog() + AuthenticationHelper.removeToken() + this.navigatePageTo(LoginActivity::class.java) + PageNavigationManager.finishAllActivity() + } + else -> { + DialogHelper.dismissLoadingDialog() + } + } + }) } - private class WeakReferenceHandler(activity: MainActivity) : Handler(Looper.getMainLooper()) { + override fun onDrawerSlide(drawerView: View, slideOffset: Float) { - private val reference: WeakReference = WeakReference(activity) + } - override fun handleMessage(msg: Message) { - super.handleMessage(msg) - val activity = reference.get()!! - + override fun onDrawerOpened(drawerView: View) { + val userDetailJson = SaveKeyValues.getValue(Constant.USER_DETAIL_MODEL, "") as String + if (userDetailJson.isNotBlank()) { + val userDetail = Gson().fromJson( + userDetailJson, object : TypeToken() {}.type + ) + userNameView.text = userDetail.name + userDeptView.text = userDetail.deptName + userRoleView.text = userDetail.roleNames.toString() } } + override fun onDrawerClosed(drawerView: View) { + + } + + override fun onDrawerStateChanged(newState: Int) { + + } + + override fun onNavigationItemSelected(item: MenuItem): Boolean { + when (item.itemId) { + R.id.changePwdView -> { + ChangePasswordDialog.Builder() + .setContext(this) + .setOnDialogButtonClickListener(object : + ChangePasswordDialog.OnDialogButtonClickListener { + override fun onConfirmClick(oldPwd: String, newPwd: String) { + val publicKey = + RSAUtils.keyStrToPublicKey(AuthenticationHelper.publicKey)!! + val oldPassKey = RSAUtils.encryptDataByPublicKey( + oldPwd.toByteArray(StandardCharsets.UTF_8), + publicKey + ) + val newPassKey = RSAUtils.encryptDataByPublicKey( + newPwd.toByteArray(StandardCharsets.UTF_8), + publicKey + ) + changePwdViewModel.changePassword(oldPassKey, newPassKey) + } + }).build().show() + } + R.id.shareApkView -> { + //apk服务器下载地址 +// val downloadPath = "1111" +// val createCodeBitmap = QRUtils.getInstance().createQRCode( +// downloadPath, +// SizeUtil.dp2px(this, 300f), +// SizeUtil.dp2px(this, 300f) +// ) +// ShareDialog.Builder() +// .setContext(this) +// .setDialogTitle("扫以下二维码就可以下载本应用") +// .setDialogBitmap(createCodeBitmap).build().show() + "尽情期待~".show() + } + R.id.versionNameView -> { + "已是最新版本,无需更新".show() + } + R.id.loginOutView -> { + AlertControlDialog.Builder() + .setContext(this) + .setTitle("退出登录") + .setMessage("确定要退出吗?") + .setNegativeButton("取消") + .setPositiveButton("确定") + .setOnDialogButtonClickListener(object : + AlertControlDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + loginViewModel.out() + } + + override fun onCancelClick() {} + }).build().show() + } + } + return false + } + override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { return if (keyCode == KeyEvent.KEYCODE_BACK) { if (System.currentTimeMillis() - clickTime > 2000) { diff --git a/app/src/main/java/com/casic/qd/smartwell/vm/ChangePasswordViewModel.kt b/app/src/main/java/com/casic/qd/smartwell/vm/ChangePasswordViewModel.kt new file mode 100644 index 0000000..751a5f4 --- /dev/null +++ b/app/src/main/java/com/casic/qd/smartwell/vm/ChangePasswordViewModel.kt @@ -0,0 +1,28 @@ +package com.casic.qd.smartwell.vm + +import com.casic.qd.smartwell.base.BaseViewModel +import com.casic.qd.smartwell.extensions.launch +import com.casic.qd.smartwell.extensions.separateResponseCode +import com.casic.qd.smartwell.extensions.show +import com.casic.qd.smartwell.extensions.toErrorMessage +import com.casic.qd.smartwell.utils.LoadState +import com.casic.qd.smartwell.utils.retrofit.RetrofitServiceManager + +class ChangePasswordViewModel : BaseViewModel() { + + fun changePassword(oldPwd: String, newPwd: String) = launch({ + loadState.value = LoadState.Loading + val response = RetrofitServiceManager.changePassword(oldPwd, newPwd) + val responseCode = response.separateResponseCode() + if (responseCode == 200) { + loadState.value = LoadState.Success + "修改成功,请重新登录".show() + } else { + loadState.value = LoadState.Fail + response.toErrorMessage().show() + } + }, { + loadState.value = LoadState.Fail + it.printStackTrace() + }) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/widgets/ChangePasswordDialog.kt b/app/src/main/java/com/casic/qd/smartwell/widgets/ChangePasswordDialog.kt new file mode 100644 index 0000000..98ff307 --- /dev/null +++ b/app/src/main/java/com/casic/qd/smartwell/widgets/ChangePasswordDialog.kt @@ -0,0 +1,81 @@ +package com.casic.qd.smartwell.widgets + +import android.app.Dialog +import android.content.Context +import android.os.Bundle +import android.view.Gravity +import com.casic.qd.smartwell.R +import com.casic.qd.smartwell.extensions.initDialogLayoutParams +import com.casic.qd.smartwell.extensions.isLetterAndDigit +import com.casic.qd.smartwell.extensions.show +import kotlinx.android.synthetic.main.dialog_change_pwd.* + + +/** + * @author: Pengxh + * @email: 290677893@qq.com + * @date: 2020/11/6 22:12 + */ +class ChangePasswordDialog private constructor(builder: Builder) : + Dialog(builder.context, R.style.UserDefinedDialogStyle) { + + private val listener: OnDialogButtonClickListener = builder.listener + + class Builder { + lateinit var context: Context + lateinit var listener: OnDialogButtonClickListener + + fun setContext(context: Context): Builder { + this.context = context + return this + } + + fun setOnDialogButtonClickListener(listener: OnDialogButtonClickListener): Builder { + this.listener = listener + return this + } + + fun build(): ChangePasswordDialog { + return ChangePasswordDialog(this) + } + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + this.initDialogLayoutParams(Gravity.CENTER, R.style.UserDefinedAnimation, 0.85f) + setContentView(R.layout.dialog_change_pwd) + setCancelable(true) + setCanceledOnTouchOutside(true) + + confirmButton.setChangeAlphaWhenPress(true) + confirmButton.setOnClickListener { + val oldPwd = oldPwdView.text.toString() + val newPwd = newPwdView.text.toString() + val confirmPwd = confirmPwdView.text.toString() + if (oldPwd.isBlank()) { + "请输入原密码".show() + return@setOnClickListener + } + if (newPwd.isBlank()) { + "请输入新密码".show() + return@setOnClickListener + } + if (confirmPwd.isBlank()) { + "请在此确认密码".show() + return@setOnClickListener + } + if (!newPwd.isLetterAndDigit()) { + "新密码需包含数字和字母".show() + } + if (newPwd != confirmPwd) { + "新密码和确认密码不一致,请检查".show() + return@setOnClickListener + } + listener.onConfirmClick(oldPwd, newPwd) + } + } + + interface OnDialogButtonClickListener { + fun onConfirmClick(oldPwd: String, newPwd: String) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/widgets/MarqueeTextView.kt b/app/src/main/java/com/casic/qd/smartwell/widgets/MarqueeTextView.kt new file mode 100644 index 0000000..520f6ae --- /dev/null +++ b/app/src/main/java/com/casic/qd/smartwell/widgets/MarqueeTextView.kt @@ -0,0 +1,13 @@ +package com.casic.qd.smartwell.widgets + +import android.content.Context +import android.util.AttributeSet +import androidx.appcompat.widget.AppCompatTextView + +class MarqueeTextView(context: Context, attrs: AttributeSet? = null) : + AppCompatTextView(context, attrs) { + + override fun isFocused(): Boolean { + return true //自动获取焦点 + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/widgets/ShareDialog.kt b/app/src/main/java/com/casic/qd/smartwell/widgets/ShareDialog.kt new file mode 100644 index 0000000..377febc --- /dev/null +++ b/app/src/main/java/com/casic/qd/smartwell/widgets/ShareDialog.kt @@ -0,0 +1,54 @@ +package com.casic.qd.smartwell.widgets + +import android.content.Context +import android.graphics.Bitmap +import android.os.Bundle +import androidx.appcompat.app.AlertDialog +import com.casic.qd.smartwell.R +import kotlinx.android.synthetic.main.dialog_share.* + +/** + * @author: Pengxh + * @email: 290677893@qq.com + */ +class ShareDialog private constructor(builder: Builder) : + AlertDialog(builder.context, R.style.UserDefinedDialogStyle) { + + private var title: String = builder.title + private var bitmap: Bitmap = builder.bitmap + + class Builder { + lateinit var context: Context + lateinit var title: String + lateinit var bitmap: Bitmap + + fun setContext(context: Context): Builder { + this.context = context + return this + } + + fun setDialogTitle(title: String): Builder { + this.title = title + return this + } + + fun setDialogBitmap(bitmap: Bitmap): Builder { + this.bitmap = bitmap + return this + } + + fun build(): ShareDialog { + return ShareDialog(this) + } + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.dialog_share) + setCanceledOnTouchOutside(true) + setCancelable(true) + + shareTitleView.text = title + codeView.setImageBitmap(bitmap) + } +} \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_change_pwd.xml b/app/src/main/res/drawable/ic_change_pwd.xml new file mode 100644 index 0000000..708f7bf --- /dev/null +++ b/app/src/main/res/drawable/ic_change_pwd.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/build.gradle b/app/build.gradle index ca124d1..aec7047 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -99,4 +99,6 @@ implementation 'com.jzxiang.pickerview:TimePickerDialog:1.0.1' //Html解析,爬虫 implementation 'org.jsoup:jsoup:1.14.3' + //ZBar(综合Java和C++扫码),生成二维码 + implementation 'cn.bertsir.zbarLibary:zbarlibary:1.4.2' } \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/extensions/String.kt b/app/src/main/java/com/casic/qd/smartwell/extensions/String.kt index 19808ef..6c2525f 100644 --- a/app/src/main/java/com/casic/qd/smartwell/extensions/String.kt +++ b/app/src/main/java/com/casic/qd/smartwell/extensions/String.kt @@ -76,3 +76,16 @@ } return 0 } + +fun String.isLetterAndDigit(): Boolean { + var isDigit = false + var isLetter = false + for (i in this.indices) { + if (Character.isDigit(this[i])) { + isDigit = true + } else if (Character.isLetter(this[i])) { + isLetter = true + } + } + return isDigit && isLetter +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitService.kt b/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitService.kt index 831f862..f133ef4 100644 --- a/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitService.kt +++ b/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitService.kt @@ -43,6 +43,21 @@ suspend fun obtainUserDetail(@Header("token") token: String): String /** + * 修改密码 + * + * @param oldPwd 旧密码 + * @param newPwd 新密码 + */ + @FormUrlEncoded + @POST("/mgr/changePwd") + suspend fun changePassword( + @Header("token") token: String, + @Field("oldPwd") oldPwd: String, + @Field("newPwd") newPwd: String + ): String + + + /** * 用水统计 */ @GET("/waterStatistic/overview") diff --git a/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitServiceManager.kt index e446f48..9ee4cc1 100644 --- a/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitServiceManager.kt @@ -38,6 +38,13 @@ } /** + * 修改密码 + */ + suspend fun changePassword(oldPwd: String, newPwd: String): String { + return api.changePassword(AuthenticationHelper.token!!, oldPwd, newPwd) + } + + /** * 用水统计 */ suspend fun waterStatistics(): String { diff --git a/app/src/main/java/com/casic/qd/smartwell/view/MainActivity.kt b/app/src/main/java/com/casic/qd/smartwell/view/MainActivity.kt index 8f41c87..d8af9d8 100644 --- a/app/src/main/java/com/casic/qd/smartwell/view/MainActivity.kt +++ b/app/src/main/java/com/casic/qd/smartwell/view/MainActivity.kt @@ -1,11 +1,12 @@ package com.casic.qd.smartwell.view import android.content.Context -import android.os.Handler -import android.os.Looper -import android.os.Message import android.util.Log import android.view.KeyEvent +import android.view.MenuItem +import android.view.View +import androidx.core.view.GravityCompat +import androidx.drawerlayout.widget.DrawerLayout import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.GridLayoutManager @@ -16,10 +17,14 @@ import com.casic.qd.smartwell.extensions.* import com.casic.qd.smartwell.model.BannerImageModel import com.casic.qd.smartwell.model.LineChartEntryModel +import com.casic.qd.smartwell.model.UserDetailModel import com.casic.qd.smartwell.utils.* +import com.casic.qd.smartwell.vm.ChangePasswordViewModel import com.casic.qd.smartwell.vm.LoginViewModel import com.casic.qd.smartwell.vm.WaterStatisticsViewModel +import com.casic.qd.smartwell.widgets.ChangePasswordDialog import com.github.mikephil.charting.data.Entry +import com.google.android.material.navigation.NavigationView import com.google.gson.Gson import com.google.gson.reflect.TypeToken import com.pengxh.app.multilib.widget.dialog.AlertControlDialog @@ -29,22 +34,29 @@ import com.youth.banner.holder.BannerImageHolder import com.youth.banner.indicator.CircleIndicator import com.youth.banner.transformer.ScaleInTransformer +import kotlinx.android.synthetic.main.activity_data_search.* import kotlinx.android.synthetic.main.activity_main.* -import java.lang.ref.WeakReference +import kotlinx.android.synthetic.main.activity_main.rightOptionView +import kotlinx.android.synthetic.main.activity_main.titleView +import kotlinx.android.synthetic.main.activity_main.view.* +import kotlinx.android.synthetic.main.drawer_header_layout.* +import kotlinx.android.synthetic.main.drawer_header_layout.view.* +import java.nio.charset.StandardCharsets import java.util.* import kotlin.collections.ArrayList -class MainActivity : BaseActivity() { +class MainActivity : BaseActivity(), DrawerLayout.DrawerListener, + NavigationView.OnNavigationItemSelectedListener { private val kTag = "MainActivity" private val context: Context = this@MainActivity private var clickTime: Long = 0 private lateinit var loginViewModel: LoginViewModel private lateinit var waterViewModel: WaterStatisticsViewModel + private lateinit var changePwdViewModel: ChangePasswordViewModel private val xAxisDate: MutableList = ArrayList() private val entryModels: MutableList = ArrayList() private var imageModels: MutableList = ArrayList() - private lateinit var weakReferenceHandler: WeakReferenceHandler override fun initLayoutView(): Int = R.layout.activity_main @@ -53,10 +65,10 @@ } override fun initData() { - val bannerJsonModel = SaveKeyValues.getValue(Constant.BANNER_MODEL, "") as String - if (bannerJsonModel.isNotBlank()) { + val bannerJson = SaveKeyValues.getValue(Constant.BANNER_MODEL, "") as String + if (bannerJson.isNotBlank()) { imageModels = Gson().fromJson( - bannerJsonModel, object : TypeToken>() {}.type + bannerJson, object : TypeToken>() {}.type ) } else { Constant.NEWS_PAGE.forEach { @@ -127,26 +139,19 @@ //初始化vm loginViewModel = ViewModelProvider(this).get(LoginViewModel::class.java) waterViewModel = ViewModelProvider(this).get(WaterStatisticsViewModel::class.java) - weakReferenceHandler = WeakReferenceHandler(this) + changePwdViewModel = ViewModelProvider(this).get(ChangePasswordViewModel::class.java) } override fun initEvent() { leftOptionView.setOnClickListener { - AlertControlDialog.Builder() - .setContext(this) - .setTitle("退出登录") - .setMessage("确定要退出吗?") - .setNegativeButton("取消") - .setPositiveButton("确定") - .setOnDialogButtonClickListener(object : - AlertControlDialog.OnDialogButtonClickListener { - override fun onConfirmClick() { - loginViewModel.out() - } - - override fun onCancelClick() {} - }).build().show() + if (leftDrawerLayout.isDrawerOpen(GravityCompat.START)) { + leftDrawerLayout.closeDrawer(GravityCompat.START) + } else { + leftDrawerLayout.openDrawer(GravityCompat.START) + } } + leftDrawerLayout.addDrawerListener(this) + navigationView.setNavigationItemSelectedListener(this) loginViewModel.loadState.observe(this, { if (it == LoadState.Success) { AuthenticationHelper.removeToken() @@ -205,19 +210,108 @@ expandChartView.setOnClickListener { navigatePageTo(WaterExpandedActivity::class.java) } + + changePwdViewModel.loadState.observe(this, { + when (it) { + is LoadState.Loading -> { + DialogHelper.showLoadingDialog(this, "修改中,请稍后") + } + is LoadState.Success -> { + DialogHelper.dismissLoadingDialog() + AuthenticationHelper.removeToken() + this.navigatePageTo(LoginActivity::class.java) + PageNavigationManager.finishAllActivity() + } + else -> { + DialogHelper.dismissLoadingDialog() + } + } + }) } - private class WeakReferenceHandler(activity: MainActivity) : Handler(Looper.getMainLooper()) { + override fun onDrawerSlide(drawerView: View, slideOffset: Float) { - private val reference: WeakReference = WeakReference(activity) + } - override fun handleMessage(msg: Message) { - super.handleMessage(msg) - val activity = reference.get()!! - + override fun onDrawerOpened(drawerView: View) { + val userDetailJson = SaveKeyValues.getValue(Constant.USER_DETAIL_MODEL, "") as String + if (userDetailJson.isNotBlank()) { + val userDetail = Gson().fromJson( + userDetailJson, object : TypeToken() {}.type + ) + userNameView.text = userDetail.name + userDeptView.text = userDetail.deptName + userRoleView.text = userDetail.roleNames.toString() } } + override fun onDrawerClosed(drawerView: View) { + + } + + override fun onDrawerStateChanged(newState: Int) { + + } + + override fun onNavigationItemSelected(item: MenuItem): Boolean { + when (item.itemId) { + R.id.changePwdView -> { + ChangePasswordDialog.Builder() + .setContext(this) + .setOnDialogButtonClickListener(object : + ChangePasswordDialog.OnDialogButtonClickListener { + override fun onConfirmClick(oldPwd: String, newPwd: String) { + val publicKey = + RSAUtils.keyStrToPublicKey(AuthenticationHelper.publicKey)!! + val oldPassKey = RSAUtils.encryptDataByPublicKey( + oldPwd.toByteArray(StandardCharsets.UTF_8), + publicKey + ) + val newPassKey = RSAUtils.encryptDataByPublicKey( + newPwd.toByteArray(StandardCharsets.UTF_8), + publicKey + ) + changePwdViewModel.changePassword(oldPassKey, newPassKey) + } + }).build().show() + } + R.id.shareApkView -> { + //apk服务器下载地址 +// val downloadPath = "1111" +// val createCodeBitmap = QRUtils.getInstance().createQRCode( +// downloadPath, +// SizeUtil.dp2px(this, 300f), +// SizeUtil.dp2px(this, 300f) +// ) +// ShareDialog.Builder() +// .setContext(this) +// .setDialogTitle("扫以下二维码就可以下载本应用") +// .setDialogBitmap(createCodeBitmap).build().show() + "尽情期待~".show() + } + R.id.versionNameView -> { + "已是最新版本,无需更新".show() + } + R.id.loginOutView -> { + AlertControlDialog.Builder() + .setContext(this) + .setTitle("退出登录") + .setMessage("确定要退出吗?") + .setNegativeButton("取消") + .setPositiveButton("确定") + .setOnDialogButtonClickListener(object : + AlertControlDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + loginViewModel.out() + } + + override fun onCancelClick() {} + }).build().show() + } + } + return false + } + override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { return if (keyCode == KeyEvent.KEYCODE_BACK) { if (System.currentTimeMillis() - clickTime > 2000) { diff --git a/app/src/main/java/com/casic/qd/smartwell/vm/ChangePasswordViewModel.kt b/app/src/main/java/com/casic/qd/smartwell/vm/ChangePasswordViewModel.kt new file mode 100644 index 0000000..751a5f4 --- /dev/null +++ b/app/src/main/java/com/casic/qd/smartwell/vm/ChangePasswordViewModel.kt @@ -0,0 +1,28 @@ +package com.casic.qd.smartwell.vm + +import com.casic.qd.smartwell.base.BaseViewModel +import com.casic.qd.smartwell.extensions.launch +import com.casic.qd.smartwell.extensions.separateResponseCode +import com.casic.qd.smartwell.extensions.show +import com.casic.qd.smartwell.extensions.toErrorMessage +import com.casic.qd.smartwell.utils.LoadState +import com.casic.qd.smartwell.utils.retrofit.RetrofitServiceManager + +class ChangePasswordViewModel : BaseViewModel() { + + fun changePassword(oldPwd: String, newPwd: String) = launch({ + loadState.value = LoadState.Loading + val response = RetrofitServiceManager.changePassword(oldPwd, newPwd) + val responseCode = response.separateResponseCode() + if (responseCode == 200) { + loadState.value = LoadState.Success + "修改成功,请重新登录".show() + } else { + loadState.value = LoadState.Fail + response.toErrorMessage().show() + } + }, { + loadState.value = LoadState.Fail + it.printStackTrace() + }) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/widgets/ChangePasswordDialog.kt b/app/src/main/java/com/casic/qd/smartwell/widgets/ChangePasswordDialog.kt new file mode 100644 index 0000000..98ff307 --- /dev/null +++ b/app/src/main/java/com/casic/qd/smartwell/widgets/ChangePasswordDialog.kt @@ -0,0 +1,81 @@ +package com.casic.qd.smartwell.widgets + +import android.app.Dialog +import android.content.Context +import android.os.Bundle +import android.view.Gravity +import com.casic.qd.smartwell.R +import com.casic.qd.smartwell.extensions.initDialogLayoutParams +import com.casic.qd.smartwell.extensions.isLetterAndDigit +import com.casic.qd.smartwell.extensions.show +import kotlinx.android.synthetic.main.dialog_change_pwd.* + + +/** + * @author: Pengxh + * @email: 290677893@qq.com + * @date: 2020/11/6 22:12 + */ +class ChangePasswordDialog private constructor(builder: Builder) : + Dialog(builder.context, R.style.UserDefinedDialogStyle) { + + private val listener: OnDialogButtonClickListener = builder.listener + + class Builder { + lateinit var context: Context + lateinit var listener: OnDialogButtonClickListener + + fun setContext(context: Context): Builder { + this.context = context + return this + } + + fun setOnDialogButtonClickListener(listener: OnDialogButtonClickListener): Builder { + this.listener = listener + return this + } + + fun build(): ChangePasswordDialog { + return ChangePasswordDialog(this) + } + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + this.initDialogLayoutParams(Gravity.CENTER, R.style.UserDefinedAnimation, 0.85f) + setContentView(R.layout.dialog_change_pwd) + setCancelable(true) + setCanceledOnTouchOutside(true) + + confirmButton.setChangeAlphaWhenPress(true) + confirmButton.setOnClickListener { + val oldPwd = oldPwdView.text.toString() + val newPwd = newPwdView.text.toString() + val confirmPwd = confirmPwdView.text.toString() + if (oldPwd.isBlank()) { + "请输入原密码".show() + return@setOnClickListener + } + if (newPwd.isBlank()) { + "请输入新密码".show() + return@setOnClickListener + } + if (confirmPwd.isBlank()) { + "请在此确认密码".show() + return@setOnClickListener + } + if (!newPwd.isLetterAndDigit()) { + "新密码需包含数字和字母".show() + } + if (newPwd != confirmPwd) { + "新密码和确认密码不一致,请检查".show() + return@setOnClickListener + } + listener.onConfirmClick(oldPwd, newPwd) + } + } + + interface OnDialogButtonClickListener { + fun onConfirmClick(oldPwd: String, newPwd: String) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/widgets/MarqueeTextView.kt b/app/src/main/java/com/casic/qd/smartwell/widgets/MarqueeTextView.kt new file mode 100644 index 0000000..520f6ae --- /dev/null +++ b/app/src/main/java/com/casic/qd/smartwell/widgets/MarqueeTextView.kt @@ -0,0 +1,13 @@ +package com.casic.qd.smartwell.widgets + +import android.content.Context +import android.util.AttributeSet +import androidx.appcompat.widget.AppCompatTextView + +class MarqueeTextView(context: Context, attrs: AttributeSet? = null) : + AppCompatTextView(context, attrs) { + + override fun isFocused(): Boolean { + return true //自动获取焦点 + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/widgets/ShareDialog.kt b/app/src/main/java/com/casic/qd/smartwell/widgets/ShareDialog.kt new file mode 100644 index 0000000..377febc --- /dev/null +++ b/app/src/main/java/com/casic/qd/smartwell/widgets/ShareDialog.kt @@ -0,0 +1,54 @@ +package com.casic.qd.smartwell.widgets + +import android.content.Context +import android.graphics.Bitmap +import android.os.Bundle +import androidx.appcompat.app.AlertDialog +import com.casic.qd.smartwell.R +import kotlinx.android.synthetic.main.dialog_share.* + +/** + * @author: Pengxh + * @email: 290677893@qq.com + */ +class ShareDialog private constructor(builder: Builder) : + AlertDialog(builder.context, R.style.UserDefinedDialogStyle) { + + private var title: String = builder.title + private var bitmap: Bitmap = builder.bitmap + + class Builder { + lateinit var context: Context + lateinit var title: String + lateinit var bitmap: Bitmap + + fun setContext(context: Context): Builder { + this.context = context + return this + } + + fun setDialogTitle(title: String): Builder { + this.title = title + return this + } + + fun setDialogBitmap(bitmap: Bitmap): Builder { + this.bitmap = bitmap + return this + } + + fun build(): ShareDialog { + return ShareDialog(this) + } + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.dialog_share) + setCanceledOnTouchOutside(true) + setCancelable(true) + + shareTitleView.text = title + codeView.setImageBitmap(bitmap) + } +} \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_change_pwd.xml b/app/src/main/res/drawable/ic_change_pwd.xml new file mode 100644 index 0000000..708f7bf --- /dev/null +++ b/app/src/main/res/drawable/ic_change_pwd.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_login_out.xml b/app/src/main/res/drawable/ic_login_out.xml index 208a666..e07996c 100644 --- a/app/src/main/res/drawable/ic_login_out.xml +++ b/app/src/main/res/drawable/ic_login_out.xml @@ -4,9 +4,9 @@ android:viewportWidth="1024" android:viewportHeight="1024"> diff --git a/app/build.gradle b/app/build.gradle index ca124d1..aec7047 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -99,4 +99,6 @@ implementation 'com.jzxiang.pickerview:TimePickerDialog:1.0.1' //Html解析,爬虫 implementation 'org.jsoup:jsoup:1.14.3' + //ZBar(综合Java和C++扫码),生成二维码 + implementation 'cn.bertsir.zbarLibary:zbarlibary:1.4.2' } \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/extensions/String.kt b/app/src/main/java/com/casic/qd/smartwell/extensions/String.kt index 19808ef..6c2525f 100644 --- a/app/src/main/java/com/casic/qd/smartwell/extensions/String.kt +++ b/app/src/main/java/com/casic/qd/smartwell/extensions/String.kt @@ -76,3 +76,16 @@ } return 0 } + +fun String.isLetterAndDigit(): Boolean { + var isDigit = false + var isLetter = false + for (i in this.indices) { + if (Character.isDigit(this[i])) { + isDigit = true + } else if (Character.isLetter(this[i])) { + isLetter = true + } + } + return isDigit && isLetter +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitService.kt b/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitService.kt index 831f862..f133ef4 100644 --- a/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitService.kt +++ b/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitService.kt @@ -43,6 +43,21 @@ suspend fun obtainUserDetail(@Header("token") token: String): String /** + * 修改密码 + * + * @param oldPwd 旧密码 + * @param newPwd 新密码 + */ + @FormUrlEncoded + @POST("/mgr/changePwd") + suspend fun changePassword( + @Header("token") token: String, + @Field("oldPwd") oldPwd: String, + @Field("newPwd") newPwd: String + ): String + + + /** * 用水统计 */ @GET("/waterStatistic/overview") diff --git a/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitServiceManager.kt index e446f48..9ee4cc1 100644 --- a/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitServiceManager.kt @@ -38,6 +38,13 @@ } /** + * 修改密码 + */ + suspend fun changePassword(oldPwd: String, newPwd: String): String { + return api.changePassword(AuthenticationHelper.token!!, oldPwd, newPwd) + } + + /** * 用水统计 */ suspend fun waterStatistics(): String { diff --git a/app/src/main/java/com/casic/qd/smartwell/view/MainActivity.kt b/app/src/main/java/com/casic/qd/smartwell/view/MainActivity.kt index 8f41c87..d8af9d8 100644 --- a/app/src/main/java/com/casic/qd/smartwell/view/MainActivity.kt +++ b/app/src/main/java/com/casic/qd/smartwell/view/MainActivity.kt @@ -1,11 +1,12 @@ package com.casic.qd.smartwell.view import android.content.Context -import android.os.Handler -import android.os.Looper -import android.os.Message import android.util.Log import android.view.KeyEvent +import android.view.MenuItem +import android.view.View +import androidx.core.view.GravityCompat +import androidx.drawerlayout.widget.DrawerLayout import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.GridLayoutManager @@ -16,10 +17,14 @@ import com.casic.qd.smartwell.extensions.* import com.casic.qd.smartwell.model.BannerImageModel import com.casic.qd.smartwell.model.LineChartEntryModel +import com.casic.qd.smartwell.model.UserDetailModel import com.casic.qd.smartwell.utils.* +import com.casic.qd.smartwell.vm.ChangePasswordViewModel import com.casic.qd.smartwell.vm.LoginViewModel import com.casic.qd.smartwell.vm.WaterStatisticsViewModel +import com.casic.qd.smartwell.widgets.ChangePasswordDialog import com.github.mikephil.charting.data.Entry +import com.google.android.material.navigation.NavigationView import com.google.gson.Gson import com.google.gson.reflect.TypeToken import com.pengxh.app.multilib.widget.dialog.AlertControlDialog @@ -29,22 +34,29 @@ import com.youth.banner.holder.BannerImageHolder import com.youth.banner.indicator.CircleIndicator import com.youth.banner.transformer.ScaleInTransformer +import kotlinx.android.synthetic.main.activity_data_search.* import kotlinx.android.synthetic.main.activity_main.* -import java.lang.ref.WeakReference +import kotlinx.android.synthetic.main.activity_main.rightOptionView +import kotlinx.android.synthetic.main.activity_main.titleView +import kotlinx.android.synthetic.main.activity_main.view.* +import kotlinx.android.synthetic.main.drawer_header_layout.* +import kotlinx.android.synthetic.main.drawer_header_layout.view.* +import java.nio.charset.StandardCharsets import java.util.* import kotlin.collections.ArrayList -class MainActivity : BaseActivity() { +class MainActivity : BaseActivity(), DrawerLayout.DrawerListener, + NavigationView.OnNavigationItemSelectedListener { private val kTag = "MainActivity" private val context: Context = this@MainActivity private var clickTime: Long = 0 private lateinit var loginViewModel: LoginViewModel private lateinit var waterViewModel: WaterStatisticsViewModel + private lateinit var changePwdViewModel: ChangePasswordViewModel private val xAxisDate: MutableList = ArrayList() private val entryModels: MutableList = ArrayList() private var imageModels: MutableList = ArrayList() - private lateinit var weakReferenceHandler: WeakReferenceHandler override fun initLayoutView(): Int = R.layout.activity_main @@ -53,10 +65,10 @@ } override fun initData() { - val bannerJsonModel = SaveKeyValues.getValue(Constant.BANNER_MODEL, "") as String - if (bannerJsonModel.isNotBlank()) { + val bannerJson = SaveKeyValues.getValue(Constant.BANNER_MODEL, "") as String + if (bannerJson.isNotBlank()) { imageModels = Gson().fromJson( - bannerJsonModel, object : TypeToken>() {}.type + bannerJson, object : TypeToken>() {}.type ) } else { Constant.NEWS_PAGE.forEach { @@ -127,26 +139,19 @@ //初始化vm loginViewModel = ViewModelProvider(this).get(LoginViewModel::class.java) waterViewModel = ViewModelProvider(this).get(WaterStatisticsViewModel::class.java) - weakReferenceHandler = WeakReferenceHandler(this) + changePwdViewModel = ViewModelProvider(this).get(ChangePasswordViewModel::class.java) } override fun initEvent() { leftOptionView.setOnClickListener { - AlertControlDialog.Builder() - .setContext(this) - .setTitle("退出登录") - .setMessage("确定要退出吗?") - .setNegativeButton("取消") - .setPositiveButton("确定") - .setOnDialogButtonClickListener(object : - AlertControlDialog.OnDialogButtonClickListener { - override fun onConfirmClick() { - loginViewModel.out() - } - - override fun onCancelClick() {} - }).build().show() + if (leftDrawerLayout.isDrawerOpen(GravityCompat.START)) { + leftDrawerLayout.closeDrawer(GravityCompat.START) + } else { + leftDrawerLayout.openDrawer(GravityCompat.START) + } } + leftDrawerLayout.addDrawerListener(this) + navigationView.setNavigationItemSelectedListener(this) loginViewModel.loadState.observe(this, { if (it == LoadState.Success) { AuthenticationHelper.removeToken() @@ -205,19 +210,108 @@ expandChartView.setOnClickListener { navigatePageTo(WaterExpandedActivity::class.java) } + + changePwdViewModel.loadState.observe(this, { + when (it) { + is LoadState.Loading -> { + DialogHelper.showLoadingDialog(this, "修改中,请稍后") + } + is LoadState.Success -> { + DialogHelper.dismissLoadingDialog() + AuthenticationHelper.removeToken() + this.navigatePageTo(LoginActivity::class.java) + PageNavigationManager.finishAllActivity() + } + else -> { + DialogHelper.dismissLoadingDialog() + } + } + }) } - private class WeakReferenceHandler(activity: MainActivity) : Handler(Looper.getMainLooper()) { + override fun onDrawerSlide(drawerView: View, slideOffset: Float) { - private val reference: WeakReference = WeakReference(activity) + } - override fun handleMessage(msg: Message) { - super.handleMessage(msg) - val activity = reference.get()!! - + override fun onDrawerOpened(drawerView: View) { + val userDetailJson = SaveKeyValues.getValue(Constant.USER_DETAIL_MODEL, "") as String + if (userDetailJson.isNotBlank()) { + val userDetail = Gson().fromJson( + userDetailJson, object : TypeToken() {}.type + ) + userNameView.text = userDetail.name + userDeptView.text = userDetail.deptName + userRoleView.text = userDetail.roleNames.toString() } } + override fun onDrawerClosed(drawerView: View) { + + } + + override fun onDrawerStateChanged(newState: Int) { + + } + + override fun onNavigationItemSelected(item: MenuItem): Boolean { + when (item.itemId) { + R.id.changePwdView -> { + ChangePasswordDialog.Builder() + .setContext(this) + .setOnDialogButtonClickListener(object : + ChangePasswordDialog.OnDialogButtonClickListener { + override fun onConfirmClick(oldPwd: String, newPwd: String) { + val publicKey = + RSAUtils.keyStrToPublicKey(AuthenticationHelper.publicKey)!! + val oldPassKey = RSAUtils.encryptDataByPublicKey( + oldPwd.toByteArray(StandardCharsets.UTF_8), + publicKey + ) + val newPassKey = RSAUtils.encryptDataByPublicKey( + newPwd.toByteArray(StandardCharsets.UTF_8), + publicKey + ) + changePwdViewModel.changePassword(oldPassKey, newPassKey) + } + }).build().show() + } + R.id.shareApkView -> { + //apk服务器下载地址 +// val downloadPath = "1111" +// val createCodeBitmap = QRUtils.getInstance().createQRCode( +// downloadPath, +// SizeUtil.dp2px(this, 300f), +// SizeUtil.dp2px(this, 300f) +// ) +// ShareDialog.Builder() +// .setContext(this) +// .setDialogTitle("扫以下二维码就可以下载本应用") +// .setDialogBitmap(createCodeBitmap).build().show() + "尽情期待~".show() + } + R.id.versionNameView -> { + "已是最新版本,无需更新".show() + } + R.id.loginOutView -> { + AlertControlDialog.Builder() + .setContext(this) + .setTitle("退出登录") + .setMessage("确定要退出吗?") + .setNegativeButton("取消") + .setPositiveButton("确定") + .setOnDialogButtonClickListener(object : + AlertControlDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + loginViewModel.out() + } + + override fun onCancelClick() {} + }).build().show() + } + } + return false + } + override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { return if (keyCode == KeyEvent.KEYCODE_BACK) { if (System.currentTimeMillis() - clickTime > 2000) { diff --git a/app/src/main/java/com/casic/qd/smartwell/vm/ChangePasswordViewModel.kt b/app/src/main/java/com/casic/qd/smartwell/vm/ChangePasswordViewModel.kt new file mode 100644 index 0000000..751a5f4 --- /dev/null +++ b/app/src/main/java/com/casic/qd/smartwell/vm/ChangePasswordViewModel.kt @@ -0,0 +1,28 @@ +package com.casic.qd.smartwell.vm + +import com.casic.qd.smartwell.base.BaseViewModel +import com.casic.qd.smartwell.extensions.launch +import com.casic.qd.smartwell.extensions.separateResponseCode +import com.casic.qd.smartwell.extensions.show +import com.casic.qd.smartwell.extensions.toErrorMessage +import com.casic.qd.smartwell.utils.LoadState +import com.casic.qd.smartwell.utils.retrofit.RetrofitServiceManager + +class ChangePasswordViewModel : BaseViewModel() { + + fun changePassword(oldPwd: String, newPwd: String) = launch({ + loadState.value = LoadState.Loading + val response = RetrofitServiceManager.changePassword(oldPwd, newPwd) + val responseCode = response.separateResponseCode() + if (responseCode == 200) { + loadState.value = LoadState.Success + "修改成功,请重新登录".show() + } else { + loadState.value = LoadState.Fail + response.toErrorMessage().show() + } + }, { + loadState.value = LoadState.Fail + it.printStackTrace() + }) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/widgets/ChangePasswordDialog.kt b/app/src/main/java/com/casic/qd/smartwell/widgets/ChangePasswordDialog.kt new file mode 100644 index 0000000..98ff307 --- /dev/null +++ b/app/src/main/java/com/casic/qd/smartwell/widgets/ChangePasswordDialog.kt @@ -0,0 +1,81 @@ +package com.casic.qd.smartwell.widgets + +import android.app.Dialog +import android.content.Context +import android.os.Bundle +import android.view.Gravity +import com.casic.qd.smartwell.R +import com.casic.qd.smartwell.extensions.initDialogLayoutParams +import com.casic.qd.smartwell.extensions.isLetterAndDigit +import com.casic.qd.smartwell.extensions.show +import kotlinx.android.synthetic.main.dialog_change_pwd.* + + +/** + * @author: Pengxh + * @email: 290677893@qq.com + * @date: 2020/11/6 22:12 + */ +class ChangePasswordDialog private constructor(builder: Builder) : + Dialog(builder.context, R.style.UserDefinedDialogStyle) { + + private val listener: OnDialogButtonClickListener = builder.listener + + class Builder { + lateinit var context: Context + lateinit var listener: OnDialogButtonClickListener + + fun setContext(context: Context): Builder { + this.context = context + return this + } + + fun setOnDialogButtonClickListener(listener: OnDialogButtonClickListener): Builder { + this.listener = listener + return this + } + + fun build(): ChangePasswordDialog { + return ChangePasswordDialog(this) + } + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + this.initDialogLayoutParams(Gravity.CENTER, R.style.UserDefinedAnimation, 0.85f) + setContentView(R.layout.dialog_change_pwd) + setCancelable(true) + setCanceledOnTouchOutside(true) + + confirmButton.setChangeAlphaWhenPress(true) + confirmButton.setOnClickListener { + val oldPwd = oldPwdView.text.toString() + val newPwd = newPwdView.text.toString() + val confirmPwd = confirmPwdView.text.toString() + if (oldPwd.isBlank()) { + "请输入原密码".show() + return@setOnClickListener + } + if (newPwd.isBlank()) { + "请输入新密码".show() + return@setOnClickListener + } + if (confirmPwd.isBlank()) { + "请在此确认密码".show() + return@setOnClickListener + } + if (!newPwd.isLetterAndDigit()) { + "新密码需包含数字和字母".show() + } + if (newPwd != confirmPwd) { + "新密码和确认密码不一致,请检查".show() + return@setOnClickListener + } + listener.onConfirmClick(oldPwd, newPwd) + } + } + + interface OnDialogButtonClickListener { + fun onConfirmClick(oldPwd: String, newPwd: String) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/widgets/MarqueeTextView.kt b/app/src/main/java/com/casic/qd/smartwell/widgets/MarqueeTextView.kt new file mode 100644 index 0000000..520f6ae --- /dev/null +++ b/app/src/main/java/com/casic/qd/smartwell/widgets/MarqueeTextView.kt @@ -0,0 +1,13 @@ +package com.casic.qd.smartwell.widgets + +import android.content.Context +import android.util.AttributeSet +import androidx.appcompat.widget.AppCompatTextView + +class MarqueeTextView(context: Context, attrs: AttributeSet? = null) : + AppCompatTextView(context, attrs) { + + override fun isFocused(): Boolean { + return true //自动获取焦点 + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/widgets/ShareDialog.kt b/app/src/main/java/com/casic/qd/smartwell/widgets/ShareDialog.kt new file mode 100644 index 0000000..377febc --- /dev/null +++ b/app/src/main/java/com/casic/qd/smartwell/widgets/ShareDialog.kt @@ -0,0 +1,54 @@ +package com.casic.qd.smartwell.widgets + +import android.content.Context +import android.graphics.Bitmap +import android.os.Bundle +import androidx.appcompat.app.AlertDialog +import com.casic.qd.smartwell.R +import kotlinx.android.synthetic.main.dialog_share.* + +/** + * @author: Pengxh + * @email: 290677893@qq.com + */ +class ShareDialog private constructor(builder: Builder) : + AlertDialog(builder.context, R.style.UserDefinedDialogStyle) { + + private var title: String = builder.title + private var bitmap: Bitmap = builder.bitmap + + class Builder { + lateinit var context: Context + lateinit var title: String + lateinit var bitmap: Bitmap + + fun setContext(context: Context): Builder { + this.context = context + return this + } + + fun setDialogTitle(title: String): Builder { + this.title = title + return this + } + + fun setDialogBitmap(bitmap: Bitmap): Builder { + this.bitmap = bitmap + return this + } + + fun build(): ShareDialog { + return ShareDialog(this) + } + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.dialog_share) + setCanceledOnTouchOutside(true) + setCancelable(true) + + shareTitleView.text = title + codeView.setImageBitmap(bitmap) + } +} \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_change_pwd.xml b/app/src/main/res/drawable/ic_change_pwd.xml new file mode 100644 index 0000000..708f7bf --- /dev/null +++ b/app/src/main/res/drawable/ic_change_pwd.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_login_out.xml b/app/src/main/res/drawable/ic_login_out.xml index 208a666..e07996c 100644 --- a/app/src/main/res/drawable/ic_login_out.xml +++ b/app/src/main/res/drawable/ic_login_out.xml @@ -4,9 +4,9 @@ android:viewportWidth="1024" android:viewportHeight="1024"> diff --git a/app/src/main/res/drawable/ic_menu.xml b/app/src/main/res/drawable/ic_menu.xml new file mode 100644 index 0000000..eabc132 --- /dev/null +++ b/app/src/main/res/drawable/ic_menu.xml @@ -0,0 +1,24 @@ + + + + + + + + diff --git a/app/build.gradle b/app/build.gradle index ca124d1..aec7047 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -99,4 +99,6 @@ implementation 'com.jzxiang.pickerview:TimePickerDialog:1.0.1' //Html解析,爬虫 implementation 'org.jsoup:jsoup:1.14.3' + //ZBar(综合Java和C++扫码),生成二维码 + implementation 'cn.bertsir.zbarLibary:zbarlibary:1.4.2' } \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/extensions/String.kt b/app/src/main/java/com/casic/qd/smartwell/extensions/String.kt index 19808ef..6c2525f 100644 --- a/app/src/main/java/com/casic/qd/smartwell/extensions/String.kt +++ b/app/src/main/java/com/casic/qd/smartwell/extensions/String.kt @@ -76,3 +76,16 @@ } return 0 } + +fun String.isLetterAndDigit(): Boolean { + var isDigit = false + var isLetter = false + for (i in this.indices) { + if (Character.isDigit(this[i])) { + isDigit = true + } else if (Character.isLetter(this[i])) { + isLetter = true + } + } + return isDigit && isLetter +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitService.kt b/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitService.kt index 831f862..f133ef4 100644 --- a/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitService.kt +++ b/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitService.kt @@ -43,6 +43,21 @@ suspend fun obtainUserDetail(@Header("token") token: String): String /** + * 修改密码 + * + * @param oldPwd 旧密码 + * @param newPwd 新密码 + */ + @FormUrlEncoded + @POST("/mgr/changePwd") + suspend fun changePassword( + @Header("token") token: String, + @Field("oldPwd") oldPwd: String, + @Field("newPwd") newPwd: String + ): String + + + /** * 用水统计 */ @GET("/waterStatistic/overview") diff --git a/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitServiceManager.kt index e446f48..9ee4cc1 100644 --- a/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitServiceManager.kt @@ -38,6 +38,13 @@ } /** + * 修改密码 + */ + suspend fun changePassword(oldPwd: String, newPwd: String): String { + return api.changePassword(AuthenticationHelper.token!!, oldPwd, newPwd) + } + + /** * 用水统计 */ suspend fun waterStatistics(): String { diff --git a/app/src/main/java/com/casic/qd/smartwell/view/MainActivity.kt b/app/src/main/java/com/casic/qd/smartwell/view/MainActivity.kt index 8f41c87..d8af9d8 100644 --- a/app/src/main/java/com/casic/qd/smartwell/view/MainActivity.kt +++ b/app/src/main/java/com/casic/qd/smartwell/view/MainActivity.kt @@ -1,11 +1,12 @@ package com.casic.qd.smartwell.view import android.content.Context -import android.os.Handler -import android.os.Looper -import android.os.Message import android.util.Log import android.view.KeyEvent +import android.view.MenuItem +import android.view.View +import androidx.core.view.GravityCompat +import androidx.drawerlayout.widget.DrawerLayout import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.GridLayoutManager @@ -16,10 +17,14 @@ import com.casic.qd.smartwell.extensions.* import com.casic.qd.smartwell.model.BannerImageModel import com.casic.qd.smartwell.model.LineChartEntryModel +import com.casic.qd.smartwell.model.UserDetailModel import com.casic.qd.smartwell.utils.* +import com.casic.qd.smartwell.vm.ChangePasswordViewModel import com.casic.qd.smartwell.vm.LoginViewModel import com.casic.qd.smartwell.vm.WaterStatisticsViewModel +import com.casic.qd.smartwell.widgets.ChangePasswordDialog import com.github.mikephil.charting.data.Entry +import com.google.android.material.navigation.NavigationView import com.google.gson.Gson import com.google.gson.reflect.TypeToken import com.pengxh.app.multilib.widget.dialog.AlertControlDialog @@ -29,22 +34,29 @@ import com.youth.banner.holder.BannerImageHolder import com.youth.banner.indicator.CircleIndicator import com.youth.banner.transformer.ScaleInTransformer +import kotlinx.android.synthetic.main.activity_data_search.* import kotlinx.android.synthetic.main.activity_main.* -import java.lang.ref.WeakReference +import kotlinx.android.synthetic.main.activity_main.rightOptionView +import kotlinx.android.synthetic.main.activity_main.titleView +import kotlinx.android.synthetic.main.activity_main.view.* +import kotlinx.android.synthetic.main.drawer_header_layout.* +import kotlinx.android.synthetic.main.drawer_header_layout.view.* +import java.nio.charset.StandardCharsets import java.util.* import kotlin.collections.ArrayList -class MainActivity : BaseActivity() { +class MainActivity : BaseActivity(), DrawerLayout.DrawerListener, + NavigationView.OnNavigationItemSelectedListener { private val kTag = "MainActivity" private val context: Context = this@MainActivity private var clickTime: Long = 0 private lateinit var loginViewModel: LoginViewModel private lateinit var waterViewModel: WaterStatisticsViewModel + private lateinit var changePwdViewModel: ChangePasswordViewModel private val xAxisDate: MutableList = ArrayList() private val entryModels: MutableList = ArrayList() private var imageModels: MutableList = ArrayList() - private lateinit var weakReferenceHandler: WeakReferenceHandler override fun initLayoutView(): Int = R.layout.activity_main @@ -53,10 +65,10 @@ } override fun initData() { - val bannerJsonModel = SaveKeyValues.getValue(Constant.BANNER_MODEL, "") as String - if (bannerJsonModel.isNotBlank()) { + val bannerJson = SaveKeyValues.getValue(Constant.BANNER_MODEL, "") as String + if (bannerJson.isNotBlank()) { imageModels = Gson().fromJson( - bannerJsonModel, object : TypeToken>() {}.type + bannerJson, object : TypeToken>() {}.type ) } else { Constant.NEWS_PAGE.forEach { @@ -127,26 +139,19 @@ //初始化vm loginViewModel = ViewModelProvider(this).get(LoginViewModel::class.java) waterViewModel = ViewModelProvider(this).get(WaterStatisticsViewModel::class.java) - weakReferenceHandler = WeakReferenceHandler(this) + changePwdViewModel = ViewModelProvider(this).get(ChangePasswordViewModel::class.java) } override fun initEvent() { leftOptionView.setOnClickListener { - AlertControlDialog.Builder() - .setContext(this) - .setTitle("退出登录") - .setMessage("确定要退出吗?") - .setNegativeButton("取消") - .setPositiveButton("确定") - .setOnDialogButtonClickListener(object : - AlertControlDialog.OnDialogButtonClickListener { - override fun onConfirmClick() { - loginViewModel.out() - } - - override fun onCancelClick() {} - }).build().show() + if (leftDrawerLayout.isDrawerOpen(GravityCompat.START)) { + leftDrawerLayout.closeDrawer(GravityCompat.START) + } else { + leftDrawerLayout.openDrawer(GravityCompat.START) + } } + leftDrawerLayout.addDrawerListener(this) + navigationView.setNavigationItemSelectedListener(this) loginViewModel.loadState.observe(this, { if (it == LoadState.Success) { AuthenticationHelper.removeToken() @@ -205,19 +210,108 @@ expandChartView.setOnClickListener { navigatePageTo(WaterExpandedActivity::class.java) } + + changePwdViewModel.loadState.observe(this, { + when (it) { + is LoadState.Loading -> { + DialogHelper.showLoadingDialog(this, "修改中,请稍后") + } + is LoadState.Success -> { + DialogHelper.dismissLoadingDialog() + AuthenticationHelper.removeToken() + this.navigatePageTo(LoginActivity::class.java) + PageNavigationManager.finishAllActivity() + } + else -> { + DialogHelper.dismissLoadingDialog() + } + } + }) } - private class WeakReferenceHandler(activity: MainActivity) : Handler(Looper.getMainLooper()) { + override fun onDrawerSlide(drawerView: View, slideOffset: Float) { - private val reference: WeakReference = WeakReference(activity) + } - override fun handleMessage(msg: Message) { - super.handleMessage(msg) - val activity = reference.get()!! - + override fun onDrawerOpened(drawerView: View) { + val userDetailJson = SaveKeyValues.getValue(Constant.USER_DETAIL_MODEL, "") as String + if (userDetailJson.isNotBlank()) { + val userDetail = Gson().fromJson( + userDetailJson, object : TypeToken() {}.type + ) + userNameView.text = userDetail.name + userDeptView.text = userDetail.deptName + userRoleView.text = userDetail.roleNames.toString() } } + override fun onDrawerClosed(drawerView: View) { + + } + + override fun onDrawerStateChanged(newState: Int) { + + } + + override fun onNavigationItemSelected(item: MenuItem): Boolean { + when (item.itemId) { + R.id.changePwdView -> { + ChangePasswordDialog.Builder() + .setContext(this) + .setOnDialogButtonClickListener(object : + ChangePasswordDialog.OnDialogButtonClickListener { + override fun onConfirmClick(oldPwd: String, newPwd: String) { + val publicKey = + RSAUtils.keyStrToPublicKey(AuthenticationHelper.publicKey)!! + val oldPassKey = RSAUtils.encryptDataByPublicKey( + oldPwd.toByteArray(StandardCharsets.UTF_8), + publicKey + ) + val newPassKey = RSAUtils.encryptDataByPublicKey( + newPwd.toByteArray(StandardCharsets.UTF_8), + publicKey + ) + changePwdViewModel.changePassword(oldPassKey, newPassKey) + } + }).build().show() + } + R.id.shareApkView -> { + //apk服务器下载地址 +// val downloadPath = "1111" +// val createCodeBitmap = QRUtils.getInstance().createQRCode( +// downloadPath, +// SizeUtil.dp2px(this, 300f), +// SizeUtil.dp2px(this, 300f) +// ) +// ShareDialog.Builder() +// .setContext(this) +// .setDialogTitle("扫以下二维码就可以下载本应用") +// .setDialogBitmap(createCodeBitmap).build().show() + "尽情期待~".show() + } + R.id.versionNameView -> { + "已是最新版本,无需更新".show() + } + R.id.loginOutView -> { + AlertControlDialog.Builder() + .setContext(this) + .setTitle("退出登录") + .setMessage("确定要退出吗?") + .setNegativeButton("取消") + .setPositiveButton("确定") + .setOnDialogButtonClickListener(object : + AlertControlDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + loginViewModel.out() + } + + override fun onCancelClick() {} + }).build().show() + } + } + return false + } + override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { return if (keyCode == KeyEvent.KEYCODE_BACK) { if (System.currentTimeMillis() - clickTime > 2000) { diff --git a/app/src/main/java/com/casic/qd/smartwell/vm/ChangePasswordViewModel.kt b/app/src/main/java/com/casic/qd/smartwell/vm/ChangePasswordViewModel.kt new file mode 100644 index 0000000..751a5f4 --- /dev/null +++ b/app/src/main/java/com/casic/qd/smartwell/vm/ChangePasswordViewModel.kt @@ -0,0 +1,28 @@ +package com.casic.qd.smartwell.vm + +import com.casic.qd.smartwell.base.BaseViewModel +import com.casic.qd.smartwell.extensions.launch +import com.casic.qd.smartwell.extensions.separateResponseCode +import com.casic.qd.smartwell.extensions.show +import com.casic.qd.smartwell.extensions.toErrorMessage +import com.casic.qd.smartwell.utils.LoadState +import com.casic.qd.smartwell.utils.retrofit.RetrofitServiceManager + +class ChangePasswordViewModel : BaseViewModel() { + + fun changePassword(oldPwd: String, newPwd: String) = launch({ + loadState.value = LoadState.Loading + val response = RetrofitServiceManager.changePassword(oldPwd, newPwd) + val responseCode = response.separateResponseCode() + if (responseCode == 200) { + loadState.value = LoadState.Success + "修改成功,请重新登录".show() + } else { + loadState.value = LoadState.Fail + response.toErrorMessage().show() + } + }, { + loadState.value = LoadState.Fail + it.printStackTrace() + }) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/widgets/ChangePasswordDialog.kt b/app/src/main/java/com/casic/qd/smartwell/widgets/ChangePasswordDialog.kt new file mode 100644 index 0000000..98ff307 --- /dev/null +++ b/app/src/main/java/com/casic/qd/smartwell/widgets/ChangePasswordDialog.kt @@ -0,0 +1,81 @@ +package com.casic.qd.smartwell.widgets + +import android.app.Dialog +import android.content.Context +import android.os.Bundle +import android.view.Gravity +import com.casic.qd.smartwell.R +import com.casic.qd.smartwell.extensions.initDialogLayoutParams +import com.casic.qd.smartwell.extensions.isLetterAndDigit +import com.casic.qd.smartwell.extensions.show +import kotlinx.android.synthetic.main.dialog_change_pwd.* + + +/** + * @author: Pengxh + * @email: 290677893@qq.com + * @date: 2020/11/6 22:12 + */ +class ChangePasswordDialog private constructor(builder: Builder) : + Dialog(builder.context, R.style.UserDefinedDialogStyle) { + + private val listener: OnDialogButtonClickListener = builder.listener + + class Builder { + lateinit var context: Context + lateinit var listener: OnDialogButtonClickListener + + fun setContext(context: Context): Builder { + this.context = context + return this + } + + fun setOnDialogButtonClickListener(listener: OnDialogButtonClickListener): Builder { + this.listener = listener + return this + } + + fun build(): ChangePasswordDialog { + return ChangePasswordDialog(this) + } + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + this.initDialogLayoutParams(Gravity.CENTER, R.style.UserDefinedAnimation, 0.85f) + setContentView(R.layout.dialog_change_pwd) + setCancelable(true) + setCanceledOnTouchOutside(true) + + confirmButton.setChangeAlphaWhenPress(true) + confirmButton.setOnClickListener { + val oldPwd = oldPwdView.text.toString() + val newPwd = newPwdView.text.toString() + val confirmPwd = confirmPwdView.text.toString() + if (oldPwd.isBlank()) { + "请输入原密码".show() + return@setOnClickListener + } + if (newPwd.isBlank()) { + "请输入新密码".show() + return@setOnClickListener + } + if (confirmPwd.isBlank()) { + "请在此确认密码".show() + return@setOnClickListener + } + if (!newPwd.isLetterAndDigit()) { + "新密码需包含数字和字母".show() + } + if (newPwd != confirmPwd) { + "新密码和确认密码不一致,请检查".show() + return@setOnClickListener + } + listener.onConfirmClick(oldPwd, newPwd) + } + } + + interface OnDialogButtonClickListener { + fun onConfirmClick(oldPwd: String, newPwd: String) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/widgets/MarqueeTextView.kt b/app/src/main/java/com/casic/qd/smartwell/widgets/MarqueeTextView.kt new file mode 100644 index 0000000..520f6ae --- /dev/null +++ b/app/src/main/java/com/casic/qd/smartwell/widgets/MarqueeTextView.kt @@ -0,0 +1,13 @@ +package com.casic.qd.smartwell.widgets + +import android.content.Context +import android.util.AttributeSet +import androidx.appcompat.widget.AppCompatTextView + +class MarqueeTextView(context: Context, attrs: AttributeSet? = null) : + AppCompatTextView(context, attrs) { + + override fun isFocused(): Boolean { + return true //自动获取焦点 + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/widgets/ShareDialog.kt b/app/src/main/java/com/casic/qd/smartwell/widgets/ShareDialog.kt new file mode 100644 index 0000000..377febc --- /dev/null +++ b/app/src/main/java/com/casic/qd/smartwell/widgets/ShareDialog.kt @@ -0,0 +1,54 @@ +package com.casic.qd.smartwell.widgets + +import android.content.Context +import android.graphics.Bitmap +import android.os.Bundle +import androidx.appcompat.app.AlertDialog +import com.casic.qd.smartwell.R +import kotlinx.android.synthetic.main.dialog_share.* + +/** + * @author: Pengxh + * @email: 290677893@qq.com + */ +class ShareDialog private constructor(builder: Builder) : + AlertDialog(builder.context, R.style.UserDefinedDialogStyle) { + + private var title: String = builder.title + private var bitmap: Bitmap = builder.bitmap + + class Builder { + lateinit var context: Context + lateinit var title: String + lateinit var bitmap: Bitmap + + fun setContext(context: Context): Builder { + this.context = context + return this + } + + fun setDialogTitle(title: String): Builder { + this.title = title + return this + } + + fun setDialogBitmap(bitmap: Bitmap): Builder { + this.bitmap = bitmap + return this + } + + fun build(): ShareDialog { + return ShareDialog(this) + } + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.dialog_share) + setCanceledOnTouchOutside(true) + setCancelable(true) + + shareTitleView.text = title + codeView.setImageBitmap(bitmap) + } +} \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_change_pwd.xml b/app/src/main/res/drawable/ic_change_pwd.xml new file mode 100644 index 0000000..708f7bf --- /dev/null +++ b/app/src/main/res/drawable/ic_change_pwd.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_login_out.xml b/app/src/main/res/drawable/ic_login_out.xml index 208a666..e07996c 100644 --- a/app/src/main/res/drawable/ic_login_out.xml +++ b/app/src/main/res/drawable/ic_login_out.xml @@ -4,9 +4,9 @@ android:viewportWidth="1024" android:viewportHeight="1024"> diff --git a/app/src/main/res/drawable/ic_menu.xml b/app/src/main/res/drawable/ic_menu.xml new file mode 100644 index 0000000..eabc132 --- /dev/null +++ b/app/src/main/res/drawable/ic_menu.xml @@ -0,0 +1,24 @@ + + + + + + + + diff --git a/app/src/main/res/drawable/ic_share.xml b/app/src/main/res/drawable/ic_share.xml new file mode 100644 index 0000000..e309ad4 --- /dev/null +++ b/app/src/main/res/drawable/ic_share.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/build.gradle b/app/build.gradle index ca124d1..aec7047 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -99,4 +99,6 @@ implementation 'com.jzxiang.pickerview:TimePickerDialog:1.0.1' //Html解析,爬虫 implementation 'org.jsoup:jsoup:1.14.3' + //ZBar(综合Java和C++扫码),生成二维码 + implementation 'cn.bertsir.zbarLibary:zbarlibary:1.4.2' } \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/extensions/String.kt b/app/src/main/java/com/casic/qd/smartwell/extensions/String.kt index 19808ef..6c2525f 100644 --- a/app/src/main/java/com/casic/qd/smartwell/extensions/String.kt +++ b/app/src/main/java/com/casic/qd/smartwell/extensions/String.kt @@ -76,3 +76,16 @@ } return 0 } + +fun String.isLetterAndDigit(): Boolean { + var isDigit = false + var isLetter = false + for (i in this.indices) { + if (Character.isDigit(this[i])) { + isDigit = true + } else if (Character.isLetter(this[i])) { + isLetter = true + } + } + return isDigit && isLetter +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitService.kt b/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitService.kt index 831f862..f133ef4 100644 --- a/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitService.kt +++ b/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitService.kt @@ -43,6 +43,21 @@ suspend fun obtainUserDetail(@Header("token") token: String): String /** + * 修改密码 + * + * @param oldPwd 旧密码 + * @param newPwd 新密码 + */ + @FormUrlEncoded + @POST("/mgr/changePwd") + suspend fun changePassword( + @Header("token") token: String, + @Field("oldPwd") oldPwd: String, + @Field("newPwd") newPwd: String + ): String + + + /** * 用水统计 */ @GET("/waterStatistic/overview") diff --git a/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitServiceManager.kt index e446f48..9ee4cc1 100644 --- a/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitServiceManager.kt @@ -38,6 +38,13 @@ } /** + * 修改密码 + */ + suspend fun changePassword(oldPwd: String, newPwd: String): String { + return api.changePassword(AuthenticationHelper.token!!, oldPwd, newPwd) + } + + /** * 用水统计 */ suspend fun waterStatistics(): String { diff --git a/app/src/main/java/com/casic/qd/smartwell/view/MainActivity.kt b/app/src/main/java/com/casic/qd/smartwell/view/MainActivity.kt index 8f41c87..d8af9d8 100644 --- a/app/src/main/java/com/casic/qd/smartwell/view/MainActivity.kt +++ b/app/src/main/java/com/casic/qd/smartwell/view/MainActivity.kt @@ -1,11 +1,12 @@ package com.casic.qd.smartwell.view import android.content.Context -import android.os.Handler -import android.os.Looper -import android.os.Message import android.util.Log import android.view.KeyEvent +import android.view.MenuItem +import android.view.View +import androidx.core.view.GravityCompat +import androidx.drawerlayout.widget.DrawerLayout import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.GridLayoutManager @@ -16,10 +17,14 @@ import com.casic.qd.smartwell.extensions.* import com.casic.qd.smartwell.model.BannerImageModel import com.casic.qd.smartwell.model.LineChartEntryModel +import com.casic.qd.smartwell.model.UserDetailModel import com.casic.qd.smartwell.utils.* +import com.casic.qd.smartwell.vm.ChangePasswordViewModel import com.casic.qd.smartwell.vm.LoginViewModel import com.casic.qd.smartwell.vm.WaterStatisticsViewModel +import com.casic.qd.smartwell.widgets.ChangePasswordDialog import com.github.mikephil.charting.data.Entry +import com.google.android.material.navigation.NavigationView import com.google.gson.Gson import com.google.gson.reflect.TypeToken import com.pengxh.app.multilib.widget.dialog.AlertControlDialog @@ -29,22 +34,29 @@ import com.youth.banner.holder.BannerImageHolder import com.youth.banner.indicator.CircleIndicator import com.youth.banner.transformer.ScaleInTransformer +import kotlinx.android.synthetic.main.activity_data_search.* import kotlinx.android.synthetic.main.activity_main.* -import java.lang.ref.WeakReference +import kotlinx.android.synthetic.main.activity_main.rightOptionView +import kotlinx.android.synthetic.main.activity_main.titleView +import kotlinx.android.synthetic.main.activity_main.view.* +import kotlinx.android.synthetic.main.drawer_header_layout.* +import kotlinx.android.synthetic.main.drawer_header_layout.view.* +import java.nio.charset.StandardCharsets import java.util.* import kotlin.collections.ArrayList -class MainActivity : BaseActivity() { +class MainActivity : BaseActivity(), DrawerLayout.DrawerListener, + NavigationView.OnNavigationItemSelectedListener { private val kTag = "MainActivity" private val context: Context = this@MainActivity private var clickTime: Long = 0 private lateinit var loginViewModel: LoginViewModel private lateinit var waterViewModel: WaterStatisticsViewModel + private lateinit var changePwdViewModel: ChangePasswordViewModel private val xAxisDate: MutableList = ArrayList() private val entryModels: MutableList = ArrayList() private var imageModels: MutableList = ArrayList() - private lateinit var weakReferenceHandler: WeakReferenceHandler override fun initLayoutView(): Int = R.layout.activity_main @@ -53,10 +65,10 @@ } override fun initData() { - val bannerJsonModel = SaveKeyValues.getValue(Constant.BANNER_MODEL, "") as String - if (bannerJsonModel.isNotBlank()) { + val bannerJson = SaveKeyValues.getValue(Constant.BANNER_MODEL, "") as String + if (bannerJson.isNotBlank()) { imageModels = Gson().fromJson( - bannerJsonModel, object : TypeToken>() {}.type + bannerJson, object : TypeToken>() {}.type ) } else { Constant.NEWS_PAGE.forEach { @@ -127,26 +139,19 @@ //初始化vm loginViewModel = ViewModelProvider(this).get(LoginViewModel::class.java) waterViewModel = ViewModelProvider(this).get(WaterStatisticsViewModel::class.java) - weakReferenceHandler = WeakReferenceHandler(this) + changePwdViewModel = ViewModelProvider(this).get(ChangePasswordViewModel::class.java) } override fun initEvent() { leftOptionView.setOnClickListener { - AlertControlDialog.Builder() - .setContext(this) - .setTitle("退出登录") - .setMessage("确定要退出吗?") - .setNegativeButton("取消") - .setPositiveButton("确定") - .setOnDialogButtonClickListener(object : - AlertControlDialog.OnDialogButtonClickListener { - override fun onConfirmClick() { - loginViewModel.out() - } - - override fun onCancelClick() {} - }).build().show() + if (leftDrawerLayout.isDrawerOpen(GravityCompat.START)) { + leftDrawerLayout.closeDrawer(GravityCompat.START) + } else { + leftDrawerLayout.openDrawer(GravityCompat.START) + } } + leftDrawerLayout.addDrawerListener(this) + navigationView.setNavigationItemSelectedListener(this) loginViewModel.loadState.observe(this, { if (it == LoadState.Success) { AuthenticationHelper.removeToken() @@ -205,19 +210,108 @@ expandChartView.setOnClickListener { navigatePageTo(WaterExpandedActivity::class.java) } + + changePwdViewModel.loadState.observe(this, { + when (it) { + is LoadState.Loading -> { + DialogHelper.showLoadingDialog(this, "修改中,请稍后") + } + is LoadState.Success -> { + DialogHelper.dismissLoadingDialog() + AuthenticationHelper.removeToken() + this.navigatePageTo(LoginActivity::class.java) + PageNavigationManager.finishAllActivity() + } + else -> { + DialogHelper.dismissLoadingDialog() + } + } + }) } - private class WeakReferenceHandler(activity: MainActivity) : Handler(Looper.getMainLooper()) { + override fun onDrawerSlide(drawerView: View, slideOffset: Float) { - private val reference: WeakReference = WeakReference(activity) + } - override fun handleMessage(msg: Message) { - super.handleMessage(msg) - val activity = reference.get()!! - + override fun onDrawerOpened(drawerView: View) { + val userDetailJson = SaveKeyValues.getValue(Constant.USER_DETAIL_MODEL, "") as String + if (userDetailJson.isNotBlank()) { + val userDetail = Gson().fromJson( + userDetailJson, object : TypeToken() {}.type + ) + userNameView.text = userDetail.name + userDeptView.text = userDetail.deptName + userRoleView.text = userDetail.roleNames.toString() } } + override fun onDrawerClosed(drawerView: View) { + + } + + override fun onDrawerStateChanged(newState: Int) { + + } + + override fun onNavigationItemSelected(item: MenuItem): Boolean { + when (item.itemId) { + R.id.changePwdView -> { + ChangePasswordDialog.Builder() + .setContext(this) + .setOnDialogButtonClickListener(object : + ChangePasswordDialog.OnDialogButtonClickListener { + override fun onConfirmClick(oldPwd: String, newPwd: String) { + val publicKey = + RSAUtils.keyStrToPublicKey(AuthenticationHelper.publicKey)!! + val oldPassKey = RSAUtils.encryptDataByPublicKey( + oldPwd.toByteArray(StandardCharsets.UTF_8), + publicKey + ) + val newPassKey = RSAUtils.encryptDataByPublicKey( + newPwd.toByteArray(StandardCharsets.UTF_8), + publicKey + ) + changePwdViewModel.changePassword(oldPassKey, newPassKey) + } + }).build().show() + } + R.id.shareApkView -> { + //apk服务器下载地址 +// val downloadPath = "1111" +// val createCodeBitmap = QRUtils.getInstance().createQRCode( +// downloadPath, +// SizeUtil.dp2px(this, 300f), +// SizeUtil.dp2px(this, 300f) +// ) +// ShareDialog.Builder() +// .setContext(this) +// .setDialogTitle("扫以下二维码就可以下载本应用") +// .setDialogBitmap(createCodeBitmap).build().show() + "尽情期待~".show() + } + R.id.versionNameView -> { + "已是最新版本,无需更新".show() + } + R.id.loginOutView -> { + AlertControlDialog.Builder() + .setContext(this) + .setTitle("退出登录") + .setMessage("确定要退出吗?") + .setNegativeButton("取消") + .setPositiveButton("确定") + .setOnDialogButtonClickListener(object : + AlertControlDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + loginViewModel.out() + } + + override fun onCancelClick() {} + }).build().show() + } + } + return false + } + override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { return if (keyCode == KeyEvent.KEYCODE_BACK) { if (System.currentTimeMillis() - clickTime > 2000) { diff --git a/app/src/main/java/com/casic/qd/smartwell/vm/ChangePasswordViewModel.kt b/app/src/main/java/com/casic/qd/smartwell/vm/ChangePasswordViewModel.kt new file mode 100644 index 0000000..751a5f4 --- /dev/null +++ b/app/src/main/java/com/casic/qd/smartwell/vm/ChangePasswordViewModel.kt @@ -0,0 +1,28 @@ +package com.casic.qd.smartwell.vm + +import com.casic.qd.smartwell.base.BaseViewModel +import com.casic.qd.smartwell.extensions.launch +import com.casic.qd.smartwell.extensions.separateResponseCode +import com.casic.qd.smartwell.extensions.show +import com.casic.qd.smartwell.extensions.toErrorMessage +import com.casic.qd.smartwell.utils.LoadState +import com.casic.qd.smartwell.utils.retrofit.RetrofitServiceManager + +class ChangePasswordViewModel : BaseViewModel() { + + fun changePassword(oldPwd: String, newPwd: String) = launch({ + loadState.value = LoadState.Loading + val response = RetrofitServiceManager.changePassword(oldPwd, newPwd) + val responseCode = response.separateResponseCode() + if (responseCode == 200) { + loadState.value = LoadState.Success + "修改成功,请重新登录".show() + } else { + loadState.value = LoadState.Fail + response.toErrorMessage().show() + } + }, { + loadState.value = LoadState.Fail + it.printStackTrace() + }) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/widgets/ChangePasswordDialog.kt b/app/src/main/java/com/casic/qd/smartwell/widgets/ChangePasswordDialog.kt new file mode 100644 index 0000000..98ff307 --- /dev/null +++ b/app/src/main/java/com/casic/qd/smartwell/widgets/ChangePasswordDialog.kt @@ -0,0 +1,81 @@ +package com.casic.qd.smartwell.widgets + +import android.app.Dialog +import android.content.Context +import android.os.Bundle +import android.view.Gravity +import com.casic.qd.smartwell.R +import com.casic.qd.smartwell.extensions.initDialogLayoutParams +import com.casic.qd.smartwell.extensions.isLetterAndDigit +import com.casic.qd.smartwell.extensions.show +import kotlinx.android.synthetic.main.dialog_change_pwd.* + + +/** + * @author: Pengxh + * @email: 290677893@qq.com + * @date: 2020/11/6 22:12 + */ +class ChangePasswordDialog private constructor(builder: Builder) : + Dialog(builder.context, R.style.UserDefinedDialogStyle) { + + private val listener: OnDialogButtonClickListener = builder.listener + + class Builder { + lateinit var context: Context + lateinit var listener: OnDialogButtonClickListener + + fun setContext(context: Context): Builder { + this.context = context + return this + } + + fun setOnDialogButtonClickListener(listener: OnDialogButtonClickListener): Builder { + this.listener = listener + return this + } + + fun build(): ChangePasswordDialog { + return ChangePasswordDialog(this) + } + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + this.initDialogLayoutParams(Gravity.CENTER, R.style.UserDefinedAnimation, 0.85f) + setContentView(R.layout.dialog_change_pwd) + setCancelable(true) + setCanceledOnTouchOutside(true) + + confirmButton.setChangeAlphaWhenPress(true) + confirmButton.setOnClickListener { + val oldPwd = oldPwdView.text.toString() + val newPwd = newPwdView.text.toString() + val confirmPwd = confirmPwdView.text.toString() + if (oldPwd.isBlank()) { + "请输入原密码".show() + return@setOnClickListener + } + if (newPwd.isBlank()) { + "请输入新密码".show() + return@setOnClickListener + } + if (confirmPwd.isBlank()) { + "请在此确认密码".show() + return@setOnClickListener + } + if (!newPwd.isLetterAndDigit()) { + "新密码需包含数字和字母".show() + } + if (newPwd != confirmPwd) { + "新密码和确认密码不一致,请检查".show() + return@setOnClickListener + } + listener.onConfirmClick(oldPwd, newPwd) + } + } + + interface OnDialogButtonClickListener { + fun onConfirmClick(oldPwd: String, newPwd: String) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/widgets/MarqueeTextView.kt b/app/src/main/java/com/casic/qd/smartwell/widgets/MarqueeTextView.kt new file mode 100644 index 0000000..520f6ae --- /dev/null +++ b/app/src/main/java/com/casic/qd/smartwell/widgets/MarqueeTextView.kt @@ -0,0 +1,13 @@ +package com.casic.qd.smartwell.widgets + +import android.content.Context +import android.util.AttributeSet +import androidx.appcompat.widget.AppCompatTextView + +class MarqueeTextView(context: Context, attrs: AttributeSet? = null) : + AppCompatTextView(context, attrs) { + + override fun isFocused(): Boolean { + return true //自动获取焦点 + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/widgets/ShareDialog.kt b/app/src/main/java/com/casic/qd/smartwell/widgets/ShareDialog.kt new file mode 100644 index 0000000..377febc --- /dev/null +++ b/app/src/main/java/com/casic/qd/smartwell/widgets/ShareDialog.kt @@ -0,0 +1,54 @@ +package com.casic.qd.smartwell.widgets + +import android.content.Context +import android.graphics.Bitmap +import android.os.Bundle +import androidx.appcompat.app.AlertDialog +import com.casic.qd.smartwell.R +import kotlinx.android.synthetic.main.dialog_share.* + +/** + * @author: Pengxh + * @email: 290677893@qq.com + */ +class ShareDialog private constructor(builder: Builder) : + AlertDialog(builder.context, R.style.UserDefinedDialogStyle) { + + private var title: String = builder.title + private var bitmap: Bitmap = builder.bitmap + + class Builder { + lateinit var context: Context + lateinit var title: String + lateinit var bitmap: Bitmap + + fun setContext(context: Context): Builder { + this.context = context + return this + } + + fun setDialogTitle(title: String): Builder { + this.title = title + return this + } + + fun setDialogBitmap(bitmap: Bitmap): Builder { + this.bitmap = bitmap + return this + } + + fun build(): ShareDialog { + return ShareDialog(this) + } + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.dialog_share) + setCanceledOnTouchOutside(true) + setCancelable(true) + + shareTitleView.text = title + codeView.setImageBitmap(bitmap) + } +} \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_change_pwd.xml b/app/src/main/res/drawable/ic_change_pwd.xml new file mode 100644 index 0000000..708f7bf --- /dev/null +++ b/app/src/main/res/drawable/ic_change_pwd.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_login_out.xml b/app/src/main/res/drawable/ic_login_out.xml index 208a666..e07996c 100644 --- a/app/src/main/res/drawable/ic_login_out.xml +++ b/app/src/main/res/drawable/ic_login_out.xml @@ -4,9 +4,9 @@ android:viewportWidth="1024" android:viewportHeight="1024"> diff --git a/app/src/main/res/drawable/ic_menu.xml b/app/src/main/res/drawable/ic_menu.xml new file mode 100644 index 0000000..eabc132 --- /dev/null +++ b/app/src/main/res/drawable/ic_menu.xml @@ -0,0 +1,24 @@ + + + + + + + + diff --git a/app/src/main/res/drawable/ic_share.xml b/app/src/main/res/drawable/ic_share.xml new file mode 100644 index 0000000..e309ad4 --- /dev/null +++ b/app/src/main/res/drawable/ic_share.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_update.xml b/app/src/main/res/drawable/ic_update.xml new file mode 100644 index 0000000..4aa8aa9 --- /dev/null +++ b/app/src/main/res/drawable/ic_update.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/build.gradle b/app/build.gradle index ca124d1..aec7047 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -99,4 +99,6 @@ implementation 'com.jzxiang.pickerview:TimePickerDialog:1.0.1' //Html解析,爬虫 implementation 'org.jsoup:jsoup:1.14.3' + //ZBar(综合Java和C++扫码),生成二维码 + implementation 'cn.bertsir.zbarLibary:zbarlibary:1.4.2' } \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/extensions/String.kt b/app/src/main/java/com/casic/qd/smartwell/extensions/String.kt index 19808ef..6c2525f 100644 --- a/app/src/main/java/com/casic/qd/smartwell/extensions/String.kt +++ b/app/src/main/java/com/casic/qd/smartwell/extensions/String.kt @@ -76,3 +76,16 @@ } return 0 } + +fun String.isLetterAndDigit(): Boolean { + var isDigit = false + var isLetter = false + for (i in this.indices) { + if (Character.isDigit(this[i])) { + isDigit = true + } else if (Character.isLetter(this[i])) { + isLetter = true + } + } + return isDigit && isLetter +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitService.kt b/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitService.kt index 831f862..f133ef4 100644 --- a/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitService.kt +++ b/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitService.kt @@ -43,6 +43,21 @@ suspend fun obtainUserDetail(@Header("token") token: String): String /** + * 修改密码 + * + * @param oldPwd 旧密码 + * @param newPwd 新密码 + */ + @FormUrlEncoded + @POST("/mgr/changePwd") + suspend fun changePassword( + @Header("token") token: String, + @Field("oldPwd") oldPwd: String, + @Field("newPwd") newPwd: String + ): String + + + /** * 用水统计 */ @GET("/waterStatistic/overview") diff --git a/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitServiceManager.kt index e446f48..9ee4cc1 100644 --- a/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitServiceManager.kt @@ -38,6 +38,13 @@ } /** + * 修改密码 + */ + suspend fun changePassword(oldPwd: String, newPwd: String): String { + return api.changePassword(AuthenticationHelper.token!!, oldPwd, newPwd) + } + + /** * 用水统计 */ suspend fun waterStatistics(): String { diff --git a/app/src/main/java/com/casic/qd/smartwell/view/MainActivity.kt b/app/src/main/java/com/casic/qd/smartwell/view/MainActivity.kt index 8f41c87..d8af9d8 100644 --- a/app/src/main/java/com/casic/qd/smartwell/view/MainActivity.kt +++ b/app/src/main/java/com/casic/qd/smartwell/view/MainActivity.kt @@ -1,11 +1,12 @@ package com.casic.qd.smartwell.view import android.content.Context -import android.os.Handler -import android.os.Looper -import android.os.Message import android.util.Log import android.view.KeyEvent +import android.view.MenuItem +import android.view.View +import androidx.core.view.GravityCompat +import androidx.drawerlayout.widget.DrawerLayout import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.GridLayoutManager @@ -16,10 +17,14 @@ import com.casic.qd.smartwell.extensions.* import com.casic.qd.smartwell.model.BannerImageModel import com.casic.qd.smartwell.model.LineChartEntryModel +import com.casic.qd.smartwell.model.UserDetailModel import com.casic.qd.smartwell.utils.* +import com.casic.qd.smartwell.vm.ChangePasswordViewModel import com.casic.qd.smartwell.vm.LoginViewModel import com.casic.qd.smartwell.vm.WaterStatisticsViewModel +import com.casic.qd.smartwell.widgets.ChangePasswordDialog import com.github.mikephil.charting.data.Entry +import com.google.android.material.navigation.NavigationView import com.google.gson.Gson import com.google.gson.reflect.TypeToken import com.pengxh.app.multilib.widget.dialog.AlertControlDialog @@ -29,22 +34,29 @@ import com.youth.banner.holder.BannerImageHolder import com.youth.banner.indicator.CircleIndicator import com.youth.banner.transformer.ScaleInTransformer +import kotlinx.android.synthetic.main.activity_data_search.* import kotlinx.android.synthetic.main.activity_main.* -import java.lang.ref.WeakReference +import kotlinx.android.synthetic.main.activity_main.rightOptionView +import kotlinx.android.synthetic.main.activity_main.titleView +import kotlinx.android.synthetic.main.activity_main.view.* +import kotlinx.android.synthetic.main.drawer_header_layout.* +import kotlinx.android.synthetic.main.drawer_header_layout.view.* +import java.nio.charset.StandardCharsets import java.util.* import kotlin.collections.ArrayList -class MainActivity : BaseActivity() { +class MainActivity : BaseActivity(), DrawerLayout.DrawerListener, + NavigationView.OnNavigationItemSelectedListener { private val kTag = "MainActivity" private val context: Context = this@MainActivity private var clickTime: Long = 0 private lateinit var loginViewModel: LoginViewModel private lateinit var waterViewModel: WaterStatisticsViewModel + private lateinit var changePwdViewModel: ChangePasswordViewModel private val xAxisDate: MutableList = ArrayList() private val entryModels: MutableList = ArrayList() private var imageModels: MutableList = ArrayList() - private lateinit var weakReferenceHandler: WeakReferenceHandler override fun initLayoutView(): Int = R.layout.activity_main @@ -53,10 +65,10 @@ } override fun initData() { - val bannerJsonModel = SaveKeyValues.getValue(Constant.BANNER_MODEL, "") as String - if (bannerJsonModel.isNotBlank()) { + val bannerJson = SaveKeyValues.getValue(Constant.BANNER_MODEL, "") as String + if (bannerJson.isNotBlank()) { imageModels = Gson().fromJson( - bannerJsonModel, object : TypeToken>() {}.type + bannerJson, object : TypeToken>() {}.type ) } else { Constant.NEWS_PAGE.forEach { @@ -127,26 +139,19 @@ //初始化vm loginViewModel = ViewModelProvider(this).get(LoginViewModel::class.java) waterViewModel = ViewModelProvider(this).get(WaterStatisticsViewModel::class.java) - weakReferenceHandler = WeakReferenceHandler(this) + changePwdViewModel = ViewModelProvider(this).get(ChangePasswordViewModel::class.java) } override fun initEvent() { leftOptionView.setOnClickListener { - AlertControlDialog.Builder() - .setContext(this) - .setTitle("退出登录") - .setMessage("确定要退出吗?") - .setNegativeButton("取消") - .setPositiveButton("确定") - .setOnDialogButtonClickListener(object : - AlertControlDialog.OnDialogButtonClickListener { - override fun onConfirmClick() { - loginViewModel.out() - } - - override fun onCancelClick() {} - }).build().show() + if (leftDrawerLayout.isDrawerOpen(GravityCompat.START)) { + leftDrawerLayout.closeDrawer(GravityCompat.START) + } else { + leftDrawerLayout.openDrawer(GravityCompat.START) + } } + leftDrawerLayout.addDrawerListener(this) + navigationView.setNavigationItemSelectedListener(this) loginViewModel.loadState.observe(this, { if (it == LoadState.Success) { AuthenticationHelper.removeToken() @@ -205,19 +210,108 @@ expandChartView.setOnClickListener { navigatePageTo(WaterExpandedActivity::class.java) } + + changePwdViewModel.loadState.observe(this, { + when (it) { + is LoadState.Loading -> { + DialogHelper.showLoadingDialog(this, "修改中,请稍后") + } + is LoadState.Success -> { + DialogHelper.dismissLoadingDialog() + AuthenticationHelper.removeToken() + this.navigatePageTo(LoginActivity::class.java) + PageNavigationManager.finishAllActivity() + } + else -> { + DialogHelper.dismissLoadingDialog() + } + } + }) } - private class WeakReferenceHandler(activity: MainActivity) : Handler(Looper.getMainLooper()) { + override fun onDrawerSlide(drawerView: View, slideOffset: Float) { - private val reference: WeakReference = WeakReference(activity) + } - override fun handleMessage(msg: Message) { - super.handleMessage(msg) - val activity = reference.get()!! - + override fun onDrawerOpened(drawerView: View) { + val userDetailJson = SaveKeyValues.getValue(Constant.USER_DETAIL_MODEL, "") as String + if (userDetailJson.isNotBlank()) { + val userDetail = Gson().fromJson( + userDetailJson, object : TypeToken() {}.type + ) + userNameView.text = userDetail.name + userDeptView.text = userDetail.deptName + userRoleView.text = userDetail.roleNames.toString() } } + override fun onDrawerClosed(drawerView: View) { + + } + + override fun onDrawerStateChanged(newState: Int) { + + } + + override fun onNavigationItemSelected(item: MenuItem): Boolean { + when (item.itemId) { + R.id.changePwdView -> { + ChangePasswordDialog.Builder() + .setContext(this) + .setOnDialogButtonClickListener(object : + ChangePasswordDialog.OnDialogButtonClickListener { + override fun onConfirmClick(oldPwd: String, newPwd: String) { + val publicKey = + RSAUtils.keyStrToPublicKey(AuthenticationHelper.publicKey)!! + val oldPassKey = RSAUtils.encryptDataByPublicKey( + oldPwd.toByteArray(StandardCharsets.UTF_8), + publicKey + ) + val newPassKey = RSAUtils.encryptDataByPublicKey( + newPwd.toByteArray(StandardCharsets.UTF_8), + publicKey + ) + changePwdViewModel.changePassword(oldPassKey, newPassKey) + } + }).build().show() + } + R.id.shareApkView -> { + //apk服务器下载地址 +// val downloadPath = "1111" +// val createCodeBitmap = QRUtils.getInstance().createQRCode( +// downloadPath, +// SizeUtil.dp2px(this, 300f), +// SizeUtil.dp2px(this, 300f) +// ) +// ShareDialog.Builder() +// .setContext(this) +// .setDialogTitle("扫以下二维码就可以下载本应用") +// .setDialogBitmap(createCodeBitmap).build().show() + "尽情期待~".show() + } + R.id.versionNameView -> { + "已是最新版本,无需更新".show() + } + R.id.loginOutView -> { + AlertControlDialog.Builder() + .setContext(this) + .setTitle("退出登录") + .setMessage("确定要退出吗?") + .setNegativeButton("取消") + .setPositiveButton("确定") + .setOnDialogButtonClickListener(object : + AlertControlDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + loginViewModel.out() + } + + override fun onCancelClick() {} + }).build().show() + } + } + return false + } + override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { return if (keyCode == KeyEvent.KEYCODE_BACK) { if (System.currentTimeMillis() - clickTime > 2000) { diff --git a/app/src/main/java/com/casic/qd/smartwell/vm/ChangePasswordViewModel.kt b/app/src/main/java/com/casic/qd/smartwell/vm/ChangePasswordViewModel.kt new file mode 100644 index 0000000..751a5f4 --- /dev/null +++ b/app/src/main/java/com/casic/qd/smartwell/vm/ChangePasswordViewModel.kt @@ -0,0 +1,28 @@ +package com.casic.qd.smartwell.vm + +import com.casic.qd.smartwell.base.BaseViewModel +import com.casic.qd.smartwell.extensions.launch +import com.casic.qd.smartwell.extensions.separateResponseCode +import com.casic.qd.smartwell.extensions.show +import com.casic.qd.smartwell.extensions.toErrorMessage +import com.casic.qd.smartwell.utils.LoadState +import com.casic.qd.smartwell.utils.retrofit.RetrofitServiceManager + +class ChangePasswordViewModel : BaseViewModel() { + + fun changePassword(oldPwd: String, newPwd: String) = launch({ + loadState.value = LoadState.Loading + val response = RetrofitServiceManager.changePassword(oldPwd, newPwd) + val responseCode = response.separateResponseCode() + if (responseCode == 200) { + loadState.value = LoadState.Success + "修改成功,请重新登录".show() + } else { + loadState.value = LoadState.Fail + response.toErrorMessage().show() + } + }, { + loadState.value = LoadState.Fail + it.printStackTrace() + }) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/widgets/ChangePasswordDialog.kt b/app/src/main/java/com/casic/qd/smartwell/widgets/ChangePasswordDialog.kt new file mode 100644 index 0000000..98ff307 --- /dev/null +++ b/app/src/main/java/com/casic/qd/smartwell/widgets/ChangePasswordDialog.kt @@ -0,0 +1,81 @@ +package com.casic.qd.smartwell.widgets + +import android.app.Dialog +import android.content.Context +import android.os.Bundle +import android.view.Gravity +import com.casic.qd.smartwell.R +import com.casic.qd.smartwell.extensions.initDialogLayoutParams +import com.casic.qd.smartwell.extensions.isLetterAndDigit +import com.casic.qd.smartwell.extensions.show +import kotlinx.android.synthetic.main.dialog_change_pwd.* + + +/** + * @author: Pengxh + * @email: 290677893@qq.com + * @date: 2020/11/6 22:12 + */ +class ChangePasswordDialog private constructor(builder: Builder) : + Dialog(builder.context, R.style.UserDefinedDialogStyle) { + + private val listener: OnDialogButtonClickListener = builder.listener + + class Builder { + lateinit var context: Context + lateinit var listener: OnDialogButtonClickListener + + fun setContext(context: Context): Builder { + this.context = context + return this + } + + fun setOnDialogButtonClickListener(listener: OnDialogButtonClickListener): Builder { + this.listener = listener + return this + } + + fun build(): ChangePasswordDialog { + return ChangePasswordDialog(this) + } + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + this.initDialogLayoutParams(Gravity.CENTER, R.style.UserDefinedAnimation, 0.85f) + setContentView(R.layout.dialog_change_pwd) + setCancelable(true) + setCanceledOnTouchOutside(true) + + confirmButton.setChangeAlphaWhenPress(true) + confirmButton.setOnClickListener { + val oldPwd = oldPwdView.text.toString() + val newPwd = newPwdView.text.toString() + val confirmPwd = confirmPwdView.text.toString() + if (oldPwd.isBlank()) { + "请输入原密码".show() + return@setOnClickListener + } + if (newPwd.isBlank()) { + "请输入新密码".show() + return@setOnClickListener + } + if (confirmPwd.isBlank()) { + "请在此确认密码".show() + return@setOnClickListener + } + if (!newPwd.isLetterAndDigit()) { + "新密码需包含数字和字母".show() + } + if (newPwd != confirmPwd) { + "新密码和确认密码不一致,请检查".show() + return@setOnClickListener + } + listener.onConfirmClick(oldPwd, newPwd) + } + } + + interface OnDialogButtonClickListener { + fun onConfirmClick(oldPwd: String, newPwd: String) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/widgets/MarqueeTextView.kt b/app/src/main/java/com/casic/qd/smartwell/widgets/MarqueeTextView.kt new file mode 100644 index 0000000..520f6ae --- /dev/null +++ b/app/src/main/java/com/casic/qd/smartwell/widgets/MarqueeTextView.kt @@ -0,0 +1,13 @@ +package com.casic.qd.smartwell.widgets + +import android.content.Context +import android.util.AttributeSet +import androidx.appcompat.widget.AppCompatTextView + +class MarqueeTextView(context: Context, attrs: AttributeSet? = null) : + AppCompatTextView(context, attrs) { + + override fun isFocused(): Boolean { + return true //自动获取焦点 + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/widgets/ShareDialog.kt b/app/src/main/java/com/casic/qd/smartwell/widgets/ShareDialog.kt new file mode 100644 index 0000000..377febc --- /dev/null +++ b/app/src/main/java/com/casic/qd/smartwell/widgets/ShareDialog.kt @@ -0,0 +1,54 @@ +package com.casic.qd.smartwell.widgets + +import android.content.Context +import android.graphics.Bitmap +import android.os.Bundle +import androidx.appcompat.app.AlertDialog +import com.casic.qd.smartwell.R +import kotlinx.android.synthetic.main.dialog_share.* + +/** + * @author: Pengxh + * @email: 290677893@qq.com + */ +class ShareDialog private constructor(builder: Builder) : + AlertDialog(builder.context, R.style.UserDefinedDialogStyle) { + + private var title: String = builder.title + private var bitmap: Bitmap = builder.bitmap + + class Builder { + lateinit var context: Context + lateinit var title: String + lateinit var bitmap: Bitmap + + fun setContext(context: Context): Builder { + this.context = context + return this + } + + fun setDialogTitle(title: String): Builder { + this.title = title + return this + } + + fun setDialogBitmap(bitmap: Bitmap): Builder { + this.bitmap = bitmap + return this + } + + fun build(): ShareDialog { + return ShareDialog(this) + } + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.dialog_share) + setCanceledOnTouchOutside(true) + setCancelable(true) + + shareTitleView.text = title + codeView.setImageBitmap(bitmap) + } +} \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_change_pwd.xml b/app/src/main/res/drawable/ic_change_pwd.xml new file mode 100644 index 0000000..708f7bf --- /dev/null +++ b/app/src/main/res/drawable/ic_change_pwd.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_login_out.xml b/app/src/main/res/drawable/ic_login_out.xml index 208a666..e07996c 100644 --- a/app/src/main/res/drawable/ic_login_out.xml +++ b/app/src/main/res/drawable/ic_login_out.xml @@ -4,9 +4,9 @@ android:viewportWidth="1024" android:viewportHeight="1024"> diff --git a/app/src/main/res/drawable/ic_menu.xml b/app/src/main/res/drawable/ic_menu.xml new file mode 100644 index 0000000..eabc132 --- /dev/null +++ b/app/src/main/res/drawable/ic_menu.xml @@ -0,0 +1,24 @@ + + + + + + + + diff --git a/app/src/main/res/drawable/ic_share.xml b/app/src/main/res/drawable/ic_share.xml new file mode 100644 index 0000000..e309ad4 --- /dev/null +++ b/app/src/main/res/drawable/ic_share.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_update.xml b/app/src/main/res/drawable/ic_update.xml new file mode 100644 index 0000000..4aa8aa9 --- /dev/null +++ b/app/src/main/res/drawable/ic_update.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 4b7cc22..19a7438 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -1,10 +1,12 @@ + + android:src="@drawable/ic_menu" /> - + android:layout_height="match_parent" + android:fitsSystemWindows="true" + tools:openDrawer="start"> - + - - - - - - + android:scrollbars="vertical"> + android:orientation="vertical" + android:padding="@dimen/dp_10"> - + + + android:layout_marginTop="@dimen/dp_10" /> + + + android:layout_height="wrap_content" + android:orientation="vertical"> + + + android:layout_width="match_parent" + android:layout_height="60dp" + android:orientation="horizontal"> - + - - + - + + - + - - + - + + - + - + + + + - - - - - - - - - - - - - - - \ No newline at end of file + android:layout_height="wrap_content" + android:orientation="horizontal"> + + + + + + + + + + + + + + + + + diff --git a/app/build.gradle b/app/build.gradle index ca124d1..aec7047 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -99,4 +99,6 @@ implementation 'com.jzxiang.pickerview:TimePickerDialog:1.0.1' //Html解析,爬虫 implementation 'org.jsoup:jsoup:1.14.3' + //ZBar(综合Java和C++扫码),生成二维码 + implementation 'cn.bertsir.zbarLibary:zbarlibary:1.4.2' } \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/extensions/String.kt b/app/src/main/java/com/casic/qd/smartwell/extensions/String.kt index 19808ef..6c2525f 100644 --- a/app/src/main/java/com/casic/qd/smartwell/extensions/String.kt +++ b/app/src/main/java/com/casic/qd/smartwell/extensions/String.kt @@ -76,3 +76,16 @@ } return 0 } + +fun String.isLetterAndDigit(): Boolean { + var isDigit = false + var isLetter = false + for (i in this.indices) { + if (Character.isDigit(this[i])) { + isDigit = true + } else if (Character.isLetter(this[i])) { + isLetter = true + } + } + return isDigit && isLetter +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitService.kt b/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitService.kt index 831f862..f133ef4 100644 --- a/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitService.kt +++ b/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitService.kt @@ -43,6 +43,21 @@ suspend fun obtainUserDetail(@Header("token") token: String): String /** + * 修改密码 + * + * @param oldPwd 旧密码 + * @param newPwd 新密码 + */ + @FormUrlEncoded + @POST("/mgr/changePwd") + suspend fun changePassword( + @Header("token") token: String, + @Field("oldPwd") oldPwd: String, + @Field("newPwd") newPwd: String + ): String + + + /** * 用水统计 */ @GET("/waterStatistic/overview") diff --git a/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitServiceManager.kt index e446f48..9ee4cc1 100644 --- a/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitServiceManager.kt @@ -38,6 +38,13 @@ } /** + * 修改密码 + */ + suspend fun changePassword(oldPwd: String, newPwd: String): String { + return api.changePassword(AuthenticationHelper.token!!, oldPwd, newPwd) + } + + /** * 用水统计 */ suspend fun waterStatistics(): String { diff --git a/app/src/main/java/com/casic/qd/smartwell/view/MainActivity.kt b/app/src/main/java/com/casic/qd/smartwell/view/MainActivity.kt index 8f41c87..d8af9d8 100644 --- a/app/src/main/java/com/casic/qd/smartwell/view/MainActivity.kt +++ b/app/src/main/java/com/casic/qd/smartwell/view/MainActivity.kt @@ -1,11 +1,12 @@ package com.casic.qd.smartwell.view import android.content.Context -import android.os.Handler -import android.os.Looper -import android.os.Message import android.util.Log import android.view.KeyEvent +import android.view.MenuItem +import android.view.View +import androidx.core.view.GravityCompat +import androidx.drawerlayout.widget.DrawerLayout import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.GridLayoutManager @@ -16,10 +17,14 @@ import com.casic.qd.smartwell.extensions.* import com.casic.qd.smartwell.model.BannerImageModel import com.casic.qd.smartwell.model.LineChartEntryModel +import com.casic.qd.smartwell.model.UserDetailModel import com.casic.qd.smartwell.utils.* +import com.casic.qd.smartwell.vm.ChangePasswordViewModel import com.casic.qd.smartwell.vm.LoginViewModel import com.casic.qd.smartwell.vm.WaterStatisticsViewModel +import com.casic.qd.smartwell.widgets.ChangePasswordDialog import com.github.mikephil.charting.data.Entry +import com.google.android.material.navigation.NavigationView import com.google.gson.Gson import com.google.gson.reflect.TypeToken import com.pengxh.app.multilib.widget.dialog.AlertControlDialog @@ -29,22 +34,29 @@ import com.youth.banner.holder.BannerImageHolder import com.youth.banner.indicator.CircleIndicator import com.youth.banner.transformer.ScaleInTransformer +import kotlinx.android.synthetic.main.activity_data_search.* import kotlinx.android.synthetic.main.activity_main.* -import java.lang.ref.WeakReference +import kotlinx.android.synthetic.main.activity_main.rightOptionView +import kotlinx.android.synthetic.main.activity_main.titleView +import kotlinx.android.synthetic.main.activity_main.view.* +import kotlinx.android.synthetic.main.drawer_header_layout.* +import kotlinx.android.synthetic.main.drawer_header_layout.view.* +import java.nio.charset.StandardCharsets import java.util.* import kotlin.collections.ArrayList -class MainActivity : BaseActivity() { +class MainActivity : BaseActivity(), DrawerLayout.DrawerListener, + NavigationView.OnNavigationItemSelectedListener { private val kTag = "MainActivity" private val context: Context = this@MainActivity private var clickTime: Long = 0 private lateinit var loginViewModel: LoginViewModel private lateinit var waterViewModel: WaterStatisticsViewModel + private lateinit var changePwdViewModel: ChangePasswordViewModel private val xAxisDate: MutableList = ArrayList() private val entryModels: MutableList = ArrayList() private var imageModels: MutableList = ArrayList() - private lateinit var weakReferenceHandler: WeakReferenceHandler override fun initLayoutView(): Int = R.layout.activity_main @@ -53,10 +65,10 @@ } override fun initData() { - val bannerJsonModel = SaveKeyValues.getValue(Constant.BANNER_MODEL, "") as String - if (bannerJsonModel.isNotBlank()) { + val bannerJson = SaveKeyValues.getValue(Constant.BANNER_MODEL, "") as String + if (bannerJson.isNotBlank()) { imageModels = Gson().fromJson( - bannerJsonModel, object : TypeToken>() {}.type + bannerJson, object : TypeToken>() {}.type ) } else { Constant.NEWS_PAGE.forEach { @@ -127,26 +139,19 @@ //初始化vm loginViewModel = ViewModelProvider(this).get(LoginViewModel::class.java) waterViewModel = ViewModelProvider(this).get(WaterStatisticsViewModel::class.java) - weakReferenceHandler = WeakReferenceHandler(this) + changePwdViewModel = ViewModelProvider(this).get(ChangePasswordViewModel::class.java) } override fun initEvent() { leftOptionView.setOnClickListener { - AlertControlDialog.Builder() - .setContext(this) - .setTitle("退出登录") - .setMessage("确定要退出吗?") - .setNegativeButton("取消") - .setPositiveButton("确定") - .setOnDialogButtonClickListener(object : - AlertControlDialog.OnDialogButtonClickListener { - override fun onConfirmClick() { - loginViewModel.out() - } - - override fun onCancelClick() {} - }).build().show() + if (leftDrawerLayout.isDrawerOpen(GravityCompat.START)) { + leftDrawerLayout.closeDrawer(GravityCompat.START) + } else { + leftDrawerLayout.openDrawer(GravityCompat.START) + } } + leftDrawerLayout.addDrawerListener(this) + navigationView.setNavigationItemSelectedListener(this) loginViewModel.loadState.observe(this, { if (it == LoadState.Success) { AuthenticationHelper.removeToken() @@ -205,19 +210,108 @@ expandChartView.setOnClickListener { navigatePageTo(WaterExpandedActivity::class.java) } + + changePwdViewModel.loadState.observe(this, { + when (it) { + is LoadState.Loading -> { + DialogHelper.showLoadingDialog(this, "修改中,请稍后") + } + is LoadState.Success -> { + DialogHelper.dismissLoadingDialog() + AuthenticationHelper.removeToken() + this.navigatePageTo(LoginActivity::class.java) + PageNavigationManager.finishAllActivity() + } + else -> { + DialogHelper.dismissLoadingDialog() + } + } + }) } - private class WeakReferenceHandler(activity: MainActivity) : Handler(Looper.getMainLooper()) { + override fun onDrawerSlide(drawerView: View, slideOffset: Float) { - private val reference: WeakReference = WeakReference(activity) + } - override fun handleMessage(msg: Message) { - super.handleMessage(msg) - val activity = reference.get()!! - + override fun onDrawerOpened(drawerView: View) { + val userDetailJson = SaveKeyValues.getValue(Constant.USER_DETAIL_MODEL, "") as String + if (userDetailJson.isNotBlank()) { + val userDetail = Gson().fromJson( + userDetailJson, object : TypeToken() {}.type + ) + userNameView.text = userDetail.name + userDeptView.text = userDetail.deptName + userRoleView.text = userDetail.roleNames.toString() } } + override fun onDrawerClosed(drawerView: View) { + + } + + override fun onDrawerStateChanged(newState: Int) { + + } + + override fun onNavigationItemSelected(item: MenuItem): Boolean { + when (item.itemId) { + R.id.changePwdView -> { + ChangePasswordDialog.Builder() + .setContext(this) + .setOnDialogButtonClickListener(object : + ChangePasswordDialog.OnDialogButtonClickListener { + override fun onConfirmClick(oldPwd: String, newPwd: String) { + val publicKey = + RSAUtils.keyStrToPublicKey(AuthenticationHelper.publicKey)!! + val oldPassKey = RSAUtils.encryptDataByPublicKey( + oldPwd.toByteArray(StandardCharsets.UTF_8), + publicKey + ) + val newPassKey = RSAUtils.encryptDataByPublicKey( + newPwd.toByteArray(StandardCharsets.UTF_8), + publicKey + ) + changePwdViewModel.changePassword(oldPassKey, newPassKey) + } + }).build().show() + } + R.id.shareApkView -> { + //apk服务器下载地址 +// val downloadPath = "1111" +// val createCodeBitmap = QRUtils.getInstance().createQRCode( +// downloadPath, +// SizeUtil.dp2px(this, 300f), +// SizeUtil.dp2px(this, 300f) +// ) +// ShareDialog.Builder() +// .setContext(this) +// .setDialogTitle("扫以下二维码就可以下载本应用") +// .setDialogBitmap(createCodeBitmap).build().show() + "尽情期待~".show() + } + R.id.versionNameView -> { + "已是最新版本,无需更新".show() + } + R.id.loginOutView -> { + AlertControlDialog.Builder() + .setContext(this) + .setTitle("退出登录") + .setMessage("确定要退出吗?") + .setNegativeButton("取消") + .setPositiveButton("确定") + .setOnDialogButtonClickListener(object : + AlertControlDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + loginViewModel.out() + } + + override fun onCancelClick() {} + }).build().show() + } + } + return false + } + override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { return if (keyCode == KeyEvent.KEYCODE_BACK) { if (System.currentTimeMillis() - clickTime > 2000) { diff --git a/app/src/main/java/com/casic/qd/smartwell/vm/ChangePasswordViewModel.kt b/app/src/main/java/com/casic/qd/smartwell/vm/ChangePasswordViewModel.kt new file mode 100644 index 0000000..751a5f4 --- /dev/null +++ b/app/src/main/java/com/casic/qd/smartwell/vm/ChangePasswordViewModel.kt @@ -0,0 +1,28 @@ +package com.casic.qd.smartwell.vm + +import com.casic.qd.smartwell.base.BaseViewModel +import com.casic.qd.smartwell.extensions.launch +import com.casic.qd.smartwell.extensions.separateResponseCode +import com.casic.qd.smartwell.extensions.show +import com.casic.qd.smartwell.extensions.toErrorMessage +import com.casic.qd.smartwell.utils.LoadState +import com.casic.qd.smartwell.utils.retrofit.RetrofitServiceManager + +class ChangePasswordViewModel : BaseViewModel() { + + fun changePassword(oldPwd: String, newPwd: String) = launch({ + loadState.value = LoadState.Loading + val response = RetrofitServiceManager.changePassword(oldPwd, newPwd) + val responseCode = response.separateResponseCode() + if (responseCode == 200) { + loadState.value = LoadState.Success + "修改成功,请重新登录".show() + } else { + loadState.value = LoadState.Fail + response.toErrorMessage().show() + } + }, { + loadState.value = LoadState.Fail + it.printStackTrace() + }) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/widgets/ChangePasswordDialog.kt b/app/src/main/java/com/casic/qd/smartwell/widgets/ChangePasswordDialog.kt new file mode 100644 index 0000000..98ff307 --- /dev/null +++ b/app/src/main/java/com/casic/qd/smartwell/widgets/ChangePasswordDialog.kt @@ -0,0 +1,81 @@ +package com.casic.qd.smartwell.widgets + +import android.app.Dialog +import android.content.Context +import android.os.Bundle +import android.view.Gravity +import com.casic.qd.smartwell.R +import com.casic.qd.smartwell.extensions.initDialogLayoutParams +import com.casic.qd.smartwell.extensions.isLetterAndDigit +import com.casic.qd.smartwell.extensions.show +import kotlinx.android.synthetic.main.dialog_change_pwd.* + + +/** + * @author: Pengxh + * @email: 290677893@qq.com + * @date: 2020/11/6 22:12 + */ +class ChangePasswordDialog private constructor(builder: Builder) : + Dialog(builder.context, R.style.UserDefinedDialogStyle) { + + private val listener: OnDialogButtonClickListener = builder.listener + + class Builder { + lateinit var context: Context + lateinit var listener: OnDialogButtonClickListener + + fun setContext(context: Context): Builder { + this.context = context + return this + } + + fun setOnDialogButtonClickListener(listener: OnDialogButtonClickListener): Builder { + this.listener = listener + return this + } + + fun build(): ChangePasswordDialog { + return ChangePasswordDialog(this) + } + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + this.initDialogLayoutParams(Gravity.CENTER, R.style.UserDefinedAnimation, 0.85f) + setContentView(R.layout.dialog_change_pwd) + setCancelable(true) + setCanceledOnTouchOutside(true) + + confirmButton.setChangeAlphaWhenPress(true) + confirmButton.setOnClickListener { + val oldPwd = oldPwdView.text.toString() + val newPwd = newPwdView.text.toString() + val confirmPwd = confirmPwdView.text.toString() + if (oldPwd.isBlank()) { + "请输入原密码".show() + return@setOnClickListener + } + if (newPwd.isBlank()) { + "请输入新密码".show() + return@setOnClickListener + } + if (confirmPwd.isBlank()) { + "请在此确认密码".show() + return@setOnClickListener + } + if (!newPwd.isLetterAndDigit()) { + "新密码需包含数字和字母".show() + } + if (newPwd != confirmPwd) { + "新密码和确认密码不一致,请检查".show() + return@setOnClickListener + } + listener.onConfirmClick(oldPwd, newPwd) + } + } + + interface OnDialogButtonClickListener { + fun onConfirmClick(oldPwd: String, newPwd: String) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/widgets/MarqueeTextView.kt b/app/src/main/java/com/casic/qd/smartwell/widgets/MarqueeTextView.kt new file mode 100644 index 0000000..520f6ae --- /dev/null +++ b/app/src/main/java/com/casic/qd/smartwell/widgets/MarqueeTextView.kt @@ -0,0 +1,13 @@ +package com.casic.qd.smartwell.widgets + +import android.content.Context +import android.util.AttributeSet +import androidx.appcompat.widget.AppCompatTextView + +class MarqueeTextView(context: Context, attrs: AttributeSet? = null) : + AppCompatTextView(context, attrs) { + + override fun isFocused(): Boolean { + return true //自动获取焦点 + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/widgets/ShareDialog.kt b/app/src/main/java/com/casic/qd/smartwell/widgets/ShareDialog.kt new file mode 100644 index 0000000..377febc --- /dev/null +++ b/app/src/main/java/com/casic/qd/smartwell/widgets/ShareDialog.kt @@ -0,0 +1,54 @@ +package com.casic.qd.smartwell.widgets + +import android.content.Context +import android.graphics.Bitmap +import android.os.Bundle +import androidx.appcompat.app.AlertDialog +import com.casic.qd.smartwell.R +import kotlinx.android.synthetic.main.dialog_share.* + +/** + * @author: Pengxh + * @email: 290677893@qq.com + */ +class ShareDialog private constructor(builder: Builder) : + AlertDialog(builder.context, R.style.UserDefinedDialogStyle) { + + private var title: String = builder.title + private var bitmap: Bitmap = builder.bitmap + + class Builder { + lateinit var context: Context + lateinit var title: String + lateinit var bitmap: Bitmap + + fun setContext(context: Context): Builder { + this.context = context + return this + } + + fun setDialogTitle(title: String): Builder { + this.title = title + return this + } + + fun setDialogBitmap(bitmap: Bitmap): Builder { + this.bitmap = bitmap + return this + } + + fun build(): ShareDialog { + return ShareDialog(this) + } + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.dialog_share) + setCanceledOnTouchOutside(true) + setCancelable(true) + + shareTitleView.text = title + codeView.setImageBitmap(bitmap) + } +} \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_change_pwd.xml b/app/src/main/res/drawable/ic_change_pwd.xml new file mode 100644 index 0000000..708f7bf --- /dev/null +++ b/app/src/main/res/drawable/ic_change_pwd.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_login_out.xml b/app/src/main/res/drawable/ic_login_out.xml index 208a666..e07996c 100644 --- a/app/src/main/res/drawable/ic_login_out.xml +++ b/app/src/main/res/drawable/ic_login_out.xml @@ -4,9 +4,9 @@ android:viewportWidth="1024" android:viewportHeight="1024"> diff --git a/app/src/main/res/drawable/ic_menu.xml b/app/src/main/res/drawable/ic_menu.xml new file mode 100644 index 0000000..eabc132 --- /dev/null +++ b/app/src/main/res/drawable/ic_menu.xml @@ -0,0 +1,24 @@ + + + + + + + + diff --git a/app/src/main/res/drawable/ic_share.xml b/app/src/main/res/drawable/ic_share.xml new file mode 100644 index 0000000..e309ad4 --- /dev/null +++ b/app/src/main/res/drawable/ic_share.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_update.xml b/app/src/main/res/drawable/ic_update.xml new file mode 100644 index 0000000..4aa8aa9 --- /dev/null +++ b/app/src/main/res/drawable/ic_update.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 4b7cc22..19a7438 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -1,10 +1,12 @@ + + android:src="@drawable/ic_menu" /> - + android:layout_height="match_parent" + android:fitsSystemWindows="true" + tools:openDrawer="start"> - + - - - - - - + android:scrollbars="vertical"> + android:orientation="vertical" + android:padding="@dimen/dp_10"> - + + + android:layout_marginTop="@dimen/dp_10" /> + + + android:layout_height="wrap_content" + android:orientation="vertical"> + + + android:layout_width="match_parent" + android:layout_height="60dp" + android:orientation="horizontal"> - + - - + - + + - + - - + - + + - + - + + + + - - - - - - - - - - - - - - - \ No newline at end of file + android:layout_height="wrap_content" + android:orientation="horizontal"> + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/dialog_change_pwd.xml b/app/src/main/res/layout/dialog_change_pwd.xml new file mode 100644 index 0000000..b4197b8 --- /dev/null +++ b/app/src/main/res/layout/dialog_change_pwd.xml @@ -0,0 +1,146 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index ca124d1..aec7047 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -99,4 +99,6 @@ implementation 'com.jzxiang.pickerview:TimePickerDialog:1.0.1' //Html解析,爬虫 implementation 'org.jsoup:jsoup:1.14.3' + //ZBar(综合Java和C++扫码),生成二维码 + implementation 'cn.bertsir.zbarLibary:zbarlibary:1.4.2' } \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/extensions/String.kt b/app/src/main/java/com/casic/qd/smartwell/extensions/String.kt index 19808ef..6c2525f 100644 --- a/app/src/main/java/com/casic/qd/smartwell/extensions/String.kt +++ b/app/src/main/java/com/casic/qd/smartwell/extensions/String.kt @@ -76,3 +76,16 @@ } return 0 } + +fun String.isLetterAndDigit(): Boolean { + var isDigit = false + var isLetter = false + for (i in this.indices) { + if (Character.isDigit(this[i])) { + isDigit = true + } else if (Character.isLetter(this[i])) { + isLetter = true + } + } + return isDigit && isLetter +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitService.kt b/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitService.kt index 831f862..f133ef4 100644 --- a/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitService.kt +++ b/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitService.kt @@ -43,6 +43,21 @@ suspend fun obtainUserDetail(@Header("token") token: String): String /** + * 修改密码 + * + * @param oldPwd 旧密码 + * @param newPwd 新密码 + */ + @FormUrlEncoded + @POST("/mgr/changePwd") + suspend fun changePassword( + @Header("token") token: String, + @Field("oldPwd") oldPwd: String, + @Field("newPwd") newPwd: String + ): String + + + /** * 用水统计 */ @GET("/waterStatistic/overview") diff --git a/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitServiceManager.kt index e446f48..9ee4cc1 100644 --- a/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitServiceManager.kt @@ -38,6 +38,13 @@ } /** + * 修改密码 + */ + suspend fun changePassword(oldPwd: String, newPwd: String): String { + return api.changePassword(AuthenticationHelper.token!!, oldPwd, newPwd) + } + + /** * 用水统计 */ suspend fun waterStatistics(): String { diff --git a/app/src/main/java/com/casic/qd/smartwell/view/MainActivity.kt b/app/src/main/java/com/casic/qd/smartwell/view/MainActivity.kt index 8f41c87..d8af9d8 100644 --- a/app/src/main/java/com/casic/qd/smartwell/view/MainActivity.kt +++ b/app/src/main/java/com/casic/qd/smartwell/view/MainActivity.kt @@ -1,11 +1,12 @@ package com.casic.qd.smartwell.view import android.content.Context -import android.os.Handler -import android.os.Looper -import android.os.Message import android.util.Log import android.view.KeyEvent +import android.view.MenuItem +import android.view.View +import androidx.core.view.GravityCompat +import androidx.drawerlayout.widget.DrawerLayout import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.GridLayoutManager @@ -16,10 +17,14 @@ import com.casic.qd.smartwell.extensions.* import com.casic.qd.smartwell.model.BannerImageModel import com.casic.qd.smartwell.model.LineChartEntryModel +import com.casic.qd.smartwell.model.UserDetailModel import com.casic.qd.smartwell.utils.* +import com.casic.qd.smartwell.vm.ChangePasswordViewModel import com.casic.qd.smartwell.vm.LoginViewModel import com.casic.qd.smartwell.vm.WaterStatisticsViewModel +import com.casic.qd.smartwell.widgets.ChangePasswordDialog import com.github.mikephil.charting.data.Entry +import com.google.android.material.navigation.NavigationView import com.google.gson.Gson import com.google.gson.reflect.TypeToken import com.pengxh.app.multilib.widget.dialog.AlertControlDialog @@ -29,22 +34,29 @@ import com.youth.banner.holder.BannerImageHolder import com.youth.banner.indicator.CircleIndicator import com.youth.banner.transformer.ScaleInTransformer +import kotlinx.android.synthetic.main.activity_data_search.* import kotlinx.android.synthetic.main.activity_main.* -import java.lang.ref.WeakReference +import kotlinx.android.synthetic.main.activity_main.rightOptionView +import kotlinx.android.synthetic.main.activity_main.titleView +import kotlinx.android.synthetic.main.activity_main.view.* +import kotlinx.android.synthetic.main.drawer_header_layout.* +import kotlinx.android.synthetic.main.drawer_header_layout.view.* +import java.nio.charset.StandardCharsets import java.util.* import kotlin.collections.ArrayList -class MainActivity : BaseActivity() { +class MainActivity : BaseActivity(), DrawerLayout.DrawerListener, + NavigationView.OnNavigationItemSelectedListener { private val kTag = "MainActivity" private val context: Context = this@MainActivity private var clickTime: Long = 0 private lateinit var loginViewModel: LoginViewModel private lateinit var waterViewModel: WaterStatisticsViewModel + private lateinit var changePwdViewModel: ChangePasswordViewModel private val xAxisDate: MutableList = ArrayList() private val entryModels: MutableList = ArrayList() private var imageModels: MutableList = ArrayList() - private lateinit var weakReferenceHandler: WeakReferenceHandler override fun initLayoutView(): Int = R.layout.activity_main @@ -53,10 +65,10 @@ } override fun initData() { - val bannerJsonModel = SaveKeyValues.getValue(Constant.BANNER_MODEL, "") as String - if (bannerJsonModel.isNotBlank()) { + val bannerJson = SaveKeyValues.getValue(Constant.BANNER_MODEL, "") as String + if (bannerJson.isNotBlank()) { imageModels = Gson().fromJson( - bannerJsonModel, object : TypeToken>() {}.type + bannerJson, object : TypeToken>() {}.type ) } else { Constant.NEWS_PAGE.forEach { @@ -127,26 +139,19 @@ //初始化vm loginViewModel = ViewModelProvider(this).get(LoginViewModel::class.java) waterViewModel = ViewModelProvider(this).get(WaterStatisticsViewModel::class.java) - weakReferenceHandler = WeakReferenceHandler(this) + changePwdViewModel = ViewModelProvider(this).get(ChangePasswordViewModel::class.java) } override fun initEvent() { leftOptionView.setOnClickListener { - AlertControlDialog.Builder() - .setContext(this) - .setTitle("退出登录") - .setMessage("确定要退出吗?") - .setNegativeButton("取消") - .setPositiveButton("确定") - .setOnDialogButtonClickListener(object : - AlertControlDialog.OnDialogButtonClickListener { - override fun onConfirmClick() { - loginViewModel.out() - } - - override fun onCancelClick() {} - }).build().show() + if (leftDrawerLayout.isDrawerOpen(GravityCompat.START)) { + leftDrawerLayout.closeDrawer(GravityCompat.START) + } else { + leftDrawerLayout.openDrawer(GravityCompat.START) + } } + leftDrawerLayout.addDrawerListener(this) + navigationView.setNavigationItemSelectedListener(this) loginViewModel.loadState.observe(this, { if (it == LoadState.Success) { AuthenticationHelper.removeToken() @@ -205,19 +210,108 @@ expandChartView.setOnClickListener { navigatePageTo(WaterExpandedActivity::class.java) } + + changePwdViewModel.loadState.observe(this, { + when (it) { + is LoadState.Loading -> { + DialogHelper.showLoadingDialog(this, "修改中,请稍后") + } + is LoadState.Success -> { + DialogHelper.dismissLoadingDialog() + AuthenticationHelper.removeToken() + this.navigatePageTo(LoginActivity::class.java) + PageNavigationManager.finishAllActivity() + } + else -> { + DialogHelper.dismissLoadingDialog() + } + } + }) } - private class WeakReferenceHandler(activity: MainActivity) : Handler(Looper.getMainLooper()) { + override fun onDrawerSlide(drawerView: View, slideOffset: Float) { - private val reference: WeakReference = WeakReference(activity) + } - override fun handleMessage(msg: Message) { - super.handleMessage(msg) - val activity = reference.get()!! - + override fun onDrawerOpened(drawerView: View) { + val userDetailJson = SaveKeyValues.getValue(Constant.USER_DETAIL_MODEL, "") as String + if (userDetailJson.isNotBlank()) { + val userDetail = Gson().fromJson( + userDetailJson, object : TypeToken() {}.type + ) + userNameView.text = userDetail.name + userDeptView.text = userDetail.deptName + userRoleView.text = userDetail.roleNames.toString() } } + override fun onDrawerClosed(drawerView: View) { + + } + + override fun onDrawerStateChanged(newState: Int) { + + } + + override fun onNavigationItemSelected(item: MenuItem): Boolean { + when (item.itemId) { + R.id.changePwdView -> { + ChangePasswordDialog.Builder() + .setContext(this) + .setOnDialogButtonClickListener(object : + ChangePasswordDialog.OnDialogButtonClickListener { + override fun onConfirmClick(oldPwd: String, newPwd: String) { + val publicKey = + RSAUtils.keyStrToPublicKey(AuthenticationHelper.publicKey)!! + val oldPassKey = RSAUtils.encryptDataByPublicKey( + oldPwd.toByteArray(StandardCharsets.UTF_8), + publicKey + ) + val newPassKey = RSAUtils.encryptDataByPublicKey( + newPwd.toByteArray(StandardCharsets.UTF_8), + publicKey + ) + changePwdViewModel.changePassword(oldPassKey, newPassKey) + } + }).build().show() + } + R.id.shareApkView -> { + //apk服务器下载地址 +// val downloadPath = "1111" +// val createCodeBitmap = QRUtils.getInstance().createQRCode( +// downloadPath, +// SizeUtil.dp2px(this, 300f), +// SizeUtil.dp2px(this, 300f) +// ) +// ShareDialog.Builder() +// .setContext(this) +// .setDialogTitle("扫以下二维码就可以下载本应用") +// .setDialogBitmap(createCodeBitmap).build().show() + "尽情期待~".show() + } + R.id.versionNameView -> { + "已是最新版本,无需更新".show() + } + R.id.loginOutView -> { + AlertControlDialog.Builder() + .setContext(this) + .setTitle("退出登录") + .setMessage("确定要退出吗?") + .setNegativeButton("取消") + .setPositiveButton("确定") + .setOnDialogButtonClickListener(object : + AlertControlDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + loginViewModel.out() + } + + override fun onCancelClick() {} + }).build().show() + } + } + return false + } + override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { return if (keyCode == KeyEvent.KEYCODE_BACK) { if (System.currentTimeMillis() - clickTime > 2000) { diff --git a/app/src/main/java/com/casic/qd/smartwell/vm/ChangePasswordViewModel.kt b/app/src/main/java/com/casic/qd/smartwell/vm/ChangePasswordViewModel.kt new file mode 100644 index 0000000..751a5f4 --- /dev/null +++ b/app/src/main/java/com/casic/qd/smartwell/vm/ChangePasswordViewModel.kt @@ -0,0 +1,28 @@ +package com.casic.qd.smartwell.vm + +import com.casic.qd.smartwell.base.BaseViewModel +import com.casic.qd.smartwell.extensions.launch +import com.casic.qd.smartwell.extensions.separateResponseCode +import com.casic.qd.smartwell.extensions.show +import com.casic.qd.smartwell.extensions.toErrorMessage +import com.casic.qd.smartwell.utils.LoadState +import com.casic.qd.smartwell.utils.retrofit.RetrofitServiceManager + +class ChangePasswordViewModel : BaseViewModel() { + + fun changePassword(oldPwd: String, newPwd: String) = launch({ + loadState.value = LoadState.Loading + val response = RetrofitServiceManager.changePassword(oldPwd, newPwd) + val responseCode = response.separateResponseCode() + if (responseCode == 200) { + loadState.value = LoadState.Success + "修改成功,请重新登录".show() + } else { + loadState.value = LoadState.Fail + response.toErrorMessage().show() + } + }, { + loadState.value = LoadState.Fail + it.printStackTrace() + }) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/widgets/ChangePasswordDialog.kt b/app/src/main/java/com/casic/qd/smartwell/widgets/ChangePasswordDialog.kt new file mode 100644 index 0000000..98ff307 --- /dev/null +++ b/app/src/main/java/com/casic/qd/smartwell/widgets/ChangePasswordDialog.kt @@ -0,0 +1,81 @@ +package com.casic.qd.smartwell.widgets + +import android.app.Dialog +import android.content.Context +import android.os.Bundle +import android.view.Gravity +import com.casic.qd.smartwell.R +import com.casic.qd.smartwell.extensions.initDialogLayoutParams +import com.casic.qd.smartwell.extensions.isLetterAndDigit +import com.casic.qd.smartwell.extensions.show +import kotlinx.android.synthetic.main.dialog_change_pwd.* + + +/** + * @author: Pengxh + * @email: 290677893@qq.com + * @date: 2020/11/6 22:12 + */ +class ChangePasswordDialog private constructor(builder: Builder) : + Dialog(builder.context, R.style.UserDefinedDialogStyle) { + + private val listener: OnDialogButtonClickListener = builder.listener + + class Builder { + lateinit var context: Context + lateinit var listener: OnDialogButtonClickListener + + fun setContext(context: Context): Builder { + this.context = context + return this + } + + fun setOnDialogButtonClickListener(listener: OnDialogButtonClickListener): Builder { + this.listener = listener + return this + } + + fun build(): ChangePasswordDialog { + return ChangePasswordDialog(this) + } + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + this.initDialogLayoutParams(Gravity.CENTER, R.style.UserDefinedAnimation, 0.85f) + setContentView(R.layout.dialog_change_pwd) + setCancelable(true) + setCanceledOnTouchOutside(true) + + confirmButton.setChangeAlphaWhenPress(true) + confirmButton.setOnClickListener { + val oldPwd = oldPwdView.text.toString() + val newPwd = newPwdView.text.toString() + val confirmPwd = confirmPwdView.text.toString() + if (oldPwd.isBlank()) { + "请输入原密码".show() + return@setOnClickListener + } + if (newPwd.isBlank()) { + "请输入新密码".show() + return@setOnClickListener + } + if (confirmPwd.isBlank()) { + "请在此确认密码".show() + return@setOnClickListener + } + if (!newPwd.isLetterAndDigit()) { + "新密码需包含数字和字母".show() + } + if (newPwd != confirmPwd) { + "新密码和确认密码不一致,请检查".show() + return@setOnClickListener + } + listener.onConfirmClick(oldPwd, newPwd) + } + } + + interface OnDialogButtonClickListener { + fun onConfirmClick(oldPwd: String, newPwd: String) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/widgets/MarqueeTextView.kt b/app/src/main/java/com/casic/qd/smartwell/widgets/MarqueeTextView.kt new file mode 100644 index 0000000..520f6ae --- /dev/null +++ b/app/src/main/java/com/casic/qd/smartwell/widgets/MarqueeTextView.kt @@ -0,0 +1,13 @@ +package com.casic.qd.smartwell.widgets + +import android.content.Context +import android.util.AttributeSet +import androidx.appcompat.widget.AppCompatTextView + +class MarqueeTextView(context: Context, attrs: AttributeSet? = null) : + AppCompatTextView(context, attrs) { + + override fun isFocused(): Boolean { + return true //自动获取焦点 + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/widgets/ShareDialog.kt b/app/src/main/java/com/casic/qd/smartwell/widgets/ShareDialog.kt new file mode 100644 index 0000000..377febc --- /dev/null +++ b/app/src/main/java/com/casic/qd/smartwell/widgets/ShareDialog.kt @@ -0,0 +1,54 @@ +package com.casic.qd.smartwell.widgets + +import android.content.Context +import android.graphics.Bitmap +import android.os.Bundle +import androidx.appcompat.app.AlertDialog +import com.casic.qd.smartwell.R +import kotlinx.android.synthetic.main.dialog_share.* + +/** + * @author: Pengxh + * @email: 290677893@qq.com + */ +class ShareDialog private constructor(builder: Builder) : + AlertDialog(builder.context, R.style.UserDefinedDialogStyle) { + + private var title: String = builder.title + private var bitmap: Bitmap = builder.bitmap + + class Builder { + lateinit var context: Context + lateinit var title: String + lateinit var bitmap: Bitmap + + fun setContext(context: Context): Builder { + this.context = context + return this + } + + fun setDialogTitle(title: String): Builder { + this.title = title + return this + } + + fun setDialogBitmap(bitmap: Bitmap): Builder { + this.bitmap = bitmap + return this + } + + fun build(): ShareDialog { + return ShareDialog(this) + } + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.dialog_share) + setCanceledOnTouchOutside(true) + setCancelable(true) + + shareTitleView.text = title + codeView.setImageBitmap(bitmap) + } +} \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_change_pwd.xml b/app/src/main/res/drawable/ic_change_pwd.xml new file mode 100644 index 0000000..708f7bf --- /dev/null +++ b/app/src/main/res/drawable/ic_change_pwd.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_login_out.xml b/app/src/main/res/drawable/ic_login_out.xml index 208a666..e07996c 100644 --- a/app/src/main/res/drawable/ic_login_out.xml +++ b/app/src/main/res/drawable/ic_login_out.xml @@ -4,9 +4,9 @@ android:viewportWidth="1024" android:viewportHeight="1024"> diff --git a/app/src/main/res/drawable/ic_menu.xml b/app/src/main/res/drawable/ic_menu.xml new file mode 100644 index 0000000..eabc132 --- /dev/null +++ b/app/src/main/res/drawable/ic_menu.xml @@ -0,0 +1,24 @@ + + + + + + + + diff --git a/app/src/main/res/drawable/ic_share.xml b/app/src/main/res/drawable/ic_share.xml new file mode 100644 index 0000000..e309ad4 --- /dev/null +++ b/app/src/main/res/drawable/ic_share.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_update.xml b/app/src/main/res/drawable/ic_update.xml new file mode 100644 index 0000000..4aa8aa9 --- /dev/null +++ b/app/src/main/res/drawable/ic_update.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 4b7cc22..19a7438 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -1,10 +1,12 @@ + + android:src="@drawable/ic_menu" /> - + android:layout_height="match_parent" + android:fitsSystemWindows="true" + tools:openDrawer="start"> - + - - - - - - + android:scrollbars="vertical"> + android:orientation="vertical" + android:padding="@dimen/dp_10"> - + + + android:layout_marginTop="@dimen/dp_10" /> + + + android:layout_height="wrap_content" + android:orientation="vertical"> + + + android:layout_width="match_parent" + android:layout_height="60dp" + android:orientation="horizontal"> - + - - + - + + - + - - + - + + - + - + + + + - - - - - - - - - - - - - - - \ No newline at end of file + android:layout_height="wrap_content" + android:orientation="horizontal"> + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/dialog_change_pwd.xml b/app/src/main/res/layout/dialog_change_pwd.xml new file mode 100644 index 0000000..b4197b8 --- /dev/null +++ b/app/src/main/res/layout/dialog_change_pwd.xml @@ -0,0 +1,146 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_share.xml b/app/src/main/res/layout/dialog_share.xml new file mode 100644 index 0000000..d6b6592 --- /dev/null +++ b/app/src/main/res/layout/dialog_share.xml @@ -0,0 +1,32 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index ca124d1..aec7047 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -99,4 +99,6 @@ implementation 'com.jzxiang.pickerview:TimePickerDialog:1.0.1' //Html解析,爬虫 implementation 'org.jsoup:jsoup:1.14.3' + //ZBar(综合Java和C++扫码),生成二维码 + implementation 'cn.bertsir.zbarLibary:zbarlibary:1.4.2' } \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/extensions/String.kt b/app/src/main/java/com/casic/qd/smartwell/extensions/String.kt index 19808ef..6c2525f 100644 --- a/app/src/main/java/com/casic/qd/smartwell/extensions/String.kt +++ b/app/src/main/java/com/casic/qd/smartwell/extensions/String.kt @@ -76,3 +76,16 @@ } return 0 } + +fun String.isLetterAndDigit(): Boolean { + var isDigit = false + var isLetter = false + for (i in this.indices) { + if (Character.isDigit(this[i])) { + isDigit = true + } else if (Character.isLetter(this[i])) { + isLetter = true + } + } + return isDigit && isLetter +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitService.kt b/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitService.kt index 831f862..f133ef4 100644 --- a/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitService.kt +++ b/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitService.kt @@ -43,6 +43,21 @@ suspend fun obtainUserDetail(@Header("token") token: String): String /** + * 修改密码 + * + * @param oldPwd 旧密码 + * @param newPwd 新密码 + */ + @FormUrlEncoded + @POST("/mgr/changePwd") + suspend fun changePassword( + @Header("token") token: String, + @Field("oldPwd") oldPwd: String, + @Field("newPwd") newPwd: String + ): String + + + /** * 用水统计 */ @GET("/waterStatistic/overview") diff --git a/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitServiceManager.kt index e446f48..9ee4cc1 100644 --- a/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitServiceManager.kt @@ -38,6 +38,13 @@ } /** + * 修改密码 + */ + suspend fun changePassword(oldPwd: String, newPwd: String): String { + return api.changePassword(AuthenticationHelper.token!!, oldPwd, newPwd) + } + + /** * 用水统计 */ suspend fun waterStatistics(): String { diff --git a/app/src/main/java/com/casic/qd/smartwell/view/MainActivity.kt b/app/src/main/java/com/casic/qd/smartwell/view/MainActivity.kt index 8f41c87..d8af9d8 100644 --- a/app/src/main/java/com/casic/qd/smartwell/view/MainActivity.kt +++ b/app/src/main/java/com/casic/qd/smartwell/view/MainActivity.kt @@ -1,11 +1,12 @@ package com.casic.qd.smartwell.view import android.content.Context -import android.os.Handler -import android.os.Looper -import android.os.Message import android.util.Log import android.view.KeyEvent +import android.view.MenuItem +import android.view.View +import androidx.core.view.GravityCompat +import androidx.drawerlayout.widget.DrawerLayout import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.GridLayoutManager @@ -16,10 +17,14 @@ import com.casic.qd.smartwell.extensions.* import com.casic.qd.smartwell.model.BannerImageModel import com.casic.qd.smartwell.model.LineChartEntryModel +import com.casic.qd.smartwell.model.UserDetailModel import com.casic.qd.smartwell.utils.* +import com.casic.qd.smartwell.vm.ChangePasswordViewModel import com.casic.qd.smartwell.vm.LoginViewModel import com.casic.qd.smartwell.vm.WaterStatisticsViewModel +import com.casic.qd.smartwell.widgets.ChangePasswordDialog import com.github.mikephil.charting.data.Entry +import com.google.android.material.navigation.NavigationView import com.google.gson.Gson import com.google.gson.reflect.TypeToken import com.pengxh.app.multilib.widget.dialog.AlertControlDialog @@ -29,22 +34,29 @@ import com.youth.banner.holder.BannerImageHolder import com.youth.banner.indicator.CircleIndicator import com.youth.banner.transformer.ScaleInTransformer +import kotlinx.android.synthetic.main.activity_data_search.* import kotlinx.android.synthetic.main.activity_main.* -import java.lang.ref.WeakReference +import kotlinx.android.synthetic.main.activity_main.rightOptionView +import kotlinx.android.synthetic.main.activity_main.titleView +import kotlinx.android.synthetic.main.activity_main.view.* +import kotlinx.android.synthetic.main.drawer_header_layout.* +import kotlinx.android.synthetic.main.drawer_header_layout.view.* +import java.nio.charset.StandardCharsets import java.util.* import kotlin.collections.ArrayList -class MainActivity : BaseActivity() { +class MainActivity : BaseActivity(), DrawerLayout.DrawerListener, + NavigationView.OnNavigationItemSelectedListener { private val kTag = "MainActivity" private val context: Context = this@MainActivity private var clickTime: Long = 0 private lateinit var loginViewModel: LoginViewModel private lateinit var waterViewModel: WaterStatisticsViewModel + private lateinit var changePwdViewModel: ChangePasswordViewModel private val xAxisDate: MutableList = ArrayList() private val entryModels: MutableList = ArrayList() private var imageModels: MutableList = ArrayList() - private lateinit var weakReferenceHandler: WeakReferenceHandler override fun initLayoutView(): Int = R.layout.activity_main @@ -53,10 +65,10 @@ } override fun initData() { - val bannerJsonModel = SaveKeyValues.getValue(Constant.BANNER_MODEL, "") as String - if (bannerJsonModel.isNotBlank()) { + val bannerJson = SaveKeyValues.getValue(Constant.BANNER_MODEL, "") as String + if (bannerJson.isNotBlank()) { imageModels = Gson().fromJson( - bannerJsonModel, object : TypeToken>() {}.type + bannerJson, object : TypeToken>() {}.type ) } else { Constant.NEWS_PAGE.forEach { @@ -127,26 +139,19 @@ //初始化vm loginViewModel = ViewModelProvider(this).get(LoginViewModel::class.java) waterViewModel = ViewModelProvider(this).get(WaterStatisticsViewModel::class.java) - weakReferenceHandler = WeakReferenceHandler(this) + changePwdViewModel = ViewModelProvider(this).get(ChangePasswordViewModel::class.java) } override fun initEvent() { leftOptionView.setOnClickListener { - AlertControlDialog.Builder() - .setContext(this) - .setTitle("退出登录") - .setMessage("确定要退出吗?") - .setNegativeButton("取消") - .setPositiveButton("确定") - .setOnDialogButtonClickListener(object : - AlertControlDialog.OnDialogButtonClickListener { - override fun onConfirmClick() { - loginViewModel.out() - } - - override fun onCancelClick() {} - }).build().show() + if (leftDrawerLayout.isDrawerOpen(GravityCompat.START)) { + leftDrawerLayout.closeDrawer(GravityCompat.START) + } else { + leftDrawerLayout.openDrawer(GravityCompat.START) + } } + leftDrawerLayout.addDrawerListener(this) + navigationView.setNavigationItemSelectedListener(this) loginViewModel.loadState.observe(this, { if (it == LoadState.Success) { AuthenticationHelper.removeToken() @@ -205,19 +210,108 @@ expandChartView.setOnClickListener { navigatePageTo(WaterExpandedActivity::class.java) } + + changePwdViewModel.loadState.observe(this, { + when (it) { + is LoadState.Loading -> { + DialogHelper.showLoadingDialog(this, "修改中,请稍后") + } + is LoadState.Success -> { + DialogHelper.dismissLoadingDialog() + AuthenticationHelper.removeToken() + this.navigatePageTo(LoginActivity::class.java) + PageNavigationManager.finishAllActivity() + } + else -> { + DialogHelper.dismissLoadingDialog() + } + } + }) } - private class WeakReferenceHandler(activity: MainActivity) : Handler(Looper.getMainLooper()) { + override fun onDrawerSlide(drawerView: View, slideOffset: Float) { - private val reference: WeakReference = WeakReference(activity) + } - override fun handleMessage(msg: Message) { - super.handleMessage(msg) - val activity = reference.get()!! - + override fun onDrawerOpened(drawerView: View) { + val userDetailJson = SaveKeyValues.getValue(Constant.USER_DETAIL_MODEL, "") as String + if (userDetailJson.isNotBlank()) { + val userDetail = Gson().fromJson( + userDetailJson, object : TypeToken() {}.type + ) + userNameView.text = userDetail.name + userDeptView.text = userDetail.deptName + userRoleView.text = userDetail.roleNames.toString() } } + override fun onDrawerClosed(drawerView: View) { + + } + + override fun onDrawerStateChanged(newState: Int) { + + } + + override fun onNavigationItemSelected(item: MenuItem): Boolean { + when (item.itemId) { + R.id.changePwdView -> { + ChangePasswordDialog.Builder() + .setContext(this) + .setOnDialogButtonClickListener(object : + ChangePasswordDialog.OnDialogButtonClickListener { + override fun onConfirmClick(oldPwd: String, newPwd: String) { + val publicKey = + RSAUtils.keyStrToPublicKey(AuthenticationHelper.publicKey)!! + val oldPassKey = RSAUtils.encryptDataByPublicKey( + oldPwd.toByteArray(StandardCharsets.UTF_8), + publicKey + ) + val newPassKey = RSAUtils.encryptDataByPublicKey( + newPwd.toByteArray(StandardCharsets.UTF_8), + publicKey + ) + changePwdViewModel.changePassword(oldPassKey, newPassKey) + } + }).build().show() + } + R.id.shareApkView -> { + //apk服务器下载地址 +// val downloadPath = "1111" +// val createCodeBitmap = QRUtils.getInstance().createQRCode( +// downloadPath, +// SizeUtil.dp2px(this, 300f), +// SizeUtil.dp2px(this, 300f) +// ) +// ShareDialog.Builder() +// .setContext(this) +// .setDialogTitle("扫以下二维码就可以下载本应用") +// .setDialogBitmap(createCodeBitmap).build().show() + "尽情期待~".show() + } + R.id.versionNameView -> { + "已是最新版本,无需更新".show() + } + R.id.loginOutView -> { + AlertControlDialog.Builder() + .setContext(this) + .setTitle("退出登录") + .setMessage("确定要退出吗?") + .setNegativeButton("取消") + .setPositiveButton("确定") + .setOnDialogButtonClickListener(object : + AlertControlDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + loginViewModel.out() + } + + override fun onCancelClick() {} + }).build().show() + } + } + return false + } + override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { return if (keyCode == KeyEvent.KEYCODE_BACK) { if (System.currentTimeMillis() - clickTime > 2000) { diff --git a/app/src/main/java/com/casic/qd/smartwell/vm/ChangePasswordViewModel.kt b/app/src/main/java/com/casic/qd/smartwell/vm/ChangePasswordViewModel.kt new file mode 100644 index 0000000..751a5f4 --- /dev/null +++ b/app/src/main/java/com/casic/qd/smartwell/vm/ChangePasswordViewModel.kt @@ -0,0 +1,28 @@ +package com.casic.qd.smartwell.vm + +import com.casic.qd.smartwell.base.BaseViewModel +import com.casic.qd.smartwell.extensions.launch +import com.casic.qd.smartwell.extensions.separateResponseCode +import com.casic.qd.smartwell.extensions.show +import com.casic.qd.smartwell.extensions.toErrorMessage +import com.casic.qd.smartwell.utils.LoadState +import com.casic.qd.smartwell.utils.retrofit.RetrofitServiceManager + +class ChangePasswordViewModel : BaseViewModel() { + + fun changePassword(oldPwd: String, newPwd: String) = launch({ + loadState.value = LoadState.Loading + val response = RetrofitServiceManager.changePassword(oldPwd, newPwd) + val responseCode = response.separateResponseCode() + if (responseCode == 200) { + loadState.value = LoadState.Success + "修改成功,请重新登录".show() + } else { + loadState.value = LoadState.Fail + response.toErrorMessage().show() + } + }, { + loadState.value = LoadState.Fail + it.printStackTrace() + }) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/widgets/ChangePasswordDialog.kt b/app/src/main/java/com/casic/qd/smartwell/widgets/ChangePasswordDialog.kt new file mode 100644 index 0000000..98ff307 --- /dev/null +++ b/app/src/main/java/com/casic/qd/smartwell/widgets/ChangePasswordDialog.kt @@ -0,0 +1,81 @@ +package com.casic.qd.smartwell.widgets + +import android.app.Dialog +import android.content.Context +import android.os.Bundle +import android.view.Gravity +import com.casic.qd.smartwell.R +import com.casic.qd.smartwell.extensions.initDialogLayoutParams +import com.casic.qd.smartwell.extensions.isLetterAndDigit +import com.casic.qd.smartwell.extensions.show +import kotlinx.android.synthetic.main.dialog_change_pwd.* + + +/** + * @author: Pengxh + * @email: 290677893@qq.com + * @date: 2020/11/6 22:12 + */ +class ChangePasswordDialog private constructor(builder: Builder) : + Dialog(builder.context, R.style.UserDefinedDialogStyle) { + + private val listener: OnDialogButtonClickListener = builder.listener + + class Builder { + lateinit var context: Context + lateinit var listener: OnDialogButtonClickListener + + fun setContext(context: Context): Builder { + this.context = context + return this + } + + fun setOnDialogButtonClickListener(listener: OnDialogButtonClickListener): Builder { + this.listener = listener + return this + } + + fun build(): ChangePasswordDialog { + return ChangePasswordDialog(this) + } + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + this.initDialogLayoutParams(Gravity.CENTER, R.style.UserDefinedAnimation, 0.85f) + setContentView(R.layout.dialog_change_pwd) + setCancelable(true) + setCanceledOnTouchOutside(true) + + confirmButton.setChangeAlphaWhenPress(true) + confirmButton.setOnClickListener { + val oldPwd = oldPwdView.text.toString() + val newPwd = newPwdView.text.toString() + val confirmPwd = confirmPwdView.text.toString() + if (oldPwd.isBlank()) { + "请输入原密码".show() + return@setOnClickListener + } + if (newPwd.isBlank()) { + "请输入新密码".show() + return@setOnClickListener + } + if (confirmPwd.isBlank()) { + "请在此确认密码".show() + return@setOnClickListener + } + if (!newPwd.isLetterAndDigit()) { + "新密码需包含数字和字母".show() + } + if (newPwd != confirmPwd) { + "新密码和确认密码不一致,请检查".show() + return@setOnClickListener + } + listener.onConfirmClick(oldPwd, newPwd) + } + } + + interface OnDialogButtonClickListener { + fun onConfirmClick(oldPwd: String, newPwd: String) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/widgets/MarqueeTextView.kt b/app/src/main/java/com/casic/qd/smartwell/widgets/MarqueeTextView.kt new file mode 100644 index 0000000..520f6ae --- /dev/null +++ b/app/src/main/java/com/casic/qd/smartwell/widgets/MarqueeTextView.kt @@ -0,0 +1,13 @@ +package com.casic.qd.smartwell.widgets + +import android.content.Context +import android.util.AttributeSet +import androidx.appcompat.widget.AppCompatTextView + +class MarqueeTextView(context: Context, attrs: AttributeSet? = null) : + AppCompatTextView(context, attrs) { + + override fun isFocused(): Boolean { + return true //自动获取焦点 + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/widgets/ShareDialog.kt b/app/src/main/java/com/casic/qd/smartwell/widgets/ShareDialog.kt new file mode 100644 index 0000000..377febc --- /dev/null +++ b/app/src/main/java/com/casic/qd/smartwell/widgets/ShareDialog.kt @@ -0,0 +1,54 @@ +package com.casic.qd.smartwell.widgets + +import android.content.Context +import android.graphics.Bitmap +import android.os.Bundle +import androidx.appcompat.app.AlertDialog +import com.casic.qd.smartwell.R +import kotlinx.android.synthetic.main.dialog_share.* + +/** + * @author: Pengxh + * @email: 290677893@qq.com + */ +class ShareDialog private constructor(builder: Builder) : + AlertDialog(builder.context, R.style.UserDefinedDialogStyle) { + + private var title: String = builder.title + private var bitmap: Bitmap = builder.bitmap + + class Builder { + lateinit var context: Context + lateinit var title: String + lateinit var bitmap: Bitmap + + fun setContext(context: Context): Builder { + this.context = context + return this + } + + fun setDialogTitle(title: String): Builder { + this.title = title + return this + } + + fun setDialogBitmap(bitmap: Bitmap): Builder { + this.bitmap = bitmap + return this + } + + fun build(): ShareDialog { + return ShareDialog(this) + } + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.dialog_share) + setCanceledOnTouchOutside(true) + setCancelable(true) + + shareTitleView.text = title + codeView.setImageBitmap(bitmap) + } +} \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_change_pwd.xml b/app/src/main/res/drawable/ic_change_pwd.xml new file mode 100644 index 0000000..708f7bf --- /dev/null +++ b/app/src/main/res/drawable/ic_change_pwd.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_login_out.xml b/app/src/main/res/drawable/ic_login_out.xml index 208a666..e07996c 100644 --- a/app/src/main/res/drawable/ic_login_out.xml +++ b/app/src/main/res/drawable/ic_login_out.xml @@ -4,9 +4,9 @@ android:viewportWidth="1024" android:viewportHeight="1024"> diff --git a/app/src/main/res/drawable/ic_menu.xml b/app/src/main/res/drawable/ic_menu.xml new file mode 100644 index 0000000..eabc132 --- /dev/null +++ b/app/src/main/res/drawable/ic_menu.xml @@ -0,0 +1,24 @@ + + + + + + + + diff --git a/app/src/main/res/drawable/ic_share.xml b/app/src/main/res/drawable/ic_share.xml new file mode 100644 index 0000000..e309ad4 --- /dev/null +++ b/app/src/main/res/drawable/ic_share.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_update.xml b/app/src/main/res/drawable/ic_update.xml new file mode 100644 index 0000000..4aa8aa9 --- /dev/null +++ b/app/src/main/res/drawable/ic_update.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 4b7cc22..19a7438 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -1,10 +1,12 @@ + + android:src="@drawable/ic_menu" /> - + android:layout_height="match_parent" + android:fitsSystemWindows="true" + tools:openDrawer="start"> - + - - - - - - + android:scrollbars="vertical"> + android:orientation="vertical" + android:padding="@dimen/dp_10"> - + + + android:layout_marginTop="@dimen/dp_10" /> + + + android:layout_height="wrap_content" + android:orientation="vertical"> + + + android:layout_width="match_parent" + android:layout_height="60dp" + android:orientation="horizontal"> - + - - + - + + - + - - + - + + - + - + + + + - - - - - - - - - - - - - - - \ No newline at end of file + android:layout_height="wrap_content" + android:orientation="horizontal"> + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/dialog_change_pwd.xml b/app/src/main/res/layout/dialog_change_pwd.xml new file mode 100644 index 0000000..b4197b8 --- /dev/null +++ b/app/src/main/res/layout/dialog_change_pwd.xml @@ -0,0 +1,146 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_share.xml b/app/src/main/res/layout/dialog_share.xml new file mode 100644 index 0000000..d6b6592 --- /dev/null +++ b/app/src/main/res/layout/dialog_share.xml @@ -0,0 +1,32 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/drawer_header_layout.xml b/app/src/main/res/layout/drawer_header_layout.xml new file mode 100644 index 0000000..49edf71 --- /dev/null +++ b/app/src/main/res/layout/drawer_header_layout.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + diff --git a/app/build.gradle b/app/build.gradle index ca124d1..aec7047 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -99,4 +99,6 @@ implementation 'com.jzxiang.pickerview:TimePickerDialog:1.0.1' //Html解析,爬虫 implementation 'org.jsoup:jsoup:1.14.3' + //ZBar(综合Java和C++扫码),生成二维码 + implementation 'cn.bertsir.zbarLibary:zbarlibary:1.4.2' } \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/extensions/String.kt b/app/src/main/java/com/casic/qd/smartwell/extensions/String.kt index 19808ef..6c2525f 100644 --- a/app/src/main/java/com/casic/qd/smartwell/extensions/String.kt +++ b/app/src/main/java/com/casic/qd/smartwell/extensions/String.kt @@ -76,3 +76,16 @@ } return 0 } + +fun String.isLetterAndDigit(): Boolean { + var isDigit = false + var isLetter = false + for (i in this.indices) { + if (Character.isDigit(this[i])) { + isDigit = true + } else if (Character.isLetter(this[i])) { + isLetter = true + } + } + return isDigit && isLetter +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitService.kt b/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitService.kt index 831f862..f133ef4 100644 --- a/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitService.kt +++ b/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitService.kt @@ -43,6 +43,21 @@ suspend fun obtainUserDetail(@Header("token") token: String): String /** + * 修改密码 + * + * @param oldPwd 旧密码 + * @param newPwd 新密码 + */ + @FormUrlEncoded + @POST("/mgr/changePwd") + suspend fun changePassword( + @Header("token") token: String, + @Field("oldPwd") oldPwd: String, + @Field("newPwd") newPwd: String + ): String + + + /** * 用水统计 */ @GET("/waterStatistic/overview") diff --git a/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitServiceManager.kt index e446f48..9ee4cc1 100644 --- a/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitServiceManager.kt @@ -38,6 +38,13 @@ } /** + * 修改密码 + */ + suspend fun changePassword(oldPwd: String, newPwd: String): String { + return api.changePassword(AuthenticationHelper.token!!, oldPwd, newPwd) + } + + /** * 用水统计 */ suspend fun waterStatistics(): String { diff --git a/app/src/main/java/com/casic/qd/smartwell/view/MainActivity.kt b/app/src/main/java/com/casic/qd/smartwell/view/MainActivity.kt index 8f41c87..d8af9d8 100644 --- a/app/src/main/java/com/casic/qd/smartwell/view/MainActivity.kt +++ b/app/src/main/java/com/casic/qd/smartwell/view/MainActivity.kt @@ -1,11 +1,12 @@ package com.casic.qd.smartwell.view import android.content.Context -import android.os.Handler -import android.os.Looper -import android.os.Message import android.util.Log import android.view.KeyEvent +import android.view.MenuItem +import android.view.View +import androidx.core.view.GravityCompat +import androidx.drawerlayout.widget.DrawerLayout import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.GridLayoutManager @@ -16,10 +17,14 @@ import com.casic.qd.smartwell.extensions.* import com.casic.qd.smartwell.model.BannerImageModel import com.casic.qd.smartwell.model.LineChartEntryModel +import com.casic.qd.smartwell.model.UserDetailModel import com.casic.qd.smartwell.utils.* +import com.casic.qd.smartwell.vm.ChangePasswordViewModel import com.casic.qd.smartwell.vm.LoginViewModel import com.casic.qd.smartwell.vm.WaterStatisticsViewModel +import com.casic.qd.smartwell.widgets.ChangePasswordDialog import com.github.mikephil.charting.data.Entry +import com.google.android.material.navigation.NavigationView import com.google.gson.Gson import com.google.gson.reflect.TypeToken import com.pengxh.app.multilib.widget.dialog.AlertControlDialog @@ -29,22 +34,29 @@ import com.youth.banner.holder.BannerImageHolder import com.youth.banner.indicator.CircleIndicator import com.youth.banner.transformer.ScaleInTransformer +import kotlinx.android.synthetic.main.activity_data_search.* import kotlinx.android.synthetic.main.activity_main.* -import java.lang.ref.WeakReference +import kotlinx.android.synthetic.main.activity_main.rightOptionView +import kotlinx.android.synthetic.main.activity_main.titleView +import kotlinx.android.synthetic.main.activity_main.view.* +import kotlinx.android.synthetic.main.drawer_header_layout.* +import kotlinx.android.synthetic.main.drawer_header_layout.view.* +import java.nio.charset.StandardCharsets import java.util.* import kotlin.collections.ArrayList -class MainActivity : BaseActivity() { +class MainActivity : BaseActivity(), DrawerLayout.DrawerListener, + NavigationView.OnNavigationItemSelectedListener { private val kTag = "MainActivity" private val context: Context = this@MainActivity private var clickTime: Long = 0 private lateinit var loginViewModel: LoginViewModel private lateinit var waterViewModel: WaterStatisticsViewModel + private lateinit var changePwdViewModel: ChangePasswordViewModel private val xAxisDate: MutableList = ArrayList() private val entryModels: MutableList = ArrayList() private var imageModels: MutableList = ArrayList() - private lateinit var weakReferenceHandler: WeakReferenceHandler override fun initLayoutView(): Int = R.layout.activity_main @@ -53,10 +65,10 @@ } override fun initData() { - val bannerJsonModel = SaveKeyValues.getValue(Constant.BANNER_MODEL, "") as String - if (bannerJsonModel.isNotBlank()) { + val bannerJson = SaveKeyValues.getValue(Constant.BANNER_MODEL, "") as String + if (bannerJson.isNotBlank()) { imageModels = Gson().fromJson( - bannerJsonModel, object : TypeToken>() {}.type + bannerJson, object : TypeToken>() {}.type ) } else { Constant.NEWS_PAGE.forEach { @@ -127,26 +139,19 @@ //初始化vm loginViewModel = ViewModelProvider(this).get(LoginViewModel::class.java) waterViewModel = ViewModelProvider(this).get(WaterStatisticsViewModel::class.java) - weakReferenceHandler = WeakReferenceHandler(this) + changePwdViewModel = ViewModelProvider(this).get(ChangePasswordViewModel::class.java) } override fun initEvent() { leftOptionView.setOnClickListener { - AlertControlDialog.Builder() - .setContext(this) - .setTitle("退出登录") - .setMessage("确定要退出吗?") - .setNegativeButton("取消") - .setPositiveButton("确定") - .setOnDialogButtonClickListener(object : - AlertControlDialog.OnDialogButtonClickListener { - override fun onConfirmClick() { - loginViewModel.out() - } - - override fun onCancelClick() {} - }).build().show() + if (leftDrawerLayout.isDrawerOpen(GravityCompat.START)) { + leftDrawerLayout.closeDrawer(GravityCompat.START) + } else { + leftDrawerLayout.openDrawer(GravityCompat.START) + } } + leftDrawerLayout.addDrawerListener(this) + navigationView.setNavigationItemSelectedListener(this) loginViewModel.loadState.observe(this, { if (it == LoadState.Success) { AuthenticationHelper.removeToken() @@ -205,19 +210,108 @@ expandChartView.setOnClickListener { navigatePageTo(WaterExpandedActivity::class.java) } + + changePwdViewModel.loadState.observe(this, { + when (it) { + is LoadState.Loading -> { + DialogHelper.showLoadingDialog(this, "修改中,请稍后") + } + is LoadState.Success -> { + DialogHelper.dismissLoadingDialog() + AuthenticationHelper.removeToken() + this.navigatePageTo(LoginActivity::class.java) + PageNavigationManager.finishAllActivity() + } + else -> { + DialogHelper.dismissLoadingDialog() + } + } + }) } - private class WeakReferenceHandler(activity: MainActivity) : Handler(Looper.getMainLooper()) { + override fun onDrawerSlide(drawerView: View, slideOffset: Float) { - private val reference: WeakReference = WeakReference(activity) + } - override fun handleMessage(msg: Message) { - super.handleMessage(msg) - val activity = reference.get()!! - + override fun onDrawerOpened(drawerView: View) { + val userDetailJson = SaveKeyValues.getValue(Constant.USER_DETAIL_MODEL, "") as String + if (userDetailJson.isNotBlank()) { + val userDetail = Gson().fromJson( + userDetailJson, object : TypeToken() {}.type + ) + userNameView.text = userDetail.name + userDeptView.text = userDetail.deptName + userRoleView.text = userDetail.roleNames.toString() } } + override fun onDrawerClosed(drawerView: View) { + + } + + override fun onDrawerStateChanged(newState: Int) { + + } + + override fun onNavigationItemSelected(item: MenuItem): Boolean { + when (item.itemId) { + R.id.changePwdView -> { + ChangePasswordDialog.Builder() + .setContext(this) + .setOnDialogButtonClickListener(object : + ChangePasswordDialog.OnDialogButtonClickListener { + override fun onConfirmClick(oldPwd: String, newPwd: String) { + val publicKey = + RSAUtils.keyStrToPublicKey(AuthenticationHelper.publicKey)!! + val oldPassKey = RSAUtils.encryptDataByPublicKey( + oldPwd.toByteArray(StandardCharsets.UTF_8), + publicKey + ) + val newPassKey = RSAUtils.encryptDataByPublicKey( + newPwd.toByteArray(StandardCharsets.UTF_8), + publicKey + ) + changePwdViewModel.changePassword(oldPassKey, newPassKey) + } + }).build().show() + } + R.id.shareApkView -> { + //apk服务器下载地址 +// val downloadPath = "1111" +// val createCodeBitmap = QRUtils.getInstance().createQRCode( +// downloadPath, +// SizeUtil.dp2px(this, 300f), +// SizeUtil.dp2px(this, 300f) +// ) +// ShareDialog.Builder() +// .setContext(this) +// .setDialogTitle("扫以下二维码就可以下载本应用") +// .setDialogBitmap(createCodeBitmap).build().show() + "尽情期待~".show() + } + R.id.versionNameView -> { + "已是最新版本,无需更新".show() + } + R.id.loginOutView -> { + AlertControlDialog.Builder() + .setContext(this) + .setTitle("退出登录") + .setMessage("确定要退出吗?") + .setNegativeButton("取消") + .setPositiveButton("确定") + .setOnDialogButtonClickListener(object : + AlertControlDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + loginViewModel.out() + } + + override fun onCancelClick() {} + }).build().show() + } + } + return false + } + override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { return if (keyCode == KeyEvent.KEYCODE_BACK) { if (System.currentTimeMillis() - clickTime > 2000) { diff --git a/app/src/main/java/com/casic/qd/smartwell/vm/ChangePasswordViewModel.kt b/app/src/main/java/com/casic/qd/smartwell/vm/ChangePasswordViewModel.kt new file mode 100644 index 0000000..751a5f4 --- /dev/null +++ b/app/src/main/java/com/casic/qd/smartwell/vm/ChangePasswordViewModel.kt @@ -0,0 +1,28 @@ +package com.casic.qd.smartwell.vm + +import com.casic.qd.smartwell.base.BaseViewModel +import com.casic.qd.smartwell.extensions.launch +import com.casic.qd.smartwell.extensions.separateResponseCode +import com.casic.qd.smartwell.extensions.show +import com.casic.qd.smartwell.extensions.toErrorMessage +import com.casic.qd.smartwell.utils.LoadState +import com.casic.qd.smartwell.utils.retrofit.RetrofitServiceManager + +class ChangePasswordViewModel : BaseViewModel() { + + fun changePassword(oldPwd: String, newPwd: String) = launch({ + loadState.value = LoadState.Loading + val response = RetrofitServiceManager.changePassword(oldPwd, newPwd) + val responseCode = response.separateResponseCode() + if (responseCode == 200) { + loadState.value = LoadState.Success + "修改成功,请重新登录".show() + } else { + loadState.value = LoadState.Fail + response.toErrorMessage().show() + } + }, { + loadState.value = LoadState.Fail + it.printStackTrace() + }) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/widgets/ChangePasswordDialog.kt b/app/src/main/java/com/casic/qd/smartwell/widgets/ChangePasswordDialog.kt new file mode 100644 index 0000000..98ff307 --- /dev/null +++ b/app/src/main/java/com/casic/qd/smartwell/widgets/ChangePasswordDialog.kt @@ -0,0 +1,81 @@ +package com.casic.qd.smartwell.widgets + +import android.app.Dialog +import android.content.Context +import android.os.Bundle +import android.view.Gravity +import com.casic.qd.smartwell.R +import com.casic.qd.smartwell.extensions.initDialogLayoutParams +import com.casic.qd.smartwell.extensions.isLetterAndDigit +import com.casic.qd.smartwell.extensions.show +import kotlinx.android.synthetic.main.dialog_change_pwd.* + + +/** + * @author: Pengxh + * @email: 290677893@qq.com + * @date: 2020/11/6 22:12 + */ +class ChangePasswordDialog private constructor(builder: Builder) : + Dialog(builder.context, R.style.UserDefinedDialogStyle) { + + private val listener: OnDialogButtonClickListener = builder.listener + + class Builder { + lateinit var context: Context + lateinit var listener: OnDialogButtonClickListener + + fun setContext(context: Context): Builder { + this.context = context + return this + } + + fun setOnDialogButtonClickListener(listener: OnDialogButtonClickListener): Builder { + this.listener = listener + return this + } + + fun build(): ChangePasswordDialog { + return ChangePasswordDialog(this) + } + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + this.initDialogLayoutParams(Gravity.CENTER, R.style.UserDefinedAnimation, 0.85f) + setContentView(R.layout.dialog_change_pwd) + setCancelable(true) + setCanceledOnTouchOutside(true) + + confirmButton.setChangeAlphaWhenPress(true) + confirmButton.setOnClickListener { + val oldPwd = oldPwdView.text.toString() + val newPwd = newPwdView.text.toString() + val confirmPwd = confirmPwdView.text.toString() + if (oldPwd.isBlank()) { + "请输入原密码".show() + return@setOnClickListener + } + if (newPwd.isBlank()) { + "请输入新密码".show() + return@setOnClickListener + } + if (confirmPwd.isBlank()) { + "请在此确认密码".show() + return@setOnClickListener + } + if (!newPwd.isLetterAndDigit()) { + "新密码需包含数字和字母".show() + } + if (newPwd != confirmPwd) { + "新密码和确认密码不一致,请检查".show() + return@setOnClickListener + } + listener.onConfirmClick(oldPwd, newPwd) + } + } + + interface OnDialogButtonClickListener { + fun onConfirmClick(oldPwd: String, newPwd: String) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/widgets/MarqueeTextView.kt b/app/src/main/java/com/casic/qd/smartwell/widgets/MarqueeTextView.kt new file mode 100644 index 0000000..520f6ae --- /dev/null +++ b/app/src/main/java/com/casic/qd/smartwell/widgets/MarqueeTextView.kt @@ -0,0 +1,13 @@ +package com.casic.qd.smartwell.widgets + +import android.content.Context +import android.util.AttributeSet +import androidx.appcompat.widget.AppCompatTextView + +class MarqueeTextView(context: Context, attrs: AttributeSet? = null) : + AppCompatTextView(context, attrs) { + + override fun isFocused(): Boolean { + return true //自动获取焦点 + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/widgets/ShareDialog.kt b/app/src/main/java/com/casic/qd/smartwell/widgets/ShareDialog.kt new file mode 100644 index 0000000..377febc --- /dev/null +++ b/app/src/main/java/com/casic/qd/smartwell/widgets/ShareDialog.kt @@ -0,0 +1,54 @@ +package com.casic.qd.smartwell.widgets + +import android.content.Context +import android.graphics.Bitmap +import android.os.Bundle +import androidx.appcompat.app.AlertDialog +import com.casic.qd.smartwell.R +import kotlinx.android.synthetic.main.dialog_share.* + +/** + * @author: Pengxh + * @email: 290677893@qq.com + */ +class ShareDialog private constructor(builder: Builder) : + AlertDialog(builder.context, R.style.UserDefinedDialogStyle) { + + private var title: String = builder.title + private var bitmap: Bitmap = builder.bitmap + + class Builder { + lateinit var context: Context + lateinit var title: String + lateinit var bitmap: Bitmap + + fun setContext(context: Context): Builder { + this.context = context + return this + } + + fun setDialogTitle(title: String): Builder { + this.title = title + return this + } + + fun setDialogBitmap(bitmap: Bitmap): Builder { + this.bitmap = bitmap + return this + } + + fun build(): ShareDialog { + return ShareDialog(this) + } + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.dialog_share) + setCanceledOnTouchOutside(true) + setCancelable(true) + + shareTitleView.text = title + codeView.setImageBitmap(bitmap) + } +} \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_change_pwd.xml b/app/src/main/res/drawable/ic_change_pwd.xml new file mode 100644 index 0000000..708f7bf --- /dev/null +++ b/app/src/main/res/drawable/ic_change_pwd.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_login_out.xml b/app/src/main/res/drawable/ic_login_out.xml index 208a666..e07996c 100644 --- a/app/src/main/res/drawable/ic_login_out.xml +++ b/app/src/main/res/drawable/ic_login_out.xml @@ -4,9 +4,9 @@ android:viewportWidth="1024" android:viewportHeight="1024"> diff --git a/app/src/main/res/drawable/ic_menu.xml b/app/src/main/res/drawable/ic_menu.xml new file mode 100644 index 0000000..eabc132 --- /dev/null +++ b/app/src/main/res/drawable/ic_menu.xml @@ -0,0 +1,24 @@ + + + + + + + + diff --git a/app/src/main/res/drawable/ic_share.xml b/app/src/main/res/drawable/ic_share.xml new file mode 100644 index 0000000..e309ad4 --- /dev/null +++ b/app/src/main/res/drawable/ic_share.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_update.xml b/app/src/main/res/drawable/ic_update.xml new file mode 100644 index 0000000..4aa8aa9 --- /dev/null +++ b/app/src/main/res/drawable/ic_update.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 4b7cc22..19a7438 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -1,10 +1,12 @@ + + android:src="@drawable/ic_menu" /> - + android:layout_height="match_parent" + android:fitsSystemWindows="true" + tools:openDrawer="start"> - + - - - - - - + android:scrollbars="vertical"> + android:orientation="vertical" + android:padding="@dimen/dp_10"> - + + + android:layout_marginTop="@dimen/dp_10" /> + + + android:layout_height="wrap_content" + android:orientation="vertical"> + + + android:layout_width="match_parent" + android:layout_height="60dp" + android:orientation="horizontal"> - + - - + - + + - + - - + - + + - + - + + + + - - - - - - - - - - - - - - - \ No newline at end of file + android:layout_height="wrap_content" + android:orientation="horizontal"> + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/dialog_change_pwd.xml b/app/src/main/res/layout/dialog_change_pwd.xml new file mode 100644 index 0000000..b4197b8 --- /dev/null +++ b/app/src/main/res/layout/dialog_change_pwd.xml @@ -0,0 +1,146 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_share.xml b/app/src/main/res/layout/dialog_share.xml new file mode 100644 index 0000000..d6b6592 --- /dev/null +++ b/app/src/main/res/layout/dialog_share.xml @@ -0,0 +1,32 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/drawer_header_layout.xml b/app/src/main/res/layout/drawer_header_layout.xml new file mode 100644 index 0000000..49edf71 --- /dev/null +++ b/app/src/main/res/layout/drawer_header_layout.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + diff --git a/app/src/main/res/menu/drawer_left_menu.xml b/app/src/main/res/menu/drawer_left_menu.xml new file mode 100644 index 0000000..0b2f055 --- /dev/null +++ b/app/src/main/res/menu/drawer_left_menu.xml @@ -0,0 +1,23 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index ca124d1..aec7047 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -99,4 +99,6 @@ implementation 'com.jzxiang.pickerview:TimePickerDialog:1.0.1' //Html解析,爬虫 implementation 'org.jsoup:jsoup:1.14.3' + //ZBar(综合Java和C++扫码),生成二维码 + implementation 'cn.bertsir.zbarLibary:zbarlibary:1.4.2' } \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/extensions/String.kt b/app/src/main/java/com/casic/qd/smartwell/extensions/String.kt index 19808ef..6c2525f 100644 --- a/app/src/main/java/com/casic/qd/smartwell/extensions/String.kt +++ b/app/src/main/java/com/casic/qd/smartwell/extensions/String.kt @@ -76,3 +76,16 @@ } return 0 } + +fun String.isLetterAndDigit(): Boolean { + var isDigit = false + var isLetter = false + for (i in this.indices) { + if (Character.isDigit(this[i])) { + isDigit = true + } else if (Character.isLetter(this[i])) { + isLetter = true + } + } + return isDigit && isLetter +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitService.kt b/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitService.kt index 831f862..f133ef4 100644 --- a/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitService.kt +++ b/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitService.kt @@ -43,6 +43,21 @@ suspend fun obtainUserDetail(@Header("token") token: String): String /** + * 修改密码 + * + * @param oldPwd 旧密码 + * @param newPwd 新密码 + */ + @FormUrlEncoded + @POST("/mgr/changePwd") + suspend fun changePassword( + @Header("token") token: String, + @Field("oldPwd") oldPwd: String, + @Field("newPwd") newPwd: String + ): String + + + /** * 用水统计 */ @GET("/waterStatistic/overview") diff --git a/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitServiceManager.kt b/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitServiceManager.kt index e446f48..9ee4cc1 100644 --- a/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitServiceManager.kt +++ b/app/src/main/java/com/casic/qd/smartwell/utils/retrofit/RetrofitServiceManager.kt @@ -38,6 +38,13 @@ } /** + * 修改密码 + */ + suspend fun changePassword(oldPwd: String, newPwd: String): String { + return api.changePassword(AuthenticationHelper.token!!, oldPwd, newPwd) + } + + /** * 用水统计 */ suspend fun waterStatistics(): String { diff --git a/app/src/main/java/com/casic/qd/smartwell/view/MainActivity.kt b/app/src/main/java/com/casic/qd/smartwell/view/MainActivity.kt index 8f41c87..d8af9d8 100644 --- a/app/src/main/java/com/casic/qd/smartwell/view/MainActivity.kt +++ b/app/src/main/java/com/casic/qd/smartwell/view/MainActivity.kt @@ -1,11 +1,12 @@ package com.casic.qd.smartwell.view import android.content.Context -import android.os.Handler -import android.os.Looper -import android.os.Message import android.util.Log import android.view.KeyEvent +import android.view.MenuItem +import android.view.View +import androidx.core.view.GravityCompat +import androidx.drawerlayout.widget.DrawerLayout import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.GridLayoutManager @@ -16,10 +17,14 @@ import com.casic.qd.smartwell.extensions.* import com.casic.qd.smartwell.model.BannerImageModel import com.casic.qd.smartwell.model.LineChartEntryModel +import com.casic.qd.smartwell.model.UserDetailModel import com.casic.qd.smartwell.utils.* +import com.casic.qd.smartwell.vm.ChangePasswordViewModel import com.casic.qd.smartwell.vm.LoginViewModel import com.casic.qd.smartwell.vm.WaterStatisticsViewModel +import com.casic.qd.smartwell.widgets.ChangePasswordDialog import com.github.mikephil.charting.data.Entry +import com.google.android.material.navigation.NavigationView import com.google.gson.Gson import com.google.gson.reflect.TypeToken import com.pengxh.app.multilib.widget.dialog.AlertControlDialog @@ -29,22 +34,29 @@ import com.youth.banner.holder.BannerImageHolder import com.youth.banner.indicator.CircleIndicator import com.youth.banner.transformer.ScaleInTransformer +import kotlinx.android.synthetic.main.activity_data_search.* import kotlinx.android.synthetic.main.activity_main.* -import java.lang.ref.WeakReference +import kotlinx.android.synthetic.main.activity_main.rightOptionView +import kotlinx.android.synthetic.main.activity_main.titleView +import kotlinx.android.synthetic.main.activity_main.view.* +import kotlinx.android.synthetic.main.drawer_header_layout.* +import kotlinx.android.synthetic.main.drawer_header_layout.view.* +import java.nio.charset.StandardCharsets import java.util.* import kotlin.collections.ArrayList -class MainActivity : BaseActivity() { +class MainActivity : BaseActivity(), DrawerLayout.DrawerListener, + NavigationView.OnNavigationItemSelectedListener { private val kTag = "MainActivity" private val context: Context = this@MainActivity private var clickTime: Long = 0 private lateinit var loginViewModel: LoginViewModel private lateinit var waterViewModel: WaterStatisticsViewModel + private lateinit var changePwdViewModel: ChangePasswordViewModel private val xAxisDate: MutableList = ArrayList() private val entryModels: MutableList = ArrayList() private var imageModels: MutableList = ArrayList() - private lateinit var weakReferenceHandler: WeakReferenceHandler override fun initLayoutView(): Int = R.layout.activity_main @@ -53,10 +65,10 @@ } override fun initData() { - val bannerJsonModel = SaveKeyValues.getValue(Constant.BANNER_MODEL, "") as String - if (bannerJsonModel.isNotBlank()) { + val bannerJson = SaveKeyValues.getValue(Constant.BANNER_MODEL, "") as String + if (bannerJson.isNotBlank()) { imageModels = Gson().fromJson( - bannerJsonModel, object : TypeToken>() {}.type + bannerJson, object : TypeToken>() {}.type ) } else { Constant.NEWS_PAGE.forEach { @@ -127,26 +139,19 @@ //初始化vm loginViewModel = ViewModelProvider(this).get(LoginViewModel::class.java) waterViewModel = ViewModelProvider(this).get(WaterStatisticsViewModel::class.java) - weakReferenceHandler = WeakReferenceHandler(this) + changePwdViewModel = ViewModelProvider(this).get(ChangePasswordViewModel::class.java) } override fun initEvent() { leftOptionView.setOnClickListener { - AlertControlDialog.Builder() - .setContext(this) - .setTitle("退出登录") - .setMessage("确定要退出吗?") - .setNegativeButton("取消") - .setPositiveButton("确定") - .setOnDialogButtonClickListener(object : - AlertControlDialog.OnDialogButtonClickListener { - override fun onConfirmClick() { - loginViewModel.out() - } - - override fun onCancelClick() {} - }).build().show() + if (leftDrawerLayout.isDrawerOpen(GravityCompat.START)) { + leftDrawerLayout.closeDrawer(GravityCompat.START) + } else { + leftDrawerLayout.openDrawer(GravityCompat.START) + } } + leftDrawerLayout.addDrawerListener(this) + navigationView.setNavigationItemSelectedListener(this) loginViewModel.loadState.observe(this, { if (it == LoadState.Success) { AuthenticationHelper.removeToken() @@ -205,19 +210,108 @@ expandChartView.setOnClickListener { navigatePageTo(WaterExpandedActivity::class.java) } + + changePwdViewModel.loadState.observe(this, { + when (it) { + is LoadState.Loading -> { + DialogHelper.showLoadingDialog(this, "修改中,请稍后") + } + is LoadState.Success -> { + DialogHelper.dismissLoadingDialog() + AuthenticationHelper.removeToken() + this.navigatePageTo(LoginActivity::class.java) + PageNavigationManager.finishAllActivity() + } + else -> { + DialogHelper.dismissLoadingDialog() + } + } + }) } - private class WeakReferenceHandler(activity: MainActivity) : Handler(Looper.getMainLooper()) { + override fun onDrawerSlide(drawerView: View, slideOffset: Float) { - private val reference: WeakReference = WeakReference(activity) + } - override fun handleMessage(msg: Message) { - super.handleMessage(msg) - val activity = reference.get()!! - + override fun onDrawerOpened(drawerView: View) { + val userDetailJson = SaveKeyValues.getValue(Constant.USER_DETAIL_MODEL, "") as String + if (userDetailJson.isNotBlank()) { + val userDetail = Gson().fromJson( + userDetailJson, object : TypeToken() {}.type + ) + userNameView.text = userDetail.name + userDeptView.text = userDetail.deptName + userRoleView.text = userDetail.roleNames.toString() } } + override fun onDrawerClosed(drawerView: View) { + + } + + override fun onDrawerStateChanged(newState: Int) { + + } + + override fun onNavigationItemSelected(item: MenuItem): Boolean { + when (item.itemId) { + R.id.changePwdView -> { + ChangePasswordDialog.Builder() + .setContext(this) + .setOnDialogButtonClickListener(object : + ChangePasswordDialog.OnDialogButtonClickListener { + override fun onConfirmClick(oldPwd: String, newPwd: String) { + val publicKey = + RSAUtils.keyStrToPublicKey(AuthenticationHelper.publicKey)!! + val oldPassKey = RSAUtils.encryptDataByPublicKey( + oldPwd.toByteArray(StandardCharsets.UTF_8), + publicKey + ) + val newPassKey = RSAUtils.encryptDataByPublicKey( + newPwd.toByteArray(StandardCharsets.UTF_8), + publicKey + ) + changePwdViewModel.changePassword(oldPassKey, newPassKey) + } + }).build().show() + } + R.id.shareApkView -> { + //apk服务器下载地址 +// val downloadPath = "1111" +// val createCodeBitmap = QRUtils.getInstance().createQRCode( +// downloadPath, +// SizeUtil.dp2px(this, 300f), +// SizeUtil.dp2px(this, 300f) +// ) +// ShareDialog.Builder() +// .setContext(this) +// .setDialogTitle("扫以下二维码就可以下载本应用") +// .setDialogBitmap(createCodeBitmap).build().show() + "尽情期待~".show() + } + R.id.versionNameView -> { + "已是最新版本,无需更新".show() + } + R.id.loginOutView -> { + AlertControlDialog.Builder() + .setContext(this) + .setTitle("退出登录") + .setMessage("确定要退出吗?") + .setNegativeButton("取消") + .setPositiveButton("确定") + .setOnDialogButtonClickListener(object : + AlertControlDialog.OnDialogButtonClickListener { + override fun onConfirmClick() { + loginViewModel.out() + } + + override fun onCancelClick() {} + }).build().show() + } + } + return false + } + override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { return if (keyCode == KeyEvent.KEYCODE_BACK) { if (System.currentTimeMillis() - clickTime > 2000) { diff --git a/app/src/main/java/com/casic/qd/smartwell/vm/ChangePasswordViewModel.kt b/app/src/main/java/com/casic/qd/smartwell/vm/ChangePasswordViewModel.kt new file mode 100644 index 0000000..751a5f4 --- /dev/null +++ b/app/src/main/java/com/casic/qd/smartwell/vm/ChangePasswordViewModel.kt @@ -0,0 +1,28 @@ +package com.casic.qd.smartwell.vm + +import com.casic.qd.smartwell.base.BaseViewModel +import com.casic.qd.smartwell.extensions.launch +import com.casic.qd.smartwell.extensions.separateResponseCode +import com.casic.qd.smartwell.extensions.show +import com.casic.qd.smartwell.extensions.toErrorMessage +import com.casic.qd.smartwell.utils.LoadState +import com.casic.qd.smartwell.utils.retrofit.RetrofitServiceManager + +class ChangePasswordViewModel : BaseViewModel() { + + fun changePassword(oldPwd: String, newPwd: String) = launch({ + loadState.value = LoadState.Loading + val response = RetrofitServiceManager.changePassword(oldPwd, newPwd) + val responseCode = response.separateResponseCode() + if (responseCode == 200) { + loadState.value = LoadState.Success + "修改成功,请重新登录".show() + } else { + loadState.value = LoadState.Fail + response.toErrorMessage().show() + } + }, { + loadState.value = LoadState.Fail + it.printStackTrace() + }) +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/widgets/ChangePasswordDialog.kt b/app/src/main/java/com/casic/qd/smartwell/widgets/ChangePasswordDialog.kt new file mode 100644 index 0000000..98ff307 --- /dev/null +++ b/app/src/main/java/com/casic/qd/smartwell/widgets/ChangePasswordDialog.kt @@ -0,0 +1,81 @@ +package com.casic.qd.smartwell.widgets + +import android.app.Dialog +import android.content.Context +import android.os.Bundle +import android.view.Gravity +import com.casic.qd.smartwell.R +import com.casic.qd.smartwell.extensions.initDialogLayoutParams +import com.casic.qd.smartwell.extensions.isLetterAndDigit +import com.casic.qd.smartwell.extensions.show +import kotlinx.android.synthetic.main.dialog_change_pwd.* + + +/** + * @author: Pengxh + * @email: 290677893@qq.com + * @date: 2020/11/6 22:12 + */ +class ChangePasswordDialog private constructor(builder: Builder) : + Dialog(builder.context, R.style.UserDefinedDialogStyle) { + + private val listener: OnDialogButtonClickListener = builder.listener + + class Builder { + lateinit var context: Context + lateinit var listener: OnDialogButtonClickListener + + fun setContext(context: Context): Builder { + this.context = context + return this + } + + fun setOnDialogButtonClickListener(listener: OnDialogButtonClickListener): Builder { + this.listener = listener + return this + } + + fun build(): ChangePasswordDialog { + return ChangePasswordDialog(this) + } + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + this.initDialogLayoutParams(Gravity.CENTER, R.style.UserDefinedAnimation, 0.85f) + setContentView(R.layout.dialog_change_pwd) + setCancelable(true) + setCanceledOnTouchOutside(true) + + confirmButton.setChangeAlphaWhenPress(true) + confirmButton.setOnClickListener { + val oldPwd = oldPwdView.text.toString() + val newPwd = newPwdView.text.toString() + val confirmPwd = confirmPwdView.text.toString() + if (oldPwd.isBlank()) { + "请输入原密码".show() + return@setOnClickListener + } + if (newPwd.isBlank()) { + "请输入新密码".show() + return@setOnClickListener + } + if (confirmPwd.isBlank()) { + "请在此确认密码".show() + return@setOnClickListener + } + if (!newPwd.isLetterAndDigit()) { + "新密码需包含数字和字母".show() + } + if (newPwd != confirmPwd) { + "新密码和确认密码不一致,请检查".show() + return@setOnClickListener + } + listener.onConfirmClick(oldPwd, newPwd) + } + } + + interface OnDialogButtonClickListener { + fun onConfirmClick(oldPwd: String, newPwd: String) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/widgets/MarqueeTextView.kt b/app/src/main/java/com/casic/qd/smartwell/widgets/MarqueeTextView.kt new file mode 100644 index 0000000..520f6ae --- /dev/null +++ b/app/src/main/java/com/casic/qd/smartwell/widgets/MarqueeTextView.kt @@ -0,0 +1,13 @@ +package com.casic.qd.smartwell.widgets + +import android.content.Context +import android.util.AttributeSet +import androidx.appcompat.widget.AppCompatTextView + +class MarqueeTextView(context: Context, attrs: AttributeSet? = null) : + AppCompatTextView(context, attrs) { + + override fun isFocused(): Boolean { + return true //自动获取焦点 + } +} \ No newline at end of file diff --git a/app/src/main/java/com/casic/qd/smartwell/widgets/ShareDialog.kt b/app/src/main/java/com/casic/qd/smartwell/widgets/ShareDialog.kt new file mode 100644 index 0000000..377febc --- /dev/null +++ b/app/src/main/java/com/casic/qd/smartwell/widgets/ShareDialog.kt @@ -0,0 +1,54 @@ +package com.casic.qd.smartwell.widgets + +import android.content.Context +import android.graphics.Bitmap +import android.os.Bundle +import androidx.appcompat.app.AlertDialog +import com.casic.qd.smartwell.R +import kotlinx.android.synthetic.main.dialog_share.* + +/** + * @author: Pengxh + * @email: 290677893@qq.com + */ +class ShareDialog private constructor(builder: Builder) : + AlertDialog(builder.context, R.style.UserDefinedDialogStyle) { + + private var title: String = builder.title + private var bitmap: Bitmap = builder.bitmap + + class Builder { + lateinit var context: Context + lateinit var title: String + lateinit var bitmap: Bitmap + + fun setContext(context: Context): Builder { + this.context = context + return this + } + + fun setDialogTitle(title: String): Builder { + this.title = title + return this + } + + fun setDialogBitmap(bitmap: Bitmap): Builder { + this.bitmap = bitmap + return this + } + + fun build(): ShareDialog { + return ShareDialog(this) + } + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.dialog_share) + setCanceledOnTouchOutside(true) + setCancelable(true) + + shareTitleView.text = title + codeView.setImageBitmap(bitmap) + } +} \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_change_pwd.xml b/app/src/main/res/drawable/ic_change_pwd.xml new file mode 100644 index 0000000..708f7bf --- /dev/null +++ b/app/src/main/res/drawable/ic_change_pwd.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_login_out.xml b/app/src/main/res/drawable/ic_login_out.xml index 208a666..e07996c 100644 --- a/app/src/main/res/drawable/ic_login_out.xml +++ b/app/src/main/res/drawable/ic_login_out.xml @@ -4,9 +4,9 @@ android:viewportWidth="1024" android:viewportHeight="1024"> diff --git a/app/src/main/res/drawable/ic_menu.xml b/app/src/main/res/drawable/ic_menu.xml new file mode 100644 index 0000000..eabc132 --- /dev/null +++ b/app/src/main/res/drawable/ic_menu.xml @@ -0,0 +1,24 @@ + + + + + + + + diff --git a/app/src/main/res/drawable/ic_share.xml b/app/src/main/res/drawable/ic_share.xml new file mode 100644 index 0000000..e309ad4 --- /dev/null +++ b/app/src/main/res/drawable/ic_share.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_update.xml b/app/src/main/res/drawable/ic_update.xml new file mode 100644 index 0000000..4aa8aa9 --- /dev/null +++ b/app/src/main/res/drawable/ic_update.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 4b7cc22..19a7438 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -1,10 +1,12 @@ + + android:src="@drawable/ic_menu" /> - + android:layout_height="match_parent" + android:fitsSystemWindows="true" + tools:openDrawer="start"> - + - - - - - - + android:scrollbars="vertical"> + android:orientation="vertical" + android:padding="@dimen/dp_10"> - + + + android:layout_marginTop="@dimen/dp_10" /> + + + android:layout_height="wrap_content" + android:orientation="vertical"> + + + android:layout_width="match_parent" + android:layout_height="60dp" + android:orientation="horizontal"> - + - - + - + + - + - - + - + + - + - + + + + - - - - - - - - - - - - - - - \ No newline at end of file + android:layout_height="wrap_content" + android:orientation="horizontal"> + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/dialog_change_pwd.xml b/app/src/main/res/layout/dialog_change_pwd.xml new file mode 100644 index 0000000..b4197b8 --- /dev/null +++ b/app/src/main/res/layout/dialog_change_pwd.xml @@ -0,0 +1,146 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_share.xml b/app/src/main/res/layout/dialog_share.xml new file mode 100644 index 0000000..d6b6592 --- /dev/null +++ b/app/src/main/res/layout/dialog_share.xml @@ -0,0 +1,32 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/drawer_header_layout.xml b/app/src/main/res/layout/drawer_header_layout.xml new file mode 100644 index 0000000..49edf71 --- /dev/null +++ b/app/src/main/res/layout/drawer_header_layout.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + diff --git a/app/src/main/res/menu/drawer_left_menu.xml b/app/src/main/res/menu/drawer_left_menu.xml new file mode 100644 index 0000000..0b2f055 --- /dev/null +++ b/app/src/main/res/menu/drawer_left_menu.xml @@ -0,0 +1,23 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 897244d..4d2da71 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -143,4 +143,8 @@ @anim/popup_show @anim/popup_hide + +