列表,个人中心

This commit is contained in:
fengjignqi
2026-09-22 14:57:04 +08:00
parent 8de4af3370
commit 851a06db1a
18 changed files with 698 additions and 13 deletions

View File

@@ -80,4 +80,6 @@ dependencies {
implementation "androidx.camera:camera-view:1.0.0-alpha25"
//圆形视图库
implementation 'com.makeramen:roundedimageview:2.3.0'
//完整版引入
implementation 'io.github.carguo:gsyvideoplayer:13.2.1'
}

View File

@@ -12,6 +12,8 @@ object AppConfig {
const val SEND_CODE_SCENE_LOGIN = "login"
//验证码场景 --重置密码
const val SEND_CODE_SCENE_RESET = "resetPwd"
//验证码场景 --更换手机号
const val SEND_CODE_SCENE_REBIND = "rebind"
@Volatile
var userToken: String = ""

View File

@@ -276,7 +276,17 @@ abstract class BaseActivity<VB : ViewBinding, P : IPresenter<*>> :
}
}
dialog.setCanceledOnTouchOutside(touchOutsideCancel)
dialog.setOnShowListener { dialog.window?.setBackgroundDrawable(ColorDrawable(android.graphics.Color.TRANSPARENT)) }
dialog.setOnShowListener {
dialog.window?.apply {
// 直接设置窗口宽度,确保屏幕左右各保留 50dp,避免 AlertDialog 默认宽度影响根布局 margin。
setBackgroundDrawable(ColorDrawable(android.graphics.Color.TRANSPARENT))
setLayout(
(resources.displayMetrics.widthPixels -
2 * (50 * resources.displayMetrics.density).toInt()),
WindowManager.LayoutParams.WRAP_CONTENT
)
}
}
dialog.show()
}
@@ -322,7 +332,17 @@ abstract class BaseActivity<VB : ViewBinding, P : IPresenter<*>> :
}
}
dialog.setCanceledOnTouchOutside(touchOutsideCancel)
dialog.setOnShowListener { dialog.window?.setBackgroundDrawable(ColorDrawable(android.graphics.Color.TRANSPARENT)) }
dialog.setOnShowListener {
dialog.window?.apply {
// 固定窗口宽度,确保输入弹窗左右各保留 50dp。
setBackgroundDrawable(ColorDrawable(android.graphics.Color.TRANSPARENT))
setLayout(
(resources.displayMetrics.widthPixels -
2 * (50 * resources.displayMetrics.density).toInt()),
WindowManager.LayoutParams.WRAP_CONTENT
)
}
}
dialog.show()
}
@@ -370,7 +390,17 @@ abstract class BaseActivity<VB : ViewBinding, P : IPresenter<*>> :
val dialog = AlertDialog.Builder(this).setView(view).create()
view.findViewById<TextView>(R.id.permissionCancel).setOnClickListener { dialog.dismiss(); onCancel() }
view.findViewById<TextView>(R.id.permissionAllow).setOnClickListener { dialog.dismiss(); onAllow() }
dialog.setOnShowListener { dialog.window?.setBackgroundDrawable(ColorDrawable(android.graphics.Color.TRANSPARENT)) }
dialog.setOnShowListener {
dialog.window?.apply {
// 动态权限确认弹窗固定左右各 50dp,避免使用 AlertDialog 默认宽度。
setBackgroundDrawable(ColorDrawable(android.graphics.Color.TRANSPARENT))
setLayout(
(resources.displayMetrics.widthPixels -
2 * (50 * resources.displayMetrics.density).toInt()),
WindowManager.LayoutParams.WRAP_CONTENT
)
}
}
dialog.show()
}

View File

@@ -276,7 +276,17 @@ abstract class BaseFragment<VB : ViewBinding, P : IPresenter<*>> : Fragment(), I
}
}
dialog.setCanceledOnTouchOutside(touchOutsideCancel)
dialog.setOnShowListener { dialog.window?.setBackgroundDrawable(ColorDrawable(android.graphics.Color.TRANSPARENT)) }
dialog.setOnShowListener {
dialog.window?.apply {
// 直接设置窗口宽度,确保屏幕左右各保留 50dp,避免 AlertDialog 默认宽度影响根布局 margin。
setBackgroundDrawable(ColorDrawable(android.graphics.Color.TRANSPARENT))
setLayout(
(resources.displayMetrics.widthPixels -
2 * (50 * resources.displayMetrics.density).toInt()),
WindowManager.LayoutParams.WRAP_CONTENT
)
}
}
dialog.show()
}
@@ -322,7 +332,17 @@ abstract class BaseFragment<VB : ViewBinding, P : IPresenter<*>> : Fragment(), I
}
}
dialog.setCanceledOnTouchOutside(touchOutsideCancel)
dialog.setOnShowListener { dialog.window?.setBackgroundDrawable(ColorDrawable(android.graphics.Color.TRANSPARENT)) }
dialog.setOnShowListener {
dialog.window?.apply {
// 固定窗口宽度,确保输入弹窗左右各保留 50dp。
setBackgroundDrawable(ColorDrawable(android.graphics.Color.TRANSPARENT))
setLayout(
(resources.displayMetrics.widthPixels -
2 * (50 * resources.displayMetrics.density).toInt()),
WindowManager.LayoutParams.WRAP_CONTENT
)
}
}
dialog.show()
}
@@ -368,7 +388,17 @@ abstract class BaseFragment<VB : ViewBinding, P : IPresenter<*>> : Fragment(), I
val dialog = AlertDialog.Builder(requireContext()).setView(view).create()
view.findViewById<TextView>(R.id.permissionCancel).setOnClickListener { dialog.dismiss(); onCancel() }
view.findViewById<TextView>(R.id.permissionAllow).setOnClickListener { dialog.dismiss(); onAllow() }
dialog.setOnShowListener { dialog.window?.setBackgroundDrawable(ColorDrawable(android.graphics.Color.TRANSPARENT)) }
dialog.setOnShowListener {
dialog.window?.apply {
// 动态权限确认弹窗固定左右各 50dp,避免使用 AlertDialog 默认宽度。
setBackgroundDrawable(ColorDrawable(android.graphics.Color.TRANSPARENT))
setLayout(
(resources.displayMetrics.widthPixels -
2 * (50 * resources.displayMetrics.density).toInt()),
WindowManager.LayoutParams.WRAP_CONTENT
)
}
}
dialog.show()
}
/** 关闭并释放顶部权限提示弹窗。 */

View File

@@ -4,6 +4,8 @@ import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import java.io.File
import java.util.Locale
import com.juhabi.birds.base.BaseFragment
import com.juhabi.birds.mine.model.MineUserInfo
import com.juhabi.birds.R
@@ -14,6 +16,8 @@ import com.juhabi.birds.mine.mvp.MineContract
import com.juhabi.birds.mine.mvp.MineImpl
import com.juhabi.birds.mine.mvp.MinePresenter
import com.juhabi.birds.util.manager.UserInfoManager
import com.juhabi.birds.AppConfig
import com.juhabi.birds.login.LoginActivity
/**
* 个人中心
@@ -31,11 +35,13 @@ class MineFragment : BaseFragment<MineCenterLayoutBinding, MinePresenter>(),
override fun onResume() {
super.onResume()
displayCacheSize()
/** 页面恢复显示时重新请求当前用户的个人信息。 */
presenter?.getUserInfo()
}
override fun initView(savedInstanceState: Bundle?) {
displayCacheSize()
listOf(
binding.linearXgmm,
binding.linearGhsj,
@@ -62,6 +68,23 @@ class MineFragment : BaseFragment<MineCenterLayoutBinding, MinePresenter>(),
goTo(UpdateUserAccount::class.java, null)
}
R.id.linear_qchc -> {
showDialogtext(
"提示",
"清除当前应用缓存?",
"确定",
"取消",
object : OnDialogClick {
override fun onCancelClick() {
}
override fun onConfirmClick() {
clearCache()
}
}
)
}
//退出登录
R.id.tv_logout -> {
@@ -75,7 +98,8 @@ class MineFragment : BaseFragment<MineCenterLayoutBinding, MinePresenter>(),
}
override fun onConfirmClick() {
// 退出登录接口后续接入
// 用户确认后调用服务端退出登录接口。
presenter?.userLogout()
}
}
)
@@ -108,4 +132,75 @@ class MineFragment : BaseFragment<MineCenterLayoutBinding, MinePresenter>(),
override fun showError(message: String) {
showMessage(message)
}
override fun onLogoutSuccess(message: String) {
val context = context ?: return
// 服务端退出成功后清除本地账号信息,避免应用重启后恢复旧登录状态。
UserInfoManager.clearUser(context)
AppConfig.USER_LOGIN = false
showMessage(message)
// 清空之前的页面栈,防止用户返回到已登录页面。
goToClearTask(LoginActivity::class.java, null)
}
/** 查询应用缓存大小,并将结果显示在个人中心页面。 */
private fun displayCacheSize() {
val context = context ?: return
Thread {
val cacheSize = getFolderSize(context.cacheDir)
val sizeText = formatCacheSize(cacheSize)
activity?.runOnUiThread {
if (isAdded && view != null) {
binding.tvTotalCache.text = sizeText
}
}
}.start()
}
/** 清理应用缓存,删除完成后重新创建缓存目录并刷新显示。 */
private fun clearCache() {
val context = context ?: return
Thread {
deleteDir(context.cacheDir)
context.cacheDir.mkdirs()
activity?.runOnUiThread {
if (isAdded && view != null) {
binding.tvTotalCache.text = formatCacheSize(0L)
showMessage("缓存清理成功")
}
}
}.start()
}
/** 递归计算目录下所有文件的字节数。 */
private fun getFolderSize(directory: File?): Long {
if (directory == null || !directory.exists()) {
return 0L
}
if (directory.isFile) {
return directory.length()
}
return directory.listFiles()?.sumOf { file -> getFolderSize(file) } ?: 0L
}
/** 递归删除文件或目录。 */
private fun deleteDir(file: File?): Boolean {
if (file == null || !file.exists()) {
return true
}
if (file.isDirectory) {
file.listFiles()?.forEach { child -> deleteDir(child) }
}
return file.delete()
}
/** 大于等于 1 MB 使用 MB,否则使用 KB,保持与旧 Java 页面一致。 */
private fun formatCacheSize(bytes: Long): String {
return if (bytes >= 1024L * 1024L) {
String.format(Locale.US, "%.2f MB", bytes / (1024.0 * 1024.0))
} else {
String.format(Locale.US, "%d KB", bytes / 1024L)
}
}
}

View File

@@ -1,6 +1,7 @@
package com.juhabi.birds.mine
import android.os.Bundle
import android.os.CountDownTimer
import android.view.LayoutInflater
import android.view.View
import com.gyf.immersionbar.ImmersionBar
@@ -14,12 +15,15 @@ import com.juhabi.birds.mine.mvp.MineContract
import com.juhabi.birds.mine.mvp.MineImpl
import com.juhabi.birds.mine.mvp.MinePresenter
import com.juhabi.birds.util.manager.UserInfoManager
import com.juhabi.birds.util.ToastUtil
/**
* 修改手机号
*/
class UpdateUserAccount : BaseActivity<UpdateUserPhoneLayoutBinding, MinePresenter>(),
MineContract.MineView, View.OnClickListener {
private var codeCountDownTimer: CountDownTimer? = null
private var newPhoneCodeCountDownTimer: CountDownTimer? = null
override fun createBinding(inflater: LayoutInflater): UpdateUserPhoneLayoutBinding {
return UpdateUserPhoneLayoutBinding.inflate(inflater)
}
@@ -59,22 +63,132 @@ class UpdateUserAccount : BaseActivity<UpdateUserPhoneLayoutBinding, MinePresen
}
R.id.tv_confirm_getcode ->{
// 新接口根据登录态识别当前手机号,不需要传手机号或验证码场景。
presenter?.getCurrentPhoneCode()
}
R.id.tv_confirmAccount ->{
// 只有填写旧手机号收到的验证码后,才能进入新手机号填写页面。
val confirmCode = binding.EtConfirmCode.text.toString().trim()
if (confirmCode.isBlank()) {
ToastUtil.showShort(mContext, "验证码不能为空")
return
}
// 服务端校验通过后,再进入新手机号填写页面。
presenter?.verifyOldPhone(confirmCode)
}
R.id.tv_new_phone_getcode ->{
// 新手机号不能为空,校验通过后使用 rebind 场景发送验证码。
val newPhone = binding.etNewPhone.text.toString().trim()
if (newPhone.isBlank()) {
ToastUtil.showShort(mContext, "新手机号不能为空")
return
}
presenter?.sendNewPhoneCode(newPhone)
}
R.id.tv_submit_new_account ->{
//绑定新的手机号码
val newPhone = binding.etNewPhone.text.toString().trim()
val code = binding.etNewPhoneCode.text.toString().trim()
if (newPhone.isBlank()) {
ToastUtil.showShort(mContext, "新手机号不能为空")
return
}
if (code.isBlank()) {
ToastUtil.showShort(mContext, "验证码不能为空")
return
}
// 手机号和验证码校验通过后,提交新手机号换绑请求。
presenter?.updateBindNewPhone(newPhone, code)
}
}
}
override fun showError(message: String) {
hideLoading()
ToastUtil.showShort(mContext, message)
}
override fun sendCodeSuccess(message: String) {
hideLoading()
ToastUtil.showShort(mContext, message)
codeCountDownTimer?.cancel()
binding.tvConfirmGetcode.apply {
isEnabled = false
isClickable = false
setBackgroundResource(R.drawable.shape_register_code_disabled_bg)
text = getString(R.string.register_code_countdown, CODE_COUNTDOWN_SECONDS)
}
codeCountDownTimer = object : CountDownTimer(CODE_COUNTDOWN_MILLIS, 1_000L) {
override fun onTick(millisUntilFinished: Long) {
val secondsRemaining = (millisUntilFinished + 999L) / 1_000L
binding.tvConfirmGetcode.text = getString(
R.string.register_code_countdown,
secondsRemaining
)
}
override fun onFinish() {
codeCountDownTimer = null
binding.tvConfirmGetcode.apply {
isEnabled = true
isClickable = true
setBackgroundResource(R.drawable.shape_register_code_bg)
setText(R.string.register_get_code)
}
}
}.start()
}
override fun onVerifyOldPhoneSuccess(message: String) {
hideLoading()
ToastUtil.showShort(mContext, message)
// 当前手机号验证成功后,隐藏验证区域并展示新手机号输入区域。
binding.linearConfirmUserAccount.visibility = View.GONE
binding.linearNewUserAccount.visibility = View.VISIBLE
}
override fun newPhoneCodeSuccess(message: String) {
hideLoading()
ToastUtil.showShort(mContext, message)
newPhoneCodeCountDownTimer?.cancel()
binding.tvNewPhoneGetcode.apply {
isEnabled = false
isClickable = false
setBackgroundResource(R.drawable.shape_register_code_disabled_bg)
text = getString(R.string.register_code_countdown, CODE_COUNTDOWN_SECONDS)
}
newPhoneCodeCountDownTimer = object : CountDownTimer(CODE_COUNTDOWN_MILLIS, 1_000L) {
override fun onTick(millisUntilFinished: Long) {
val secondsRemaining = (millisUntilFinished + 999L) / 1_000L
binding.tvNewPhoneGetcode.text = getString(
R.string.register_code_countdown,
secondsRemaining
)
}
override fun onFinish() {
newPhoneCodeCountDownTimer = null
binding.tvNewPhoneGetcode.apply {
isEnabled = true
isClickable = true
setBackgroundResource(R.drawable.shape_register_code_bg)
setText(R.string.register_get_code)
}
}
}.start()
}
override fun onUpdateBindNewPhoneSuccess(message: String) {
hideLoading()
ToastUtil.showShort(mContext, message)
// 返回个人中心后,MineFragment 会在 onResume 中重新获取最新用户资料。
finish()
}
override fun getUserInfoSuccess(userInfo: MineUserInfo) {
@@ -83,5 +197,18 @@ class UpdateUserAccount : BaseActivity<UpdateUserPhoneLayoutBinding, MinePresen
override fun onVersionChecked(versionInfo: AppVersionInfo) {
}
override fun onDestroy() {
codeCountDownTimer?.cancel()
codeCountDownTimer = null
newPhoneCodeCountDownTimer?.cancel()
newPhoneCodeCountDownTimer = null
super.onDestroy()
}
}
private companion object {
const val CODE_COUNTDOWN_SECONDS = 60L
const val CODE_COUNTDOWN_MILLIS = CODE_COUNTDOWN_SECONDS * 1_000L
}
}

View File

@@ -3,6 +3,9 @@ package com.juhabi.birds.mine.mvp
import com.juhabi.birds.base.IView
import com.juhabi.birds.main.model.AppVersionInfo
import com.juhabi.birds.mine.model.MineUserInfo
import com.juhabi.birds.network.BaseBean
import com.juhabi.birds.login.model.SendCodeEntity
import org.json.JSONObject
interface MineContract {
interface Callback<T> {
@@ -17,6 +20,15 @@ interface MineContract {
callback: Callback<AppVersionInfo>
)
fun modifyPassword(oldPassword: String, newPassword: String, callback: Callback<String>)
fun getCurrentPhoneCode(callback: Callback<BaseBean<Any>>)
fun sendPhoneCode(request: JSONObject, callback: Callback<BaseBean<SendCodeEntity>>)
fun verifyOldPhone(oldCode: String, callback: Callback<BaseBean<Any>>)
fun updateBindNewPhone(
newPhoneNumber: String,
code: String,
callback: Callback<BaseBean<Any>>
)
fun userLogout(callback: Callback<BaseBean<Any>>)
fun cancel()
}
@@ -25,5 +37,15 @@ interface MineContract {
fun onVersionChecked(versionInfo: AppVersionInfo)
/** 修改密码成功回调,非修改密码页面无需处理。 */
fun onModifyPasswordSuccess(message: String) {}
/** 发送验证码成功回调。 */
fun sendCodeSuccess(message: String) {}
/** 新手机号验证码发送成功回调。 */
fun newPhoneCodeSuccess(message: String) {}
/** 当前手机号验证成功回调。 */
fun onVerifyOldPhoneSuccess(message: String) {}
/** 新手机号绑定成功回调。 */
fun onUpdateBindNewPhoneSuccess(message: String) {}
/** 退出登录成功回调。 */
fun onLogoutSuccess(message: String) {}
}
}

View File

@@ -11,12 +11,177 @@ import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
import org.json.JSONObject
import com.juhabi.birds.login.model.SendCodeEntity
class MineImpl : MineContract.DataModel {
private val mainHandler = Handler(Looper.getMainLooper())
private var userInfoCall: Call<BaseBean<MineUserInfo>>? = null
private var versionCall: Call<BaseBean<AppVersionInfo>>? = null
private var modifyPasswordCall: Call<BaseBean<Any>>? = null
private var sendCodeCall: Call<BaseBean<Any>>? = null
private var verifyOldPhoneCall: Call<BaseBean<Any>>? = null
private var newPhoneCodeCall: Call<BaseBean<SendCodeEntity>>? = null
private var updateBindNewPhoneCall: Call<BaseBean<Any>>? = null
private var logoutCall: Call<BaseBean<Any>>? = null
override fun getCurrentPhoneCode(
callback: MineContract.Callback<BaseBean<Any>>
) {
sendCodeCall?.cancel()
sendCodeCall = ApiClient.apiService
.getCurrentPhoneCode(NetworkManager.getToken())
.also { call ->
call.enqueue(object : Callback<BaseBean<Any>> {
override fun onResponse(
call: Call<BaseBean<Any>>,
response: Response<BaseBean<Any>>
) {
mainHandler.post {
response.body()?.let(callback::success)
?: callback.fail("验证码发送失败")
}
}
override fun onFailure(
call: Call<BaseBean<Any>>,
error: Throwable
) {
if (!call.isCanceled) {
mainHandler.post { callback.fail(error.message ?: "网络请求失败") }
}
}
})
}
}
override fun sendPhoneCode(
request: JSONObject,
callback: MineContract.Callback<BaseBean<SendCodeEntity>>
) {
newPhoneCodeCall?.cancel()
newPhoneCodeCall = ApiClient.apiService
.sendPhoneCode(NetworkManager.getToken(), NetworkManager.toRequestBody(request))
.also { call ->
call.enqueue(object : Callback<BaseBean<SendCodeEntity>> {
override fun onResponse(
call: Call<BaseBean<SendCodeEntity>>,
response: Response<BaseBean<SendCodeEntity>>
) {
mainHandler.post {
response.body()?.let(callback::success)
?: callback.fail("验证码发送失败")
}
}
override fun onFailure(
call: Call<BaseBean<SendCodeEntity>>,
error: Throwable
) {
if (!call.isCanceled) {
mainHandler.post { callback.fail(error.message ?: "网络请求失败") }
}
}
})
}
}
override fun verifyOldPhone(
oldCode: String,
callback: MineContract.Callback<BaseBean<Any>>
) {
verifyOldPhoneCall?.cancel()
val requestBody = JSONObject().apply {
put("oldCode", oldCode.trim())
}
verifyOldPhoneCall = ApiClient.apiService
.verifyOldPhone(NetworkManager.getToken(), NetworkManager.toRequestBody(requestBody))
.also { call ->
call.enqueue(object : Callback<BaseBean<Any>> {
override fun onResponse(
call: Call<BaseBean<Any>>,
response: Response<BaseBean<Any>>
) {
mainHandler.post {
response.body()?.let(callback::success)
?: callback.fail("当前手机号验证失败")
}
}
override fun onFailure(call: Call<BaseBean<Any>>, error: Throwable) {
if (!call.isCanceled) {
mainHandler.post {
callback.fail(error.message ?: "网络请求失败")
}
}
}
})
}
}
override fun updateBindNewPhone(
newPhoneNumber: String,
code: String,
callback: MineContract.Callback<BaseBean<Any>>
) {
updateBindNewPhoneCall?.cancel()
val requestBody = JSONObject().apply {
put("newPhoneNumber", newPhoneNumber.trim())
put("code", code.trim())
}
updateBindNewPhoneCall = ApiClient.apiService
.updateBindNewPhone(
NetworkManager.getToken(),
NetworkManager.toRequestBody(requestBody)
)
.also { call ->
call.enqueue(object : Callback<BaseBean<Any>> {
override fun onResponse(
call: Call<BaseBean<Any>>,
response: Response<BaseBean<Any>>
) {
mainHandler.post {
response.body()?.let(callback::success)
?: callback.fail("手机号更换失败")
}
}
override fun onFailure(call: Call<BaseBean<Any>>, error: Throwable) {
if (!call.isCanceled) {
mainHandler.post {
callback.fail(error.message ?: "网络请求失败")
}
}
}
})
}
}
override fun userLogout(callback: MineContract.Callback<BaseBean<Any>>) {
logoutCall?.cancel()
logoutCall = ApiClient.apiService
.userLogout(NetworkManager.getToken())
.also { call ->
call.enqueue(object : Callback<BaseBean<Any>> {
override fun onResponse(
call: Call<BaseBean<Any>>,
response: Response<BaseBean<Any>>
) {
mainHandler.post {
response.body()?.let(callback::success)
?: callback.fail("退出登录失败")
}
}
override fun onFailure(call: Call<BaseBean<Any>>, error: Throwable) {
if (!call.isCanceled) {
mainHandler.post {
callback.fail(error.message ?: "网络请求失败")
}
}
}
})
}
}
override fun getUserInfo(
params: Map<String, String>,
@@ -145,6 +310,16 @@ class MineImpl : MineContract.DataModel {
versionCall = null
modifyPasswordCall?.cancel()
modifyPasswordCall = null
sendCodeCall?.cancel()
sendCodeCall = null
verifyOldPhoneCall?.cancel()
verifyOldPhoneCall = null
newPhoneCodeCall?.cancel()
newPhoneCodeCall = null
updateBindNewPhoneCall?.cancel()
updateBindNewPhoneCall = null
logoutCall?.cancel()
logoutCall = null
mainHandler.removeCallbacksAndMessages(null)
}
}

View File

@@ -3,9 +3,149 @@ package com.juhabi.birds.mine.mvp
import com.juhabi.birds.base.BasePresenter
import com.juhabi.birds.main.model.AppVersionInfo
import com.juhabi.birds.mine.model.MineUserInfo
import com.juhabi.birds.network.BaseBean
import com.juhabi.birds.login.model.SendCodeEntity
import org.json.JSONObject
class MinePresenter(private val mineImpl: MineImpl) : BasePresenter<MineContract.MineView>() {
/** 通过登录态向当前绑定的手机号发送验证码,无需额外请求参数。 */
fun getCurrentPhoneCode() {
val currentView = view ?: return
currentView.showLoading()
mineImpl.getCurrentPhoneCode(object : MineContract.Callback<BaseBean<Any>> {
override fun success(data: BaseBean<Any>) {
view?.apply {
hideLoading()
if (data.code == 0 || data.code == 200) {
sendCodeSuccess(data.message.ifBlank { "验证码已发送" })
} else {
showError(data.message.ifBlank { "验证码发送失败" })
}
}
}
override fun fail(message: String) {
view?.apply {
hideLoading()
showError(message)
}
}
})
}
/** 向新手机号发送 rebind 场景验证码。 */
fun sendNewPhoneCode(phoneNumber: String) {
val currentView = view ?: return
currentView.showLoading()
val request = JSONObject().apply {
put("phoneNumber", phoneNumber.trim())
put("scene", com.juhabi.birds.AppConfig.SEND_CODE_SCENE_REBIND)
}
mineImpl.sendPhoneCode(request, object : MineContract.Callback<BaseBean<SendCodeEntity>> {
override fun success(data: BaseBean<SendCodeEntity>) {
view?.apply {
hideLoading()
if (data.code == 0 || data.code == 200) {
newPhoneCodeSuccess(data.message.ifBlank { "验证码已发送" })
} else {
showError(data.message.ifBlank { "验证码发送失败" })
}
}
}
override fun fail(message: String) {
view?.apply {
hideLoading()
showError(message)
}
}
})
}
/** 校验当前手机号收到的验证码。 */
fun verifyOldPhone(oldCode: String) {
val currentView = view ?: return
currentView.showLoading()
mineImpl.verifyOldPhone(oldCode, object : MineContract.Callback<BaseBean<Any>> {
override fun success(data: BaseBean<Any>) {
view?.apply {
hideLoading()
if (data.code == 0 || data.code == 200) {
onVerifyOldPhoneSuccess(
data.message.ifBlank { "当前手机号验证成功" }
)
} else {
showError(data.message.ifBlank { "当前手机号验证失败" })
}
}
}
override fun fail(message: String) {
view?.apply {
hideLoading()
showError(message)
}
}
})
}
/** 提交新手机号和验证码,完成手机号换绑。 */
fun updateBindNewPhone(newPhoneNumber: String, code: String) {
val currentView = view ?: return
currentView.showLoading()
mineImpl.updateBindNewPhone(
newPhoneNumber,
code,
object : MineContract.Callback<BaseBean<Any>> {
override fun success(data: BaseBean<Any>) {
view?.apply {
hideLoading()
if (data.code == 0 || data.code == 200) {
onUpdateBindNewPhoneSuccess(
data.message.ifBlank { "手机号更换成功" }
)
} else {
showError(data.message.ifBlank { "手机号更换失败" })
}
}
}
override fun fail(message: String) {
view?.apply {
hideLoading()
showError(message)
}
}
}
)
}
/** 调用服务端退出登录接口,并统一分发成功或失败结果。 */
fun userLogout() {
val currentView = view ?: return
currentView.showLoading()
mineImpl.userLogout(object : MineContract.Callback<BaseBean<Any>> {
override fun success(data: BaseBean<Any>) {
view?.apply {
hideLoading()
if (data.code == 0 || data.code == 200) {
onLogoutSuccess(data.message.ifBlank { "退出登录成功" })
} else {
showError(data.message.ifBlank { "退出登录失败" })
}
}
}
override fun fail(message: String) {
view?.apply {
hideLoading()
showError(message)
}
}
})
}
fun getUserInfo() {
val currentView = view ?: return
currentView.showLoading()

View File

@@ -23,6 +23,14 @@ interface ApiService {
//发送手机验证码
/**
* 入参
* {
* "phoneNumber": "15550099523",
* "scene": "场景值"
* }
*
*/
@POST("app/auth/sms/code")
fun sendPhoneCode(@HeaderMap headers: Map<String, String>, @Body requestBody: RequestBody): Call<BaseBean<SendCodeEntity>>
@@ -194,6 +202,48 @@ interface ApiService {
fun modifyPassword(@HeaderMap headers: Map<String, String>, @Body requestBody: RequestBody): Call<BaseBean<Any>>
/**
* 验证原手机号--发送短信
*
* 不需要任何入参,
*/
@POST("app/user/phone/old-code")
fun getCurrentPhoneCode(@HeaderMap headers: Map<String, String>): Call<BaseBean<Any>>
/**
* 验证原手机号--验证手机号
*
* 入参
*{
* "oldCode": "123456"
* }
*
*/
@POST("app/user/phone/verify-old")
fun verifyOldPhone(@HeaderMap headers: Map<String, String>, @Body requestBody: RequestBody): Call<BaseBean<Any>>
/**
* 更换新的绑定手机号码
{
"newPhoneNumber": "string",
"code": "string"
}
*/
@PUT("app/user/phone")
fun updateBindNewPhone(@HeaderMap headers: Map<String, String>, @Body requestBody: RequestBody): Call<BaseBean<Any>>
/**
* 退出登录
*
* 不需要任何入参,
*/
@POST("app/auth/logout")
fun userLogout(@HeaderMap headers: Map<String, String>): Call<BaseBean<Any>>
@GET("app/v1/checkVersion")

View File

@@ -3,7 +3,6 @@
android:id="@+id/contentDialog"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="36dp"
android:background="@drawable/bg_confirm_dialog"
android:orientation="vertical">

View File

@@ -12,7 +12,7 @@
android:layout_width="22dp"
android:layout_height="match_parent"
android:layout_centerVertical="true"
android:src="@mipmap/img_back_black"
android:src="@mipmap/icon_back_white"
android:layout_marginStart="10dp"/>
<TextView
android:id="@+id/tv_title"

View File

@@ -140,13 +140,25 @@
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="9"
android:layout_weight="5"
android:layout_marginStart="18dp"
android:textStyle="bold"
android:textSize="16sp"
android:textColor="@color/white"
android:text="清除缓存"/>
<TextView
android:id="@+id/tv_total_cache"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="2"
android:layout_marginStart="18dp"
android:gravity="end"
android:textSize="12sp"
android:textColor="@color/white"
android:text=""
android:singleLine="true"/>
<ImageView
android:layout_width="0dp"
android:layout_height="24dp"

View File

@@ -3,7 +3,6 @@
android:id="@+id/contentDialog"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="36dp"
android:background="@drawable/bg_confirm_dialog"
android:orientation="vertical">

View File

@@ -23,6 +23,7 @@
android:id="@+id/linear_confirm_user_account"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:orientation="vertical"
android:visibility="visible">
<LinearLayout
@@ -121,6 +122,7 @@
android:id="@+id/linear_new_user_account"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:orientation="vertical"
android:visibility="gone">
<LinearLayout

Binary file not shown.

After

Width:  |  Height:  |  Size: 808 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB