Răsfoiți Sursa

feat: 账号管理

XiaodongLin 1 an în urmă
părinte
comite
2a62b3818b

+ 1 - 0
app/src/main/java/com/adealink/weparty/module/account/data/LoginData.kt

@@ -31,6 +31,7 @@ data class SmsCountryInfo(
     @SerializedName("countryName") var countryName: String,
     @SerializedName("flag") val flag: String,
     @SerializedName("supportSms") val supportSms: Boolean,
+    @SerializedName("supportWhatsapp") val supportWhatsapp: Boolean,
     var localeName: String = ""
 ) : Parcelable {
     fun fill(): SmsCountryInfo {

+ 1 - 1
module/account/src/main/java/com/adealink/weparty/account/countryselect/viewmodel/CountrySelectViewModel.kt

@@ -21,7 +21,7 @@ class CountrySelectViewModel : BaseViewModel() {
             rlt.onSuccess { list ->
                 allCountryList = list.toMutableList()
                 if (filterSupportSms) {
-                    allCountryList = allCountryList.filter { it.supportSms }.toMutableList()
+                    allCountryList = allCountryList.filter { it.supportSms ||it.supportWhatsapp }.toMutableList()
                 }
                 countryListLD.send(allCountryList)
             }

+ 18 - 3
module/account/src/main/java/com/adealink/weparty/account/login/data/LoginData.kt

@@ -3,9 +3,8 @@ package com.adealink.weparty.account.login.data
 import android.os.Parcelable
 import com.adealink.frame.base.AppBaseInfo
 import com.adealink.frame.util.PackageUtil
-import com.adealink.weparty.module.account.AccountLocalService
 import com.adealink.weparty.channel.getChannel
-import com.adealink.weparty.debug.isCNTestEnv
+import com.adealink.weparty.module.account.AccountLocalService
 import com.adealink.weparty.module.profile.data.UserInfo
 import com.adealink.weparty.module.profile.data.contentsTheSame
 import com.google.gson.annotations.GsonNullable
@@ -14,7 +13,6 @@ import com.google.gson.annotations.Must
 import com.google.gson.annotations.SerializedName
 import com.google.gson.internal.bind.ExtReflectiveTypeAdapterFactory
 import kotlinx.parcelize.Parcelize
-import java.util.Locale
 
 /**
  * Created by sunxiaodong on 2021/3/26.
@@ -282,3 +280,20 @@ enum class EmailReason(val reason: Int) {
     GOOGLE_LOGIN(2)
 }
 
+@JsonAdapter(ExtReflectiveTypeAdapterFactory::class)
+data class AccountInfo(
+    @SerializedName("bindEmail") val bindEmail: String, //用户绑定的邮箱
+    @SerializedName("password") val password: String, //密码
+    @SerializedName("passwordWrongCount") val passwordWrongCount: Int, //密码登录输错次数
+    @SerializedName("registMethod") val registMethod: String, //账户注册方式
+    @SerializedName("registPhoneNumber") val registPhoneNumber: String, //账户注册手机号
+    @SerializedName("registerTime") val registerTime: Int, //注册时间
+    @SerializedName("relatedEmail") val relatedEmail: String, //用户关联使用的邮箱
+    @SerializedName("uid") val uid: Int, //用户uid
+)
+
+@JsonAdapter(ExtReflectiveTypeAdapterFactory::class)
+data class BindAccountWithPhoneReq(
+    @SerializedName("phoneNumber") val phoneNumber: String,//手机号;需要填写区号
+    @SerializedName("verifyCode") val verifyCode: String,//验证码
+)

+ 15 - 0
module/account/src/main/java/com/adealink/weparty/account/login/datasource/remote/LoginService.kt

@@ -2,6 +2,8 @@ package com.adealink.weparty.account.login.datasource.remote
 
 import com.adealink.frame.base.Rlt
 import com.adealink.frame.network.data.Res
+import com.adealink.weparty.account.login.data.AccountInfo
+import com.adealink.weparty.account.login.data.BindAccountWithPhoneReq
 import com.adealink.weparty.account.login.data.BindMailReq
 import com.adealink.weparty.account.login.data.EmailCodeLoginReq
 import com.adealink.weparty.account.login.data.EmailCodeResult
@@ -147,4 +149,17 @@ interface LoginService {
      */
     @POST("account/sms")
     suspend fun getSmsCountries(@Body req: GetSmsCountryReq): Rlt<Res<List<SmsCountryInfo>>>
+
+    /**
+     * 获取账号注册方式--支持靓号查询--供客户端调用
+     */
+    @GET("account/fetchAccountInfo")
+    suspend fun fetchAccountInfo(): Rlt<Res<AccountInfo>>
+
+    /**
+     * 绑定账户使用手机号登录
+     */
+    @POST("account/bindAccountWithPhone")
+    suspend fun bindAccountWithPhone(@Body req: BindAccountWithPhoneReq): Rlt<Res<Any>>
+
 }

+ 3 - 0
module/account/src/main/java/com/adealink/weparty/account/login/manager/ILoginManager.kt

@@ -3,6 +3,7 @@ package com.adealink.weparty.account.login.manager
 import com.adealink.frame.base.Rlt
 import com.adealink.frame.frame.IBaseFrame
 import com.adealink.frame.network.data.Res
+import com.adealink.weparty.account.login.data.AccountInfo
 import com.adealink.weparty.account.login.data.EmailCodeResult
 import com.adealink.weparty.account.login.data.GetVerifyCodeReason
 import com.adealink.weparty.account.login.data.LoginResult
@@ -100,5 +101,7 @@ interface ILoginManager : IBaseFrame<ILoginListener> {
     suspend fun getAllCountries(): Rlt<List<SmsCountryInfo>>
     fun getCountryByCountryCode(countryCode: String): SmsCountryInfo?
     fun getLoginDeviceId(): String
+    suspend fun fetchAccountInfo(): Rlt<AccountInfo>
+    suspend fun bindAccountWithPhone(phone: String, verifyCode: String): Rlt<Res<Any>>
 
 }

+ 19 - 0
module/account/src/main/java/com/adealink/weparty/account/login/manager/LoginManager.kt

@@ -1,6 +1,7 @@
 package com.adealink.weparty.account.login.manager
 
 import android.content.Intent
+import com.adealink.frame.base.CommonDataNullError
 import com.adealink.frame.base.IError
 import com.adealink.frame.base.Rlt
 import com.adealink.frame.coroutine.dispatcher.Dispatcher
@@ -18,6 +19,8 @@ import com.adealink.weparty.App
 import com.adealink.weparty.account.ban.banManager
 import com.adealink.weparty.account.constant.TAG_ACCOUNT_LOGIN
 import com.adealink.weparty.account.login.LoginActivity
+import com.adealink.weparty.account.login.data.AccountInfo
+import com.adealink.weparty.account.login.data.BindAccountWithPhoneReq
 import com.adealink.weparty.account.login.data.BindMailReq
 import com.adealink.weparty.account.login.data.EmailCodeLoginReq
 import com.adealink.weparty.account.login.data.EmailCodeResult
@@ -665,5 +668,21 @@ class LoginManager : BaseFrame<ILoginListener>(), ILoginManager {
         return allSmsCountryList.firstOrNull { it.countryCode == countryCode }
     }
 
+
+    override suspend fun fetchAccountInfo(): Rlt<AccountInfo> {
+        val rlt = loginService.fetchAccountInfo()
+        if (rlt is Rlt.Success) {
+            val res = rlt.data.data
+            if (res != null) {
+                return Rlt.Success(res)
+            }
+        }
+        return Rlt.Failed(CommonDataNullError())
+    }
+
+    override suspend fun bindAccountWithPhone(phone: String, verifyCode: String): Rlt<Res<Any>> {
+        return loginService.bindAccountWithPhone(req = BindAccountWithPhoneReq(phone, verifyCode))
+    }
+
 }
 

+ 33 - 10
module/account/src/main/java/com/adealink/weparty/account/login/verifycode/VerifyCodeActivity.kt

@@ -2,7 +2,6 @@ package com.adealink.weparty.account.login.verifycode
 
 import android.os.CountDownTimer
 import android.os.SystemClock
-import android.widget.Toast
 import androidx.activity.viewModels
 import com.adealink.frame.aab.util.getCompatString
 import com.adealink.frame.base.Rlt
@@ -18,6 +17,7 @@ import com.adealink.frame.util.formatAppPhoneKeepZero
 import com.adealink.frame.util.formatPhonePretty
 import com.adealink.weparty.account.R
 import com.adealink.weparty.account.constant.TAG_ACCOUNT_LOGIN_PHONE
+import com.adealink.weparty.account.countryselect.viewmodel.CountrySelectViewModel
 import com.adealink.weparty.account.databinding.ActivityVerifyCodeBinding
 import com.adealink.weparty.account.login.BaseLoginActivity
 import com.adealink.weparty.account.login.component.LoginTitleComp
@@ -32,6 +32,7 @@ import com.adealink.weparty.commonui.widget.pinedittext.PinField
 import com.adealink.weparty.module.account.Account
 import com.qmuiteam.qmui.widget.util.QMUIKeyboardHelper
 import com.qmuiteam.qmui.widget.util.QMUIStatusBarHelper
+import com.whatsapp.otp.android.sdk.WhatsAppOtpHandler
 
 /**
  * Created by sunxiaodong on 2021/10/6.
@@ -54,6 +55,8 @@ class VerifyCodeActivity : BaseLoginActivity() {
 
     private val binding by viewBinding(ActivityVerifyCodeBinding::inflate)
     private val loginViewModel by viewModels<LoginViewModel> { AccountViewModelFactory() }
+    private val countryViewModel by viewModels<CountrySelectViewModel> { AccountViewModelFactory() }
+
     private var enterVerifyCode: String? = null
     private val countDownTimer by fastLazy {
         object : CountDownTimer(60 * 1000L, 1000L) {
@@ -75,11 +78,9 @@ class VerifyCodeActivity : BaseLoginActivity() {
 
 
     private val smsViewComp by fastLazy {
-//        val enableWhatsApp = whatsAppOtpHandler.isWhatsAppInstalled(this).apply {
-//            Log.i(TAG_ACCOUNT_LOGIN_PHONE, "WhatsApp enableWhatsApp: $this")
-//        }
-        val enableWhatsApp = false
-        if (enableWhatsApp) {
+        val smsCountryInfo = countryViewModel.getCountryByCountryCode(countryCode ?: "")
+        val whatsAppOtpHandler = WhatsAppOtpHandler()
+        if (smsCountryInfo?.supportWhatsapp == true && whatsAppOtpHandler.isWhatsAppInstalled(this)) {
             WhatsAppViewComp(this)
         } else {
             PhoneSmsViewComp(this)
@@ -136,18 +137,20 @@ class VerifyCodeActivity : BaseLoginActivity() {
             return
         }
 
+        Log.i(
+            TAG_ACCOUNT_LOGIN_PHONE,
+            "verify code, login, phone:$phone, enterVerifyCode:$enterVerifyCode, countryCode:$countryCode"
+        )
         //根据不同的获取验证码原因,处理不同的逻辑
         when (getVerifyCodeReason) {
             GetVerifyCodeReason.BIND_PHONE -> {
                 //绑定新手机号
-//                checkVerifyCode(phone, countryCode, enterVerifyCode)
-                showToast("绑定新手机号,测试成功")
+                changeBindPhone(phone, countryCode, enterVerifyCode)
             }
 
             GetVerifyCodeReason.CHANGE_BIND_PHONE -> {
                 //更改绑定手机号
-//                changeBindPhone(phone, countryCode, enterVerifyCode)
-                showToast("更改绑定手机号,测试成功")
+                changeBindPhone(phone, countryCode, enterVerifyCode)
             }
 
             else -> {
@@ -157,6 +160,26 @@ class VerifyCodeActivity : BaseLoginActivity() {
         }
     }
 
+    private fun changeBindPhone(phone: String, countryCode: String, enterVerifyCode: String) {
+        showLoading()
+        loginViewModel.bindAccountWithPhone(
+            phoneWithRegion = formatAppPhone(phone, countryCode),
+            verifyCode = enterVerifyCode
+        ).observe(this) {
+            dismissLoading()
+            when (it) {
+                is Rlt.Success -> {
+                    showToast(it)
+                    finish()
+                }
+
+                is Rlt.Failed -> {
+                    showFailedToast(it)
+                }
+            }
+        }
+    }
+
 
     override fun initComponents() {
         LoginTitleComp(this, binding.loginTitle).attach()

+ 4 - 2
module/account/src/main/java/com/adealink/weparty/account/login/viewmodel/ILoginViewModel.kt

@@ -1,10 +1,10 @@
 package com.adealink.weparty.account.login.viewmodel
 
-import android.app.Activity
 import androidx.lifecycle.LiveData
 import com.adealink.frame.base.Rlt
 import com.adealink.frame.network.data.Res
 import com.adealink.frame.statistics.IEventValue
+import com.adealink.weparty.account.login.data.AccountInfo
 import com.adealink.weparty.account.login.data.GetVerifyCodeReason
 import com.adealink.weparty.account.login.data.LoginResult
 import com.adealink.weparty.account.login.data.ThirdType
@@ -55,5 +55,7 @@ interface ILoginViewModel {
     /**
      * 查询账号的绑定信息
      */
-    fun getAccountBindInfo():LiveData<Rlt<Res<Any>>>
+    fun getAccountBindInfo():LiveData<AccountInfo>
+
+    fun bindAccountWithPhone(phoneWithRegion: String, verifyCode: String): LiveData<Rlt<Any>>
 }

+ 36 - 8
module/account/src/main/java/com/adealink/weparty/account/login/viewmodel/LoginViewModel.kt

@@ -24,6 +24,7 @@ import com.adealink.weparty.account.constant.TAG_ACCOUNT_LOGIN_PHONE
 import com.adealink.weparty.account.constant.getLoginErrorByServerCode
 import com.adealink.weparty.account.login.auth.AuthManager
 import com.adealink.weparty.account.login.auth.IAuthCallback
+import com.adealink.weparty.account.login.data.AccountInfo
 import com.adealink.weparty.account.login.data.GetVerifyCodeReason
 import com.adealink.weparty.account.login.data.LoginResult
 import com.adealink.weparty.account.login.data.ThirdType
@@ -31,6 +32,7 @@ import com.adealink.weparty.account.login.data.VerifyCodeType
 import com.adealink.weparty.account.login.manager.loginManager
 import com.adealink.weparty.account.stat.AccountLoginStatEvent
 import com.adealink.weparty.account.stat.getReportLoginType
+import com.adealink.weparty.commonui.ext.onSuccess
 import com.adealink.weparty.module.account.ILoginListener
 import com.adealink.weparty.storage.AppPref
 import kotlinx.coroutines.CoroutineScope
@@ -93,8 +95,8 @@ class LoginViewModel : BaseViewModel(), ILoginViewModel, ILoginListener {
                     authType,
                     Rlt.Failed(AccountLoginAuthCancelError()),
                     getLoginStatSource()
-                )
-                , false)
+                ), false
+            )
             AccountLoginStatEvent(CommonEventValue.Action.AUTH).apply {
                 type to getReportLoginType(authType)
                 this.result to CommonEventValue.Result.CANCEL
@@ -169,6 +171,7 @@ class LoginViewModel : BaseViewModel(), ILoginViewModel, ILoginListener {
                         this.source to AccountLoginStatEvent.Source.LOGIN
                     }.send()
                 }
+
                 is Rlt.Failed -> {
                     phoneLoginRltLD.send(Rlt.Failed(getLoginErrorByServerCode(result.error)))
                     AccountLoginStatEvent(AccountLoginStatEvent.Action.SERVER_LOGIN).apply {
@@ -210,6 +213,7 @@ class LoginViewModel : BaseViewModel(), ILoginViewModel, ILoginListener {
                         this.source to source
                     }.send()
                 }
+
                 is Rlt.Failed -> {
                     phoneRegisterRltLD.send(Rlt.Failed(getLoginErrorByServerCode(result.error)))
                     AccountLoginStatEvent(AccountLoginStatEvent.Action.SERVER_LOGIN).apply {
@@ -227,7 +231,11 @@ class LoginViewModel : BaseViewModel(), ILoginViewModel, ILoginListener {
         }
     }
 
-    override fun setPhonePassword(phone: String, oldPassword: String, newPassword:String): LiveData<Rlt<Res<Any>>> {
+    override fun setPhonePassword(
+        phone: String,
+        oldPassword: String,
+        newPassword: String
+    ): LiveData<Rlt<Res<Any>>> {
         val liveData: LiveData<Rlt<Res<Any>>> = OnceMutableLiveData()
         viewModelScope.launch {
             liveData.send(
@@ -278,7 +286,7 @@ class LoginViewModel : BaseViewModel(), ILoginViewModel, ILoginListener {
         authManager.handleOnActivityResult(requestCode, resultCode, intent)
     }
 
-    fun onNewIntent(intent: Intent?){
+    fun onNewIntent(intent: Intent?) {
         authManager.onNewIntent(intent)
     }
 
@@ -312,8 +320,7 @@ class LoginViewModel : BaseViewModel(), ILoginViewModel, ILoginListener {
                             Triple(
                                 authType,
                                 Rlt.Failed(getLoginErrorByServerCode(result.error)), source
-                            )
-                            , false
+                            ), false
                         )
                         AccountLoginStatEvent(AccountLoginStatEvent.Action.SERVER_LOGIN).apply {
                             type to getReportLoginType(authType)
@@ -356,8 +363,29 @@ class LoginViewModel : BaseViewModel(), ILoginViewModel, ILoginListener {
         }
     }
 
-    override fun getAccountBindInfo(): LiveData<Rlt<Res<Any>>> {
-        val onceMutableLiveData = OnceMutableLiveData<Rlt<Res<Any>>>()
+    override fun getAccountBindInfo(): LiveData<AccountInfo> {
+        val onceMutableLiveData = OnceMutableLiveData<AccountInfo>()
+        viewModelScope.launch {
+            loginManager.fetchAccountInfo().onSuccess { data ->
+                onceMutableLiveData.send(data)
+            }
+        }
+
         return onceMutableLiveData
     }
+
+
+    override fun bindAccountWithPhone(
+        phoneWithRegion: String,
+        verifyCode: String
+    ): LiveData<Rlt<Any>> {
+        val onceMutableLiveData = OnceMutableLiveData<Rlt<Any>>()
+        viewModelScope.launch {
+            val rlt = loginManager.bindAccountWithPhone(phoneWithRegion, verifyCode)
+            onceMutableLiveData.send(rlt)
+        }
+
+        return onceMutableLiveData
+    }
+
 }

+ 38 - 26
module/account/src/main/java/com/adealink/weparty/account/setting/AccountSettingActivity.kt

@@ -13,6 +13,7 @@ import com.adealink.frame.util.onClick
 import com.adealink.weparty.account.R
 import com.adealink.weparty.account.constant.TAG_ACCOUNT
 import com.adealink.weparty.account.databinding.ActivityAccountSettingBinding
+import com.adealink.weparty.account.login.data.AccountInfo
 import com.adealink.weparty.account.login.data.GetVerifyCodeReason
 import com.adealink.weparty.account.login.viewmodel.LoginViewModel
 import com.adealink.weparty.account.viewModel.AccountViewModelFactory
@@ -22,6 +23,8 @@ import com.adealink.weparty.commonui.ext.show
 import com.adealink.weparty.commonui.widget.CommonDialog
 import com.adealink.weparty.module.account.Account
 import com.adealink.weparty.module.profile.ProfileModule
+import com.google.i18n.phonenumbers.PhoneNumberUtil
+import com.google.i18n.phonenumbers.Phonenumber.PhoneNumber
 import com.qmuiteam.qmui.widget.util.QMUIStatusBarHelper
 import com.adealink.weparty.R as APP_R
 
@@ -54,25 +57,55 @@ class AccountSettingActivity : BaseActivity() {
         }
     }
 
+    var accountInfo: AccountInfo? = null
 
     override fun loadData() {
         super.loadData()
 
         loginViewModel.getAccountBindInfo().observe(this) {
-            //todo:
+            accountInfo = it
+            updateUI(accountInfo)
         }
 
 
+        val hasPassword = false
+        if (hasPassword) {
+            binding.passwordLayout.text = getCompatString(R.string.account_paassword_modification)
+            binding.passwordLayout.onClick {
+                //修改密码
+                Router.build(this, Account.Phone.SET_PASSWORD)
+                    .putExtra(Account.Phone.EXTRA_HAS_PASSWORD, true)
+                    //todo:把手机号,国家码传过去
+                    .start()
+            }
+
+        } else {
+            binding.passwordLayout.text = getCompatString(R.string.account_password_setting)
+            binding.passwordLayout.onClick {
+                //设置密码
+                Router.build(this, Account.Phone.SET_PASSWORD)
+                    .putExtra(Account.Phone.EXTRA_HAS_PASSWORD, false)
+                    //todo:把手机号,国家码传过去
+                    .start()
+            }
+        }
+    }
+
+    private fun updateUI(accountInfo: AccountInfo?) {
+        accountInfo ?: return
+
         //todo:获取当前绑定的手机号
-        //如果没有手机号,无法设置密码
+        //todo:如果没有手机号,无法设置密码,还是改交互
 
-        val hasBindPhone = false
+        val hasBindPhone = accountInfo.registPhoneNumber.isNotEmpty()
         if (hasBindPhone) {
-            binding.tvPhoneBind.text = "1234567890"
+            binding.tvPhoneBind.text = accountInfo.registPhoneNumber
             binding.tvPhoneBind.setTextColor(getCompatColor(APP_R.color.color_AAAAAA))
             binding.tvPhoneBind.setCompoundDrawablesRelative(null, null, null, null)
             binding.tvPhoneBind.onClick {
                 //改绑手机号
+                val phoneNumber: PhoneNumber =
+                    PhoneNumberUtil.getInstance().parse(accountInfo.registPhoneNumber, null)
                 changeBindMobilePhone(currentPhoneNumber = "1234567890", currentCountryCode = "CN")
             }
             binding.passwordLayout.show()
@@ -93,30 +126,9 @@ class AccountSettingActivity : BaseActivity() {
         }
 
 
-        val hasPassword = false
-        if (hasPassword) {
-            binding.passwordLayout.text = getCompatString(R.string.account_paassword_modification)
-            binding.passwordLayout.onClick {
-                //修改密码
-                Router.build(this, Account.Phone.SET_PASSWORD)
-                    .putExtra(Account.Phone.EXTRA_HAS_PASSWORD, true)
-                    //todo:把手机号,国家码传过去
-                    .start()
-            }
-
-        } else {
-            binding.passwordLayout.text = getCompatString(R.string.account_password_setting)
-            binding.passwordLayout.onClick {
-                //设置密码
-                Router.build(this, Account.Phone.SET_PASSWORD)
-                    .putExtra(Account.Phone.EXTRA_HAS_PASSWORD, false)
-                    //todo:把手机号,国家码传过去
-                    .start()
-            }
-        }
-
     }
 
+
     private fun firstBindMobilePhone() {
         Log.i(TAG_ACCOUNT, "firstBindMobilePhone")
         Router.build(this, Account.Phone.INPUT)