feat: 新增修改用户密码功能

- 新增修改用户密码功能
- 修改设置界面为activity
This commit is contained in:
糕小菜 2024-12-15 22:44:13 +08:00
parent 293fe2c3ef
commit 00e34df0fb
11 changed files with 360 additions and 27 deletions

View File

@ -1,16 +1,11 @@
package com.kaixed.kchat.data
import com.kaixed.kchat.data.local.box.ObjectBox.getBox
import com.kaixed.kchat.data.local.box.ObjectBox.getBoxStore
import com.kaixed.kchat.data.local.entity.Contact
import com.kaixed.kchat.data.local.entity.Contact_
import com.kaixed.kchat.data.local.entity.Conversation
import com.kaixed.kchat.data.local.entity.Conversation_
import com.kaixed.kchat.data.local.entity.Messages
import com.kaixed.kchat.data.local.entity.Messages_
import com.kaixed.kchat.data.local.entity.UserInfo
import io.objectbox.Box
import io.objectbox.kotlin.boxFor
import io.objectbox.query.QueryBuilder
/**
@ -19,13 +14,13 @@ import io.objectbox.query.QueryBuilder
*/
object LocalDatabase {
private val contactBox: Box<Contact> by lazy { getBoxStore().boxFor() }
private val contactBox = DataBase.contactBox
private val messagesBox: Box<Messages> by lazy { getBoxStore().boxFor() }
private val messagesBox = DataBase.messagesBox
private val conversationBox: Box<Conversation> by lazy { getBoxStore().boxFor() }
private val conversationBox = DataBase.conversationBox
private val userInfoBox: Box<UserInfo> by lazy { getBoxStore().boxFor() }
private val userInfoBox = DataBase.userInfoBox
fun saveUserInfo(userInfo: UserInfo) {
userInfoBox.put(userInfo)

View File

@ -0,0 +1,11 @@
package com.kaixed.kchat.data.model.request
/**
* @Author: kaixed
* @Date: 2024/12/15 21:27
*/
data class UpdatePasswordRequest(
val username: String,
val oldPassword: String,
val newPassword: String,
)

View File

@ -3,8 +3,10 @@ package com.kaixed.kchat.data.repository
import com.kaixed.kchat.data.local.box.ObjectBox.getBoxStore
import com.kaixed.kchat.data.local.entity.UserInfo
import com.kaixed.kchat.data.local.entity.UserInfo_
import com.kaixed.kchat.data.model.request.UpdatePasswordRequest
import com.kaixed.kchat.data.model.request.UserRequest
import com.kaixed.kchat.data.model.search.SearchUser
import com.kaixed.kchat.network.ApiCall.apiCall
import com.kaixed.kchat.network.RetrofitClient
import com.kaixed.kchat.utils.Constants.MMKV_USER_SESSION
import com.kaixed.kchat.utils.Constants.NICKNAME_KEY
@ -70,6 +72,14 @@ class UserProfileRepository {
}
}
// 更新密码
suspend fun updatePassword(updatePasswordRequest: UpdatePasswordRequest): Result<String?> {
return apiCall(
apiCall = { userApiService.updatePassword(updatePasswordRequest) },
errorMessage = "登录失败"
)
}
private fun updateNickname(newNickname: String) {
val userInfoBox = getBoxStore().boxFor(UserInfo::class.java)
val user = userInfoBox

View File

@ -2,6 +2,7 @@ package com.kaixed.kchat.network.service
import com.kaixed.kchat.data.local.entity.UserInfo
import com.kaixed.kchat.data.model.request.RegisterRequest
import com.kaixed.kchat.data.model.request.UpdatePasswordRequest
import com.kaixed.kchat.data.model.request.UserRequest
import com.kaixed.kchat.data.model.response.register.Register
import com.kaixed.kchat.data.model.response.search.User
@ -70,4 +71,10 @@ interface UserApiService {
@Part("username") username: String,
@Part file: MultipartBody.Part
): ApiResponse<String>
// 更改昵称接口
@POST("users/password")
suspend fun updatePassword(
@Body updatePasswordRequest: UpdatePasswordRequest
): ApiResponse<String>
}

View File

@ -1,8 +1,9 @@
package com.kaixed.kchat.ui.activity.setting
import android.content.Intent
import android.os.Bundle
import androidx.activity.enableEdgeToEdge
import com.kaixed.kchat.R
import com.kaixed.kchat.data.DataBase
import com.kaixed.kchat.databinding.ActivityAccountSecurityBinding
import com.kaixed.kchat.ui.base.BaseActivity
@ -15,8 +16,24 @@ class AccountSecurityActivity : BaseActivity<ActivityAccountSecurityBinding>() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setListener()
}
private fun setListener() {
binding.ciUpdatePassword.setOnClickListener {
startActivity(
Intent(this, UpdatePasswordActivity::class.java)
)
}
}
override fun initData() {
val userInfo = DataBase.userInfoBox.query().build().findFirst()
userInfo?.let {
binding.ciAccount.setItemDesc(userInfo.username)
val telephone = userInfo.telephone.take(3) + "******" + userInfo.telephone.takeLast(2)
binding.ciTelephone.setItemDesc(telephone)
}
}
}

View File

@ -1,25 +1,102 @@
package com.kaixed.kchat.ui.activity.setting
import android.os.Bundle
import android.text.Editable
import android.text.InputFilter
import android.text.TextWatcher
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import com.kaixed.kchat.R
import androidx.activity.viewModels
import com.kaixed.kchat.data.model.request.UpdatePasswordRequest
import com.kaixed.kchat.databinding.ActivityUpdatePasswordBinding
import com.kaixed.kchat.ui.base.BaseActivity
import com.kaixed.kchat.ui.widget.LoadingDialogFragment
import com.kaixed.kchat.utils.ConstantsUtil
import com.kaixed.kchat.viewmodel.UserViewModel
class UpdatePasswordActivity : BaseActivity<ActivityUpdatePasswordBinding>() {
private val userViewModel: UserViewModel by viewModels()
private val loadingDialog by lazy { LoadingDialogFragment.newInstance("更改密码中...") }
override fun inflateBinding(): ActivityUpdatePasswordBinding {
return ActivityUpdatePasswordBinding.inflate(layoutInflater)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setListener()
observeLiveData()
}
private fun observeLiveData() {
userViewModel.updatePasswordResult.observe(this) { result ->
result.onSuccess {
toast("修改成功")
finish()
}
result.onFailure {
toast(it.message.toString())
}
loadingDialog.dismissLoading()
}
}
private fun setListener() {
binding.titleBar.setOnBtnClickListener {
val oldPassword = binding.cetOldPassword.text.toString()
val newPassword = binding.cetNewPassword.text.toString()
val confirmPassword = binding.cetConfirmPassword.text.toString()
if (confirmPassword != newPassword) {
toast("两次密码不一致,请重新输入")
return@setOnBtnClickListener
} else {
loadingDialog.showLoading(supportFragmentManager)
val updatePassword = UpdatePasswordRequest(
ConstantsUtil.getUsername(),
oldPassword,
newPassword
)
userViewModel.updatePassword(updatePassword)
}
}
binding.cetOldPassword.addTextChangedListener(textWatch)
binding.cetNewPassword.addTextChangedListener(textWatch)
binding.cetConfirmPassword.addTextChangedListener(textWatch)
}
private fun addEdittextFilter() {
val noSpaceFilter = InputFilter { source, _, _, _, _, _ ->
if (source.contains(" ")) {
return@InputFilter ""
}
null
}
binding.cetOldPassword.filters = arrayOf(noSpaceFilter)
binding.cetNewPassword.filters = arrayOf(noSpaceFilter)
binding.cetConfirmPassword.filters = arrayOf(noSpaceFilter)
}
override fun initData() {
binding.tvKid.text = ConstantsUtil.getUsername()
addEdittextFilter()
}
private val textWatch = object : TextWatcher {
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
}
override fun afterTextChanged(s: Editable?) {
val enable = binding.cetNewPassword.text?.length != 0 &&
binding.cetOldPassword.text?.length != 0 &&
binding.cetConfirmPassword.text?.length != 0
binding.titleBar.setBtnEnable(enable)
}
}
}

View File

@ -1,24 +1,87 @@
package com.kaixed.kchat.ui.widget
import android.content.Context
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.os.Build
import android.util.AttributeSet
import androidx.annotation.RequiresApi
import androidx.appcompat.widget.AppCompatEditText
import androidx.core.content.ContextCompat
import com.kaixed.kchat.R
import com.kaixed.kchat.utils.DensityUtil.dp2px
/**
* @Author: kaixed
* @Date: 2024/12/12 10:09
* 自定义 EditText 控件用于绘制下划线
*/
@RequiresApi(Build.VERSION_CODES.Q)
class CustomEditText @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = androidx.appcompat.R.attr.editTextStyle
) : AppCompatEditText(context, attrs, defStyleAttr) {
defStyle: Int = 0
) : AppCompatEditText(context, attrs, defStyle) {
// 焦点时的下划线颜色
private val focusedLineColor: Int by lazy { ContextCompat.getColor(context, R.color.green) }
// 无焦点时的下划线颜色
private val normalLineColor: Int by lazy { Color.parseColor("#E0E0E0") }
// 下划线高度
private val lineHeight: Float by lazy { dp2px(1).toFloat() }
// 画笔,用于绘制下划线
private var paint: Paint = Paint().apply {
style = Paint.Style.STROKE
strokeWidth = lineHeight
color = normalLineColor // 初始颜色为无焦点时的颜色
}
init {
// 确保背景设置为空以自定义下划线
background = null
// 设置焦点状态的参数,确保可以获得焦点
isFocusable = true
isFocusableInTouchMode = true
textCursorDrawable = ContextCompat.getDrawable(context, R.drawable.cursor)
}
}
/**
* 重写 onDraw() 方法绘制底部下划线
*/
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
// 绘制底部的下划线
val startX = 0f
val startY = height.toFloat() // 在底部绘制下划线距底部5dp
val endX = width.toFloat()
val endY = height.toFloat()
canvas.drawLine(startX, startY, endX, endY, paint)
}
/**
* 焦点变化时更新下划线的颜色
*/
override fun onFocusChanged(
focused: Boolean,
direction: Int,
previouslyFocusedRect: android.graphics.Rect?
) {
super.onFocusChanged(focused, direction, previouslyFocusedRect)
// 根据焦点状态更新下划线颜色
paint.color = if (focused) {
focusedLineColor
} else {
normalLineColor
}
// 强制重绘
invalidate()
}
}

View File

@ -6,6 +6,7 @@ import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.kaixed.kchat.data.local.entity.UserInfo
import com.kaixed.kchat.data.model.request.RegisterRequest
import com.kaixed.kchat.data.model.request.UpdatePasswordRequest
import com.kaixed.kchat.data.model.request.UserRequest
import com.kaixed.kchat.data.model.response.register.Register
import com.kaixed.kchat.data.model.response.search.User
@ -27,6 +28,17 @@ class UserViewModel : ViewModel() {
private val _loginResult = MutableLiveData<Result<UserInfo?>>()
val loginResult: LiveData<Result<UserInfo?>> = _loginResult
private val _updatePasswordResult = MutableLiveData<Result<String?>>()
val updatePasswordResult: LiveData<Result<String?>> = _updatePasswordResult
// 修改密码
fun updatePassword(updatePasswordRequest: UpdatePasswordRequest) {
viewModelScope.launch {
val result = userProfileRepo.updatePassword(updatePasswordRequest)
_updatePasswordResult.postValue(result)
}
}
fun loginByUsername(username: String, password: String) {
viewModelScope.launch {
val result = userAuthRepo.loginByUsername(username, password)

View File

@ -16,19 +16,22 @@
app:titleName="账号与安全" />
<com.kaixed.kchat.ui.widget.CustomItem
android:id="@+id/ci_account"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:isBottomDividerVisible="true"
app:itemDesc="kaixed"
app:itemName="微信号" />
app:itemName="kid号" />
<com.kaixed.kchat.ui.widget.CustomItem
android:id="@+id/ci_telephone"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:itemDesc="177******45"
app:itemName="手机号" />
<com.kaixed.kchat.ui.widget.CustomItem
android:id="@+id/ci_update_password"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/margin"

View File

@ -38,12 +38,13 @@
android:layout_marginStart="10dp"
android:src="@drawable/icon_search" />
<com.kaixed.kchat.ui.widget.CustomEditText
<EditText
android:id="@+id/et_search"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginStart="5dp"
android:textCursorDrawable="@drawable/cursor"
android:layout_toEndOf="@id/iv_search"
android:background="@null"
android:hint="搜索"

View File

@ -5,32 +5,169 @@
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#EDEDED"
android:fitsSystemWindows="true"
android:orientation="vertical"
tools:context=".ui.activity.setting.UpdatePasswordActivity">
<com.kaixed.kchat.ui.widget.CustomTitleBar
android:id="@+id/title_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:btnName="完成"
app:titleName="设置密码" />
<View
android:layout_width="match_parent"
android:layout_height="@dimen/divider_height"
android:background="#EDEDED" />
<com.kaixed.kchat.ui.widget.ReBoundScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
android:layout_height="match_parent"
android:paddingHorizontal="15dp">
<TextView
android:id="@+id/tv_tip"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:text="请设置密码。你可以用绑定的账户+密码进行登录,比如使用手机号+密码登录应用,更便捷。"
android:textColor="#A5A5A5"
android:textSize="14sp"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv_kid_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:text="微信号"
android:textColor="#A5A5A5"
android:textSize="16sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_tip" />
<TextView
android:id="@+id/tv_kid"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#A5A5A5"
android:textSize="16sp"
app:layout_constraintBottom_toBottomOf="@id/tv_kid_title"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.1"
app:layout_constraintStart_toEndOf="@id/tv_kid_title"
app:layout_constraintTop_toTopOf="@id/tv_kid_title" />
<View
android:id="@+id/view"
android:layout_width="match_parent"
android:layout_height="@dimen/divider_height"
android:layout_marginTop="10dp"
android:background="#D5D5D5"
app:layout_constraintTop_toBottomOf="@id/tv_kid_title" />
<TextView
android:id="@+id/tv_origin_password"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="15dp"
android:text="原密码"
android:textColor="@color/black"
android:textSize="16sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/view" />
<com.kaixed.kchat.ui.widget.CustomEditText
android:id="@+id/cet_old_password"
android:layout_width="0dp"
android:layout_height="35dp"
android:layout_marginStart="40dp"
android:gravity="center_vertical"
android:hint="请填写原密码"
android:inputType="textPassword"
android:maxLength="16"
android:maxLines="1"
android:paddingHorizontal="10dp"
android:textColorHint="#A5A5A5"
android:textSize="16sp"
app:layout_constraintBottom_toBottomOf="@id/tv_origin_password"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/tv_origin_password"
app:layout_constraintTop_toTopOf="@id/tv_origin_password" />
<TextView
android:id="@+id/tv_new_password"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="新密码"
android:textColor="@color/black"
android:textSize="16sp"
app:layout_constraintBottom_toBottomOf="@id/cet_new_password"
app:layout_constraintEnd_toEndOf="@id/tv_origin_password"
app:layout_constraintStart_toStartOf="@id/tv_origin_password"
app:layout_constraintTop_toTopOf="@id/cet_new_password" />
<com.kaixed.kchat.ui.widget.CustomEditText
android:id="@+id/cet_new_password"
android:layout_width="0dp"
android:layout_height="35dp"
android:layout_marginTop="5dp"
android:gravity="center_vertical"
android:hint="请填写新密码"
android:inputType="textPassword"
android:maxLength="16"
android:maxLines="1"
android:paddingHorizontal="10dp"
android:textColorHint="#A5A5A5"
android:textSize="16sp"
app:layout_constraintEnd_toEndOf="@id/cet_old_password"
app:layout_constraintStart_toStartOf="@id/cet_old_password"
app:layout_constraintTop_toBottomOf="@id/cet_old_password" />
<TextView
android:id="@+id/tv_confirm_password"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="确认密码"
android:textColor="@color/black"
android:textSize="16sp"
app:layout_constraintBottom_toBottomOf="@id/cet_confirm_password"
app:layout_constraintStart_toStartOf="@id/tv_origin_password"
app:layout_constraintTop_toTopOf="@id/cet_confirm_password" />
<com.kaixed.kchat.ui.widget.CustomEditText
android:id="@+id/cet_confirm_password"
android:layout_width="0dp"
android:layout_height="35dp"
android:layout_marginTop="5dp"
android:gravity="center_vertical"
android:hint="再次填写确认"
android:inputType="textPassword"
android:maxLength="16"
android:maxLines="1"
android:paddingHorizontal="10dp"
android:textColorHint="#A5A5A5"
android:textSize="16sp"
app:layout_constraintEnd_toEndOf="@id/cet_old_password"
app:layout_constraintStart_toStartOf="@id/cet_old_password"
app:layout_constraintTop_toBottomOf="@id/cet_new_password" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="14sp"
android:text="请设置您的账户密码"/>
android:layout_marginTop="10dp"
android:text="密码必须是8-16位的英文字母、数字、字符组合不能是纯数字"
android:textColor="@color/black"
android:textSize="13sp"
app:layout_constraintTop_toBottomOf="@id/cet_confirm_password" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</com.kaixed.kchat.ui.widget.ReBoundScrollView>