登录相关,首次提交
This commit is contained in:
@@ -1,11 +1,21 @@
|
||||
package com.juhabi.birds
|
||||
|
||||
object AppConfig {
|
||||
const val BASE_URL = "http://47.97.217.123:8081/"
|
||||
const val APP_CLIENT_ID = "428a8310cd442757ae699df5d894f051"
|
||||
// const val BASE_URL = "http://47.97.217.123:8081"
|
||||
const val BASE_URL = "http://192.168.1.217:8081/"
|
||||
const val APP_CLIENT_ID = "app"
|
||||
const val APP_USER_TYPE = "app_user"
|
||||
const val CONTENT_LANGUAGE = "zh_CN"
|
||||
//验证码场景 --注册
|
||||
const val SEND_CODE_SCENE_REGISTER = "register"
|
||||
//验证码场景 --登录
|
||||
const val SEND_CODE_SCENE_LOGIN = "login"
|
||||
//验证码场景 --重置密码
|
||||
const val SEND_CODE_SCENE_RESET = "resetPwd"
|
||||
|
||||
@Volatile
|
||||
var userToken: String = ""
|
||||
//是否登录
|
||||
var USER_LOGIN: Boolean = false;
|
||||
|
||||
}
|
||||
|
||||
@@ -6,6 +6,8 @@ import android.app.Application
|
||||
import android.content.Context
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import com.juhabi.birds.network.TokenManager
|
||||
import com.juhabi.birds.util.SharedPreferencesUtil
|
||||
import com.juhabi.birds.util.manager.UserInfoManager
|
||||
import me.jessyan.autosize.AutoSize
|
||||
import me.jessyan.autosize.AutoSizeConfig
|
||||
@@ -36,9 +38,21 @@ class MyApplication : Application(), Application.ActivityLifecycleCallbacks {
|
||||
/** Add application-wide, privacy-safe SDK initialization here. */
|
||||
private fun initialize() {
|
||||
UserInfoManager.initialize(this)
|
||||
restoreLoginSession()
|
||||
// NetworkManager is created lazily by ApiClient, so it needs no eager initialization.
|
||||
}
|
||||
|
||||
/**
|
||||
* 启动时从本地恢复 token,写入 AppConfig.userToken,
|
||||
* 业务接口通过 NetworkManager.getToken() 自动带上 Authorization。
|
||||
*/
|
||||
private fun restoreLoginSession() {
|
||||
val token = TokenManager.get(this).trim()
|
||||
AppConfig.userToken = token
|
||||
AppConfig.USER_LOGIN = token.isNotBlank() &&
|
||||
SharedPreferencesUtil.getBoolean(this, KEY_USER_LOGIN, defaultValue = token.isNotBlank())
|
||||
}
|
||||
|
||||
override fun onActivityResumed(activity: Activity) {
|
||||
currentActivity = activity
|
||||
}
|
||||
@@ -80,6 +94,8 @@ class MyApplication : Application(), Application.ActivityLifecycleCallbacks {
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val KEY_USER_LOGIN = "user_login"
|
||||
|
||||
lateinit var instance: MyApplication
|
||||
private set
|
||||
|
||||
|
||||
217
app/src/main/java/com/juhabi/birds/login/ForgetPsdActivity.kt
Normal file
217
app/src/main/java/com/juhabi/birds/login/ForgetPsdActivity.kt
Normal file
@@ -0,0 +1,217 @@
|
||||
package com.juhabi.birds.login
|
||||
|
||||
import android.os.Bundle
|
||||
import android.os.CountDownTimer
|
||||
import android.text.InputType
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.widget.EditText
|
||||
import com.gyf.immersionbar.ImmersionBar
|
||||
import com.juhabi.birds.AppConfig
|
||||
import com.juhabi.birds.R
|
||||
import com.juhabi.birds.base.BaseActivity
|
||||
import com.juhabi.birds.databinding.ForgetPsdLayoutBinding
|
||||
import com.juhabi.birds.login.model.UserEntity
|
||||
import com.juhabi.birds.login.mvp.LoginContract
|
||||
import com.juhabi.birds.login.mvp.LoginImpl
|
||||
import com.juhabi.birds.login.mvp.LoginPresenter
|
||||
import com.juhabi.birds.util.ToastUtil
|
||||
|
||||
/**
|
||||
* 忘记密码 / 修改密码
|
||||
*/
|
||||
class ForgetPsdActivity : BaseActivity<ForgetPsdLayoutBinding, LoginPresenter>(),
|
||||
LoginContract.LoginView, View.OnClickListener {
|
||||
|
||||
private var codeCountDownTimer: CountDownTimer? = null
|
||||
private var isPasswordVisible = false
|
||||
private var isConfirmPasswordVisible = false
|
||||
|
||||
override fun createBinding(inflater: LayoutInflater): ForgetPsdLayoutBinding {
|
||||
return ForgetPsdLayoutBinding.inflate(inflater)
|
||||
}
|
||||
|
||||
override fun createPresenter(): LoginPresenter? {
|
||||
return LoginPresenter(LoginImpl())
|
||||
}
|
||||
|
||||
override fun initWindows() {
|
||||
ImmersionBar.with(this)
|
||||
.statusBarView(binding.statusBarView)
|
||||
.statusBarDarkFont(true)
|
||||
.navigationBarColor(R.color.color_zhu)
|
||||
.navigationBarDarkIcon(true)
|
||||
.init()
|
||||
}
|
||||
|
||||
override fun initView(savedInstanceState: Bundle?) {
|
||||
binding.includedTitle.tvTitle.setText(R.string.forget_password_title)
|
||||
listOf(
|
||||
binding.includedTitle.imgBack,
|
||||
binding.getCodeButton,
|
||||
binding.passwordVisibilityButton,
|
||||
binding.confirmPasswordVisibilityButton,
|
||||
binding.confirmButton,
|
||||
).forEach { view ->
|
||||
view.setOnClickListener(this)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onClick(view: View) {
|
||||
when (view.id) {
|
||||
R.id.img_back -> {
|
||||
finish()
|
||||
}
|
||||
|
||||
R.id.getCodeButton -> {//获取验证码
|
||||
val phone = binding.phoneEditText.text.toString().trim()
|
||||
if (phone.isBlank()) {
|
||||
ToastUtil.showShort(mContext, "手机号不能为空")
|
||||
return
|
||||
}
|
||||
presenter?.getPhoneSmsCode(phone, AppConfig.SEND_CODE_SCENE_RESET)
|
||||
}
|
||||
|
||||
R.id.passwordVisibilityButton -> {
|
||||
isPasswordVisible = !isPasswordVisible
|
||||
togglePasswordVisibility(binding.passwordEditText, isPasswordVisible)
|
||||
}
|
||||
|
||||
R.id.confirmPasswordVisibilityButton -> {
|
||||
isConfirmPasswordVisible = !isConfirmPasswordVisible
|
||||
togglePasswordVisibility(binding.confirmPasswordEditText, isConfirmPasswordVisible)
|
||||
}
|
||||
|
||||
R.id.confirmButton -> {//修改密码
|
||||
val phone = binding.phoneEditText.text.toString().trim()
|
||||
val code = binding.codeEditText.text.toString().trim()
|
||||
val password = binding.passwordEditText.text.toString()
|
||||
val confirmPassword = binding.confirmPasswordEditText.text.toString()
|
||||
|
||||
if (phone.isBlank()) {
|
||||
ToastUtil.showShort(mContext, "手机号不能为空")
|
||||
return
|
||||
}
|
||||
if (code.isBlank()) {
|
||||
ToastUtil.showShort(mContext, "验证码不能为空")
|
||||
return
|
||||
}
|
||||
if (password.isBlank()) {
|
||||
ToastUtil.showShort(mContext, "密码不能为空")
|
||||
return
|
||||
}
|
||||
if (confirmPassword.isBlank()) {
|
||||
ToastUtil.showShort(mContext, "请再次输入密码")
|
||||
return
|
||||
}
|
||||
if (password != confirmPassword) {
|
||||
ToastUtil.showShort(mContext, "两次输入的密码不一致")
|
||||
return
|
||||
}
|
||||
if (!isValidPassword(password)) {
|
||||
ToastUtil.showShort(
|
||||
mContext,
|
||||
"密码需为8-20位,且包含大小写字母和数字"
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
presenter?.forgetPsdByPhone(phone, code, password)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun togglePasswordVisibility(editText: EditText, visible: Boolean) {
|
||||
val selection = editText.selectionEnd
|
||||
editText.inputType = if (visible) {
|
||||
InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD
|
||||
} else {
|
||||
InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_PASSWORD
|
||||
}
|
||||
editText.setSelection(selection.coerceAtLeast(0))
|
||||
editText.typeface = binding.phoneEditText.typeface
|
||||
}
|
||||
|
||||
override fun showError(message: String) {
|
||||
hideLoading()
|
||||
ToastUtil.showShort(mContext, message)
|
||||
}
|
||||
|
||||
override fun sendCodeSuccess(message: String) {
|
||||
hideLoading()
|
||||
ToastUtil.showShort(mContext, message)
|
||||
codeCountDownTimer?.cancel()
|
||||
binding.getCodeButton.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.getCodeButton.text = getString(
|
||||
R.string.register_code_countdown,
|
||||
secondsRemaining
|
||||
)
|
||||
}
|
||||
|
||||
override fun onFinish() {
|
||||
codeCountDownTimer = null
|
||||
binding.getCodeButton.apply {
|
||||
isEnabled = true
|
||||
isClickable = true
|
||||
setBackgroundResource(R.drawable.shape_register_code_bg)
|
||||
setText(R.string.register_get_code)
|
||||
}
|
||||
}
|
||||
}.start()
|
||||
}
|
||||
|
||||
override fun onRegisterSuccess(message: String) {
|
||||
}
|
||||
|
||||
override fun onForgetPsdSuccess(message: String) {
|
||||
hideLoading()
|
||||
ToastUtil.showShort(mContext, message.ifBlank { "密码修改成功" })
|
||||
finish()
|
||||
}
|
||||
|
||||
override fun showUsernameError(message: String) {
|
||||
ToastUtil.showShort(mContext, message)
|
||||
}
|
||||
|
||||
override fun showPasswordError(message: String) {
|
||||
ToastUtil.showShort(mContext, message)
|
||||
}
|
||||
|
||||
override fun clearInputErrors() {
|
||||
}
|
||||
|
||||
override fun onLoginSuccess(user: UserEntity) {
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
codeCountDownTimer?.cancel()
|
||||
codeCountDownTimer = null
|
||||
super.onDestroy()
|
||||
}
|
||||
|
||||
/** 8-20 位,且同时包含大写、小写字母和数字。 */
|
||||
private fun isValidPassword(password: String): Boolean {
|
||||
if (password.length !in PASSWORD_MIN_LENGTH..PASSWORD_MAX_LENGTH) {
|
||||
return false
|
||||
}
|
||||
val hasUpper = password.any { it.isUpperCase() }
|
||||
val hasLower = password.any { it.isLowerCase() }
|
||||
val hasDigit = password.any { it.isDigit() }
|
||||
return hasUpper && hasLower && hasDigit
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val CODE_COUNTDOWN_SECONDS = 60L
|
||||
const val CODE_COUNTDOWN_MILLIS = CODE_COUNTDOWN_SECONDS * 1_000L
|
||||
const val PASSWORD_MIN_LENGTH = 8
|
||||
const val PASSWORD_MAX_LENGTH = 20
|
||||
}
|
||||
}
|
||||
@@ -1,20 +1,35 @@
|
||||
package com.juhabi.birds.login
|
||||
|
||||
import android.os.Bundle
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.os.CountDownTimer
|
||||
import android.text.InputType
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import com.gyf.immersionbar.ImmersionBar
|
||||
import com.juhabi.birds.AppConfig
|
||||
import com.juhabi.birds.R
|
||||
import com.juhabi.birds.base.BaseActivity
|
||||
import com.juhabi.birds.databinding.ActivityLoginBinding
|
||||
import com.juhabi.birds.login.model.LoginUser
|
||||
import com.juhabi.birds.login.model.UserEntity
|
||||
import com.juhabi.birds.login.mvp.LoginContract
|
||||
import com.juhabi.birds.login.mvp.LoginImpl
|
||||
import com.juhabi.birds.login.mvp.LoginPresenter
|
||||
import com.juhabi.birds.network.TokenManager
|
||||
import com.juhabi.birds.mine.MineCenterActivity
|
||||
import com.juhabi.birds.network.TokenManager
|
||||
import com.juhabi.birds.util.SharedPreferencesUtil
|
||||
import com.juhabi.birds.util.ToastUtil
|
||||
|
||||
/**
|
||||
* 登录
|
||||
*/
|
||||
class LoginActivity : BaseActivity<ActivityLoginBinding, LoginPresenter>(),
|
||||
LoginContract.LoginView {
|
||||
LoginContract.LoginView, View.OnClickListener {
|
||||
|
||||
/** 是否使用密码登录;false 为手机号 + 验证码登录 */
|
||||
private var loginByPassword = true
|
||||
private var isPasswordVisible = false
|
||||
private var codeCountDownTimer: CountDownTimer? = null
|
||||
|
||||
override fun createBinding(inflater: LayoutInflater): ActivityLoginBinding {
|
||||
return ActivityLoginBinding.inflate(inflater)
|
||||
@@ -24,48 +39,176 @@ class LoginActivity : BaseActivity<ActivityLoginBinding, LoginPresenter>(),
|
||||
return LoginPresenter(LoginImpl())
|
||||
}
|
||||
|
||||
override fun initWindows() {
|
||||
ImmersionBar.with(this)
|
||||
.navigationBarColor(R.color.color_zhu)
|
||||
.navigationBarDarkIcon(true)
|
||||
.init()
|
||||
}
|
||||
|
||||
override fun initView(savedInstanceState: Bundle?) {
|
||||
// if (TokenManager.get(this).isNotBlank()) {
|
||||
// startActivity(Intent(this, MineCenterActivity::class.java))
|
||||
// finish()
|
||||
// return
|
||||
// }
|
||||
if(binding.usernameEditText.text.toString().isNotBlank()){
|
||||
ToastUtil.showShort(mContext,"");
|
||||
return
|
||||
listOf(
|
||||
binding.tvChangeCode,
|
||||
binding.forgotPasswordButton,
|
||||
binding.passwordVisibilityButton,
|
||||
binding.getCodeButton,
|
||||
binding.loginButton,
|
||||
binding.registerButton,
|
||||
).forEach { button ->
|
||||
button.setOnClickListener(this)
|
||||
}
|
||||
binding.loginButton.setOnClickListener {
|
||||
presenter?.login(
|
||||
binding.usernameEditText.text?.toString().orEmpty(),
|
||||
binding.passwordEditText.text?.toString().orEmpty()
|
||||
)
|
||||
}
|
||||
|
||||
override fun onClick(view: View) {
|
||||
when (view.id) {
|
||||
R.id.tvChangeCode -> {//更换登录方式
|
||||
if (loginByPassword) {
|
||||
binding.linearCode.visibility = View.VISIBLE
|
||||
binding.linearPsd.visibility = View.GONE
|
||||
loginByPassword = false
|
||||
binding.tvChangeCode.setText(R.string.register_change_psd_login)
|
||||
} else {
|
||||
binding.linearCode.visibility = View.GONE
|
||||
binding.linearPsd.visibility = View.VISIBLE
|
||||
loginByPassword = true
|
||||
binding.tvChangeCode.setText(R.string.register_change_code_login)
|
||||
}
|
||||
}
|
||||
|
||||
R.id.getCodeButton -> {//获取验证码
|
||||
val phone = binding.accountEditText.text.toString().trim()
|
||||
if (phone.isBlank()) {
|
||||
ToastUtil.showShort(mContext, "手机号不能为空")
|
||||
return
|
||||
}
|
||||
presenter?.getPhoneSmsCode(phone, AppConfig.SEND_CODE_SCENE_LOGIN)
|
||||
}
|
||||
|
||||
R.id.registerButton -> {//注册
|
||||
goTo(RegisterActivity::class.java, null)
|
||||
}
|
||||
|
||||
R.id.forgotPasswordButton -> {//忘记密码
|
||||
goTo(ForgetPsdActivity::class.java, null)
|
||||
}
|
||||
|
||||
R.id.passwordVisibilityButton -> {
|
||||
togglePasswordVisibility()
|
||||
}
|
||||
|
||||
R.id.loginButton -> {//登录
|
||||
val account = binding.accountEditText.text.toString().trim()
|
||||
if (account.isBlank()) {
|
||||
ToastUtil.showShort(mContext, "账号不能为空")
|
||||
return
|
||||
}
|
||||
|
||||
if (loginByPassword) {
|
||||
val password = binding.passwordEditText.text.toString()
|
||||
if (password.isBlank()) {
|
||||
ToastUtil.showShort(mContext, "密码不能为空")
|
||||
return
|
||||
}
|
||||
presenter?.loginByPhonePsd(account, password)
|
||||
} else {
|
||||
val code = binding.codeEditText.text.toString().trim()
|
||||
if (code.isBlank()) {
|
||||
ToastUtil.showShort(mContext, "验证码不能为空")
|
||||
return
|
||||
}
|
||||
presenter?.loginByPhoneSms(account, code)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun togglePasswordVisibility() {
|
||||
isPasswordVisible = !isPasswordVisible
|
||||
val selection = binding.passwordEditText.selectionEnd
|
||||
binding.passwordEditText.inputType = if (isPasswordVisible) {
|
||||
InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD
|
||||
} else {
|
||||
InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_PASSWORD
|
||||
}
|
||||
// 保持光标位置,并触发 typeface 刷新
|
||||
binding.passwordEditText.setSelection(selection.coerceAtLeast(0))
|
||||
binding.passwordEditText.typeface = binding.accountEditText.typeface
|
||||
}
|
||||
|
||||
override fun sendCodeSuccess(message: String) {
|
||||
hideLoading()
|
||||
ToastUtil.showShort(mContext, message)
|
||||
codeCountDownTimer?.cancel()
|
||||
binding.getCodeButton.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.getCodeButton.text = getString(
|
||||
R.string.register_code_countdown,
|
||||
secondsRemaining
|
||||
)
|
||||
}
|
||||
|
||||
override fun onFinish() {
|
||||
codeCountDownTimer = null
|
||||
binding.getCodeButton.apply {
|
||||
isEnabled = true
|
||||
isClickable = true
|
||||
setBackgroundResource(R.drawable.shape_register_code_bg)
|
||||
setText(R.string.register_get_code)
|
||||
}
|
||||
}
|
||||
}.start()
|
||||
}
|
||||
|
||||
override fun onRegisterSuccess(message: String) {
|
||||
}
|
||||
|
||||
override fun onForgetPsdSuccess(message: String) {
|
||||
}
|
||||
|
||||
override fun showUsernameError(message: String) {
|
||||
binding.usernameLayout.error = message
|
||||
binding.usernameEditText.requestFocus()
|
||||
ToastUtil.showShort(mContext, message)
|
||||
}
|
||||
|
||||
override fun showPasswordError(message: String) {
|
||||
binding.passwordLayout.error = message
|
||||
binding.passwordEditText.requestFocus()
|
||||
ToastUtil.showShort(mContext, message)
|
||||
}
|
||||
|
||||
override fun clearInputErrors() {
|
||||
binding.usernameLayout.error = null
|
||||
binding.passwordLayout.error = null
|
||||
}
|
||||
|
||||
override fun onLoginSuccess(user: LoginUser) {
|
||||
TokenManager.save(this, user.accessToken)
|
||||
binding.resultTextView.text = "登录成功,Token 已保存"
|
||||
showMessage("登录成功")
|
||||
override fun onLoginSuccess(user: UserEntity) {
|
||||
val token = user.token.trim()
|
||||
// SharedPreferences 持久化 token,并同步到内存 AppConfig.userToken
|
||||
TokenManager.save(this, token)
|
||||
AppConfig.USER_LOGIN = token.isNotBlank()
|
||||
SharedPreferencesUtil.putBoolean(this, KEY_USER_LOGIN, AppConfig.USER_LOGIN)
|
||||
|
||||
ToastUtil.showShort(mContext, "登录成功")
|
||||
startActivity(Intent(this, MineCenterActivity::class.java))
|
||||
finish()
|
||||
}
|
||||
|
||||
override fun showError(message: String) {
|
||||
ToastUtil.showShort(mContext,message)
|
||||
hideLoading()
|
||||
ToastUtil.showShort(mContext, message)
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
codeCountDownTimer?.cancel()
|
||||
codeCountDownTimer = null
|
||||
super.onDestroy()
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val CODE_COUNTDOWN_SECONDS = 60L
|
||||
const val CODE_COUNTDOWN_MILLIS = CODE_COUNTDOWN_SECONDS * 1_000L
|
||||
const val KEY_USER_LOGIN = "user_login"
|
||||
}
|
||||
}
|
||||
|
||||
192
app/src/main/java/com/juhabi/birds/login/RegisterActivity.kt
Normal file
192
app/src/main/java/com/juhabi/birds/login/RegisterActivity.kt
Normal file
@@ -0,0 +1,192 @@
|
||||
package com.juhabi.birds.login
|
||||
|
||||
import android.os.Bundle
|
||||
import android.os.CountDownTimer
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import com.gyf.immersionbar.ImmersionBar
|
||||
import com.juhabi.birds.AppConfig
|
||||
import com.juhabi.birds.R
|
||||
import com.juhabi.birds.base.BaseActivity
|
||||
import com.juhabi.birds.databinding.RegisterLayoutBinding
|
||||
import com.juhabi.birds.login.model.UserEntity
|
||||
import com.juhabi.birds.login.mvp.LoginContract
|
||||
import com.juhabi.birds.login.mvp.LoginImpl
|
||||
import com.juhabi.birds.login.mvp.LoginPresenter
|
||||
import com.juhabi.birds.util.ToastUtil
|
||||
|
||||
/**
|
||||
* 注册
|
||||
*/
|
||||
class RegisterActivity : BaseActivity<RegisterLayoutBinding, LoginPresenter>(),
|
||||
LoginContract.LoginView, View.OnClickListener {
|
||||
|
||||
private var codeCountDownTimer: CountDownTimer? = null
|
||||
|
||||
override fun createBinding(inflater: LayoutInflater): RegisterLayoutBinding {
|
||||
return RegisterLayoutBinding.inflate(inflater)
|
||||
}
|
||||
|
||||
override fun createPresenter(): LoginPresenter? {
|
||||
return LoginPresenter(LoginImpl())
|
||||
}
|
||||
|
||||
override fun initWindows() {
|
||||
ImmersionBar.with(this)
|
||||
.statusBarView(binding.statusBarView)
|
||||
.statusBarDarkFont(true)
|
||||
.navigationBarColor(R.color.color_zhu)
|
||||
.navigationBarDarkIcon(true)
|
||||
.init()
|
||||
}
|
||||
|
||||
override fun initView(savedInstanceState: Bundle?) {
|
||||
binding.includedTitle.tvTitle.setText(R.string.login_register)
|
||||
listOf(
|
||||
binding.passwordVisibilityButton,
|
||||
binding.getCodeButton,
|
||||
binding.confirmButton,
|
||||
binding.includedTitle.imgBack,
|
||||
).forEach { button ->
|
||||
button.setOnClickListener(this)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onClick(view: View) {
|
||||
when (view.id) {
|
||||
|
||||
R.id.img_back ->{
|
||||
finish()
|
||||
}
|
||||
|
||||
R.id.getCodeButton -> {//获取验证码
|
||||
if (binding.phoneEditText.text.toString().isBlank()) {
|
||||
ToastUtil.showShort(mContext, "手机号不能为空")
|
||||
return
|
||||
}
|
||||
presenter?.getPhoneSmsCode(
|
||||
binding.phoneEditText.text.toString(),
|
||||
AppConfig.SEND_CODE_SCENE_REGISTER
|
||||
)
|
||||
}
|
||||
|
||||
R.id.confirmButton -> {//注册
|
||||
val phone = binding.phoneEditText.text.toString().trim()
|
||||
val code = binding.codeEditText.text.toString().trim()
|
||||
val password = binding.passwordEditText.text.toString()
|
||||
val confirmPassword = binding.confirmPasswordEditText.text.toString()
|
||||
|
||||
if (phone.isBlank()) {
|
||||
ToastUtil.showShort(mContext, "手机号不能为空")
|
||||
return
|
||||
}
|
||||
if (code.isBlank()) {
|
||||
ToastUtil.showShort(mContext, "验证码不能为空")
|
||||
return
|
||||
}
|
||||
if (password.isBlank()) {
|
||||
ToastUtil.showShort(mContext, "密码不能为空")
|
||||
return
|
||||
}
|
||||
if (confirmPassword.isBlank()) {
|
||||
ToastUtil.showShort(mContext, "请再次输入密码")
|
||||
return
|
||||
}
|
||||
if (password != confirmPassword) {
|
||||
ToastUtil.showShort(mContext, "两次输入的密码不一致")
|
||||
return
|
||||
}
|
||||
if (!isValidPassword(password)) {
|
||||
ToastUtil.showShort(
|
||||
mContext,
|
||||
"密码需为8-20位,且包含大小写字母和数字"
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
presenter?.registerByPhone(phone, code, password)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun showError(message: String) {
|
||||
hideLoading()
|
||||
ToastUtil.showShort(mContext, message)
|
||||
}
|
||||
|
||||
override fun sendCodeSuccess(message: String) {
|
||||
hideLoading()
|
||||
ToastUtil.showShort(mContext, message)
|
||||
codeCountDownTimer?.cancel()
|
||||
binding.getCodeButton.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.getCodeButton.text = getString(
|
||||
R.string.register_code_countdown,
|
||||
secondsRemaining
|
||||
)
|
||||
}
|
||||
|
||||
override fun onFinish() {
|
||||
codeCountDownTimer = null
|
||||
binding.getCodeButton.apply {
|
||||
isEnabled = true
|
||||
isClickable = true
|
||||
setBackgroundResource(R.drawable.shape_register_code_bg)
|
||||
setText(R.string.register_get_code)
|
||||
}
|
||||
}
|
||||
}.start()
|
||||
}
|
||||
|
||||
override fun onRegisterSuccess(message: String) {
|
||||
hideLoading()
|
||||
ToastUtil.showShort(mContext, message.ifBlank { "注册成功" })
|
||||
finish()
|
||||
}
|
||||
|
||||
override fun onForgetPsdSuccess(message: String) {
|
||||
}
|
||||
|
||||
override fun showUsernameError(message: String) {
|
||||
}
|
||||
|
||||
override fun showPasswordError(message: String) {
|
||||
}
|
||||
|
||||
override fun clearInputErrors() {
|
||||
}
|
||||
|
||||
override fun onLoginSuccess(user: UserEntity) {
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
codeCountDownTimer?.cancel()
|
||||
codeCountDownTimer = null
|
||||
super.onDestroy()
|
||||
}
|
||||
|
||||
/** 8-20 位,且同时包含大写、小写字母和数字。 */
|
||||
private fun isValidPassword(password: String): Boolean {
|
||||
if (password.length !in PASSWORD_MIN_LENGTH..PASSWORD_MAX_LENGTH) {
|
||||
return false
|
||||
}
|
||||
val hasUpper = password.any { it.isUpperCase() }
|
||||
val hasLower = password.any { it.isLowerCase() }
|
||||
val hasDigit = password.any { it.isDigit() }
|
||||
return hasUpper && hasLower && hasDigit
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val CODE_COUNTDOWN_SECONDS = 60L
|
||||
const val CODE_COUNTDOWN_MILLIS = CODE_COUNTDOWN_SECONDS * 1_000L
|
||||
const val PASSWORD_MIN_LENGTH = 8
|
||||
const val PASSWORD_MAX_LENGTH = 20
|
||||
}
|
||||
}
|
||||
86
app/src/main/java/com/juhabi/birds/login/WelcomeActivity.kt
Normal file
86
app/src/main/java/com/juhabi/birds/login/WelcomeActivity.kt
Normal file
@@ -0,0 +1,86 @@
|
||||
package com.juhabi.birds.login
|
||||
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.view.LayoutInflater
|
||||
import com.gyf.immersionbar.ImmersionBar
|
||||
import com.juhabi.birds.AppConfig
|
||||
import com.juhabi.birds.R
|
||||
import com.juhabi.birds.base.BaseActivity
|
||||
import com.juhabi.birds.databinding.ActiveWelcomeBinding
|
||||
import com.juhabi.birds.login.model.UserEntity
|
||||
import com.juhabi.birds.login.mvp.LoginContract
|
||||
import com.juhabi.birds.login.mvp.LoginPresenter
|
||||
import com.juhabi.birds.main.MainActivity
|
||||
|
||||
/**
|
||||
* 启动页面
|
||||
*/
|
||||
class WelcomeActivity: BaseActivity<ActiveWelcomeBinding,LoginPresenter>(),LoginContract.LoginView {
|
||||
private val handler = Handler(Looper.getMainLooper())
|
||||
private val navigateRunnable = Runnable {
|
||||
val targetActivity = if (AppConfig.USER_LOGIN) {
|
||||
MainActivity::class.java
|
||||
} else {
|
||||
LoginActivity::class.java
|
||||
}
|
||||
startActivity(Intent(this, targetActivity))
|
||||
finish()
|
||||
}
|
||||
|
||||
override fun createBinding(inflater: LayoutInflater): ActiveWelcomeBinding {
|
||||
return ActiveWelcomeBinding.inflate(inflater)
|
||||
}
|
||||
|
||||
|
||||
override fun initWindows() {
|
||||
ImmersionBar.with(this)
|
||||
.navigationBarColor(R.color.color_zhu)
|
||||
.navigationBarDarkIcon(true)
|
||||
.init()
|
||||
}
|
||||
override fun createPresenter(): LoginPresenter? {
|
||||
return null
|
||||
}
|
||||
|
||||
override fun initView(savedInstanceState: Bundle?) {
|
||||
|
||||
handler.postDelayed(navigateRunnable, SPLASH_DELAY_MILLIS)
|
||||
|
||||
}
|
||||
|
||||
override fun showError(message: String) {
|
||||
}
|
||||
|
||||
override fun sendCodeSuccess(message: String) {
|
||||
}
|
||||
|
||||
override fun onRegisterSuccess(message: String) {
|
||||
}
|
||||
|
||||
override fun onForgetPsdSuccess(message: String) {
|
||||
}
|
||||
|
||||
override fun showUsernameError(message: String) {
|
||||
}
|
||||
|
||||
override fun showPasswordError(message: String) {
|
||||
}
|
||||
|
||||
override fun clearInputErrors() {
|
||||
}
|
||||
|
||||
override fun onLoginSuccess(user: UserEntity) {
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
handler.removeCallbacks(navigateRunnable)
|
||||
super.onDestroy()
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val SPLASH_DELAY_MILLIS = 2_000L
|
||||
}
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
package com.juhabi.birds.login.model
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
data class LoginUser(
|
||||
val scope: Any? = null,
|
||||
val openid: Any? = null,
|
||||
@SerializedName("access_token")
|
||||
val accessToken: String = "",
|
||||
@SerializedName("refresh_token")
|
||||
val refreshToken: Any? = null,
|
||||
@SerializedName("expire_in")
|
||||
val expireIn: Long = 0,
|
||||
@SerializedName("refresh_expire_in")
|
||||
val refreshExpireIn: Any? = null,
|
||||
@SerializedName("client_id")
|
||||
val clientId: String = ""
|
||||
)
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.juhabi.birds.login.model
|
||||
|
||||
data class SendCodeEntity(
|
||||
val code: Int,
|
||||
val `data`: Any,
|
||||
val msg: String
|
||||
)
|
||||
11
app/src/main/java/com/juhabi/birds/login/model/UserEntity.kt
Normal file
11
app/src/main/java/com/juhabi/birds/login/model/UserEntity.kt
Normal file
@@ -0,0 +1,11 @@
|
||||
package com.juhabi.birds.login.model
|
||||
|
||||
import com.google.gson.annotations.SerializedName
|
||||
|
||||
data class UserEntity(
|
||||
val scope: Any? = null,
|
||||
val openid: Any? = null,
|
||||
@SerializedName("access_token")
|
||||
val token: String = "",
|
||||
|
||||
)
|
||||
@@ -1,7 +1,8 @@
|
||||
package com.juhabi.birds.login.mvp
|
||||
|
||||
import com.juhabi.birds.base.IView
|
||||
import com.juhabi.birds.login.model.LoginUser
|
||||
import com.juhabi.birds.login.model.UserEntity
|
||||
import com.juhabi.birds.login.model.SendCodeEntity
|
||||
import com.juhabi.birds.network.BaseBean
|
||||
import org.json.JSONObject
|
||||
|
||||
@@ -12,15 +13,38 @@ interface LoginContract {
|
||||
}
|
||||
|
||||
interface DataModel {
|
||||
fun login(json: JSONObject, callback: Callback<BaseBean<LoginUser>>)
|
||||
//手机验证码
|
||||
fun sendPhoneCode(json: JSONObject, callback: Callback<BaseBean<SendCodeEntity>>)
|
||||
//手机号+验证码注册
|
||||
fun registerByPhone(json: JSONObject, callback: Callback<BaseBean<SendCodeEntity>>)
|
||||
//手机+密码登录
|
||||
fun loginByPhonePsd(json: JSONObject, callback: Callback<BaseBean<UserEntity>>)
|
||||
//手机+验证码登录
|
||||
fun loginByPhoneSms(json: JSONObject, callback: Callback<BaseBean<UserEntity>>)
|
||||
//手机号+验证码修改密码
|
||||
fun forgetPsdByPhone(json: JSONObject, callback: Callback<BaseBean<UserEntity>>)
|
||||
|
||||
//邮箱验证码
|
||||
fun sendEmailCode(json: JSONObject, callback: Callback<BaseBean<SendCodeEntity>>)
|
||||
//邮箱+验证码注册
|
||||
fun registerByEmail(json: JSONObject, callback: Callback<BaseBean<SendCodeEntity>>)
|
||||
//邮箱+密码登录
|
||||
fun loginByEmailPsd(json: JSONObject, callback: Callback<BaseBean<UserEntity>>)
|
||||
//邮箱+验证码登录
|
||||
fun loginByEmailSms(json: JSONObject, callback: Callback<BaseBean<UserEntity>>)
|
||||
//邮箱+验证码修改密码
|
||||
fun forgetPsdByEmail(json: JSONObject, callback: Callback<BaseBean<UserEntity>>)
|
||||
fun cancel()
|
||||
}
|
||||
|
||||
interface LoginView : IView {
|
||||
fun sendCodeSuccess(message: String)
|
||||
fun onRegisterSuccess(message: String)
|
||||
fun onForgetPsdSuccess(message: String)
|
||||
fun showUsernameError(message: String)
|
||||
fun showPasswordError(message: String)
|
||||
fun clearInputErrors()
|
||||
fun onLoginSuccess(user: LoginUser)
|
||||
fun onLoginSuccess(user: UserEntity)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -2,7 +2,8 @@ package com.juhabi.birds.login.mvp
|
||||
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import com.juhabi.birds.login.model.LoginUser
|
||||
import com.juhabi.birds.login.model.UserEntity
|
||||
import com.juhabi.birds.login.model.SendCodeEntity
|
||||
import com.juhabi.birds.network.ApiClient
|
||||
import com.juhabi.birds.network.BaseBean
|
||||
import com.juhabi.birds.network.NetworkManager
|
||||
@@ -13,45 +14,330 @@ import retrofit2.Response
|
||||
|
||||
class LoginImpl : LoginContract.DataModel {
|
||||
private val mainHandler = Handler(Looper.getMainLooper())
|
||||
private var loginCall: Call<BaseBean<LoginUser>>? = null
|
||||
private var loginCall: Call<BaseBean<UserEntity>>? = null
|
||||
|
||||
override fun login(
|
||||
private val calls = mutableSetOf<Call<*>>()
|
||||
|
||||
/**
|
||||
* 发送手机验证码
|
||||
*/
|
||||
override fun sendPhoneCode(json: JSONObject, callback: LoginContract.Callback<BaseBean<SendCodeEntity>>) {
|
||||
enqueueSendCodeCall(
|
||||
ApiClient.apiService.sendPhoneCode(
|
||||
NetworkManager.getToken(),
|
||||
NetworkManager.toRequestBody(json)
|
||||
),
|
||||
callback
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 手机号注册
|
||||
*/
|
||||
override fun registerByPhone(
|
||||
json: JSONObject,
|
||||
callback: LoginContract.Callback<BaseBean<LoginUser>>
|
||||
callback: LoginContract.Callback<BaseBean<SendCodeEntity>>
|
||||
) {
|
||||
enqueueSendCodeCall(
|
||||
ApiClient.apiService.registerByPhone(
|
||||
NetworkManager.getToken(),
|
||||
NetworkManager.toRequestBody(json)
|
||||
),
|
||||
callback
|
||||
)
|
||||
}
|
||||
|
||||
private fun enqueueSendCodeCall(
|
||||
call: Call<BaseBean<SendCodeEntity>>,
|
||||
callback: LoginContract.Callback<BaseBean<SendCodeEntity>>
|
||||
) {
|
||||
calls += call
|
||||
call.enqueue(object : Callback<BaseBean<SendCodeEntity>> {
|
||||
override fun onResponse(
|
||||
call: Call<BaseBean<SendCodeEntity>>,
|
||||
response: Response<BaseBean<SendCodeEntity>>
|
||||
) {
|
||||
calls -= call
|
||||
mainHandler.post {
|
||||
val bean = response.body()
|
||||
if (response.isSuccessful && bean != null) {
|
||||
callback.success(bean)
|
||||
} else {
|
||||
callback.fail("接口响应异常:${response.code()}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFailure(
|
||||
call: Call<BaseBean<SendCodeEntity>>,
|
||||
error: Throwable
|
||||
) {
|
||||
calls -= call
|
||||
if (!call.isCanceled) {
|
||||
mainHandler.post {
|
||||
callback.fail(error.message ?: "网络请求失败")
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
override fun loginByPhonePsd(
|
||||
json: JSONObject,
|
||||
callback: LoginContract.Callback<BaseBean<UserEntity>>
|
||||
) {
|
||||
enqueueLoginCall(
|
||||
ApiClient.apiService.loginByPhonePsd(
|
||||
NetworkManager.getToken(),
|
||||
NetworkManager.toRequestBody(json)
|
||||
),
|
||||
callback
|
||||
)
|
||||
}
|
||||
|
||||
override fun loginByPhoneSms(
|
||||
json: JSONObject,
|
||||
callback: LoginContract.Callback<BaseBean<UserEntity>>
|
||||
) {
|
||||
enqueueLoginCall(
|
||||
ApiClient.apiService.loginByPhoneSms(
|
||||
NetworkManager.getToken(),
|
||||
NetworkManager.toRequestBody(json)
|
||||
),
|
||||
callback
|
||||
)
|
||||
}
|
||||
|
||||
override fun forgetPsdByPhone(
|
||||
json: JSONObject,
|
||||
callback: LoginContract.Callback<BaseBean<UserEntity>>
|
||||
) {
|
||||
enqueueLoginCall(
|
||||
ApiClient.apiService.forgetPsdByPhone(
|
||||
NetworkManager.getToken(),
|
||||
NetworkManager.toRequestBody(json)
|
||||
),
|
||||
callback
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
override fun sendEmailCode(
|
||||
json: JSONObject,
|
||||
callback: LoginContract.Callback<BaseBean<SendCodeEntity>>
|
||||
) {
|
||||
val call = ApiClient.apiService.sendEmailCode(
|
||||
NetworkManager.getToken(),
|
||||
NetworkManager.toRequestBody(json)
|
||||
)
|
||||
calls += call
|
||||
call.enqueue(object : Callback<BaseBean<SendCodeEntity>> {
|
||||
override fun onResponse(
|
||||
call: Call<BaseBean<SendCodeEntity>>,
|
||||
response: Response<BaseBean<SendCodeEntity>>
|
||||
) {
|
||||
calls -= call
|
||||
mainHandler.post {
|
||||
val bean = response.body()
|
||||
if (response.isSuccessful && bean != null) {
|
||||
callback.success(bean)
|
||||
} else {
|
||||
callback.fail("接口响应异常:${response.code()}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFailure(call: Call<BaseBean<SendCodeEntity>>, error: Throwable) {
|
||||
calls -= call
|
||||
if (!call.isCanceled) {
|
||||
mainHandler.post {
|
||||
callback.fail(error.message ?: "网络请求失败")
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
override fun registerByEmail(
|
||||
json: JSONObject,
|
||||
callback: LoginContract.Callback<BaseBean<SendCodeEntity>>
|
||||
) {
|
||||
val call = ApiClient.apiService.registerByE(
|
||||
NetworkManager.getToken(),
|
||||
NetworkManager.toRequestBody(json)
|
||||
)
|
||||
calls += call
|
||||
call.enqueue(object : Callback<BaseBean<SendCodeEntity>> {
|
||||
override fun onResponse(
|
||||
call: Call<BaseBean<SendCodeEntity>>,
|
||||
response: Response<BaseBean<SendCodeEntity>>
|
||||
) {
|
||||
calls -= call
|
||||
mainHandler.post {
|
||||
val bean = response.body()
|
||||
if (response.isSuccessful && bean != null) {
|
||||
callback.success(bean)
|
||||
} else {
|
||||
callback.fail("接口响应异常:${response.code()}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFailure(call: Call<BaseBean<SendCodeEntity>>, error: Throwable) {
|
||||
calls -= call
|
||||
if (!call.isCanceled) {
|
||||
mainHandler.post {
|
||||
callback.fail(error.message ?: "网络请求失败")
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
override fun loginByEmailPsd(
|
||||
json: JSONObject,
|
||||
callback: LoginContract.Callback<BaseBean<UserEntity>>
|
||||
) {
|
||||
val call = ApiClient.apiService.loginByEmailPsd(
|
||||
NetworkManager.getToken(),
|
||||
NetworkManager.toRequestBody(json)
|
||||
)
|
||||
calls += call
|
||||
call.enqueue(object : Callback<BaseBean<UserEntity>> {
|
||||
override fun onResponse(
|
||||
call: Call<BaseBean<UserEntity>>,
|
||||
response: Response<BaseBean<UserEntity>>
|
||||
) {
|
||||
calls -= call
|
||||
mainHandler.post {
|
||||
val bean = response.body()
|
||||
if (response.isSuccessful && bean != null) {
|
||||
callback.success(bean)
|
||||
} else {
|
||||
callback.fail("接口响应异常:${response.code()}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFailure(call: Call<BaseBean<UserEntity>>, error: Throwable) {
|
||||
calls -= call
|
||||
if (!call.isCanceled) {
|
||||
mainHandler.post {
|
||||
callback.fail(error.message ?: "网络请求失败")
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
override fun loginByEmailSms(
|
||||
json: JSONObject,
|
||||
callback: LoginContract.Callback<BaseBean<UserEntity>>
|
||||
) {
|
||||
val call = ApiClient.apiService.loginByEmailSms(
|
||||
NetworkManager.getToken(),
|
||||
NetworkManager.toRequestBody(json)
|
||||
)
|
||||
calls += call
|
||||
call.enqueue(object : Callback<BaseBean<UserEntity>> {
|
||||
override fun onResponse(
|
||||
call: Call<BaseBean<UserEntity>>,
|
||||
response: Response<BaseBean<UserEntity>>
|
||||
) {
|
||||
calls -= call
|
||||
mainHandler.post {
|
||||
val bean = response.body()
|
||||
if (response.isSuccessful && bean != null) {
|
||||
callback.success(bean)
|
||||
} else {
|
||||
callback.fail("接口响应异常:${response.code()}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFailure(call: Call<BaseBean<UserEntity>>, error: Throwable) {
|
||||
calls -= call
|
||||
if (!call.isCanceled) {
|
||||
mainHandler.post {
|
||||
callback.fail(error.message ?: "网络请求失败")
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
override fun forgetPsdByEmail(
|
||||
json: JSONObject,
|
||||
callback: LoginContract.Callback<BaseBean<UserEntity>>
|
||||
) {
|
||||
val call = ApiClient.apiService.forgetPsdByEmail(
|
||||
NetworkManager.getToken(),
|
||||
NetworkManager.toRequestBody(json)
|
||||
)
|
||||
calls += call
|
||||
call.enqueue(object : Callback<BaseBean<UserEntity>> {
|
||||
override fun onResponse(
|
||||
call: Call<BaseBean<UserEntity>>,
|
||||
response: Response<BaseBean<UserEntity>>
|
||||
) {
|
||||
calls -= call
|
||||
mainHandler.post {
|
||||
val bean = response.body()
|
||||
if (response.isSuccessful && bean != null) {
|
||||
callback.success(bean)
|
||||
} else {
|
||||
callback.fail("接口响应异常:${response.code()}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFailure(call: Call<BaseBean<UserEntity>>, error: Throwable) {
|
||||
calls -= call
|
||||
if (!call.isCanceled) {
|
||||
mainHandler.post {
|
||||
callback.fail(error.message ?: "网络请求失败")
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun enqueueLoginCall(
|
||||
call: Call<BaseBean<UserEntity>>,
|
||||
callback: LoginContract.Callback<BaseBean<UserEntity>>
|
||||
) {
|
||||
loginCall?.cancel()
|
||||
loginCall = ApiClient.apiService
|
||||
.login(NetworkManager.getToken(), NetworkManager.toRequestBody(json))
|
||||
.also { call ->
|
||||
call.enqueue(object : Callback<BaseBean<LoginUser>> {
|
||||
override fun onResponse(
|
||||
call: Call<BaseBean<LoginUser>>,
|
||||
response: Response<BaseBean<LoginUser>>
|
||||
) {
|
||||
mainHandler.post {
|
||||
val bean = response.body()
|
||||
if (response.isSuccessful && bean != null) {
|
||||
callback.success(bean)
|
||||
} else {
|
||||
callback.fail("接口响应异常:${response.code()}")
|
||||
}
|
||||
loginCall = call
|
||||
call.enqueue(object : Callback<BaseBean<UserEntity>> {
|
||||
override fun onResponse(
|
||||
call: Call<BaseBean<UserEntity>>,
|
||||
response: Response<BaseBean<UserEntity>>
|
||||
) {
|
||||
mainHandler.post {
|
||||
val bean = response.body()
|
||||
if (response.isSuccessful && bean != null) {
|
||||
callback.success(bean)
|
||||
} else {
|
||||
callback.fail("接口响应异常:${response.code()}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFailure(call: Call<BaseBean<LoginUser>>, error: Throwable) {
|
||||
if (!call.isCanceled) {
|
||||
mainHandler.post {
|
||||
callback.fail(error.message ?: "网络请求失败")
|
||||
}
|
||||
override fun onFailure(call: Call<BaseBean<UserEntity>>, error: Throwable) {
|
||||
if (!call.isCanceled) {
|
||||
mainHandler.post {
|
||||
callback.fail(error.message ?: "网络请求失败")
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
override fun cancel() {
|
||||
loginCall?.cancel()
|
||||
loginCall = null
|
||||
calls.forEach { it.cancel() }
|
||||
calls.clear()
|
||||
mainHandler.removeCallbacksAndMessages(null)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,44 +1,31 @@
|
||||
package com.juhabi.birds.login.mvp
|
||||
|
||||
import com.juhabi.birds.base.BasePresenter
|
||||
import com.juhabi.birds.AppConfig
|
||||
import com.juhabi.birds.login.model.LoginUser
|
||||
import com.juhabi.birds.login.model.UserEntity
|
||||
import com.juhabi.birds.login.model.SendCodeEntity
|
||||
import com.juhabi.birds.network.BaseBean
|
||||
import org.json.JSONObject
|
||||
|
||||
class LoginPresenter(private val loginImpl: LoginImpl) : BasePresenter<LoginContract.LoginView>() {
|
||||
|
||||
fun login(username: String, password: String) {
|
||||
val currentView = view ?: return
|
||||
currentView.clearInputErrors()
|
||||
|
||||
if (username.isBlank()) {
|
||||
currentView.showUsernameError("请输入账号")
|
||||
return
|
||||
}
|
||||
if (password.isBlank()) {
|
||||
currentView.showPasswordError("请输入密码")
|
||||
return
|
||||
}
|
||||
|
||||
currentView.showLoading()
|
||||
fun getPhoneSmsCode(phoneNumber: String, sendCodeSceneRegister: String) {
|
||||
val json = JSONObject();
|
||||
json.put("grantType", "password")
|
||||
json.put("username", username.trim())
|
||||
json.put("password", password)
|
||||
json.put("clientId", AppConfig.APP_CLIENT_ID)
|
||||
json.put("userType", AppConfig.APP_USER_TYPE)
|
||||
loginImpl.login(
|
||||
json.put("phoneNumber", phoneNumber)
|
||||
json.put("scene", sendCodeSceneRegister)
|
||||
loginImpl.sendPhoneCode(
|
||||
json,
|
||||
object : LoginContract.Callback<BaseBean<LoginUser>> {
|
||||
override fun success(data: BaseBean<LoginUser>) {
|
||||
object : LoginContract.Callback<BaseBean<SendCodeEntity>> {
|
||||
override fun success(data: BaseBean<SendCodeEntity>) {
|
||||
val attachedView = view ?: return
|
||||
attachedView.hideLoading()
|
||||
val user = data.data
|
||||
if ((data.code == 0 || data.code == 200) && user != null) {
|
||||
attachedView.onLoginSuccess(user)
|
||||
// 发码接口通常只返回 code/msg,data 可能为 null,不能依赖 data 非空
|
||||
if (data.code == 0 || data.code == 200) {
|
||||
attachedView.sendCodeSuccess(
|
||||
data.message.ifBlank { "验证码已发送" }
|
||||
)
|
||||
} else {
|
||||
attachedView.showError(data.message.ifBlank { "登录失败" })
|
||||
attachedView.showError(data.message.ifBlank { "服务异常" })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,8 +39,310 @@ class LoginPresenter(private val loginImpl: LoginImpl) : BasePresenter<LoginCont
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 手机 + 密码登录
|
||||
* 入参:phoneNumber、password
|
||||
*/
|
||||
fun loginByPhonePsd(phoneNumber: String, password: String) {
|
||||
val currentView = view ?: return
|
||||
currentView.showLoading()
|
||||
val json = JSONObject()
|
||||
json.put("phoneNumber", phoneNumber.trim())
|
||||
json.put("password", password)
|
||||
loginImpl.loginByPhonePsd(
|
||||
json,
|
||||
createLoginCallback()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 手机 + 验证码登录
|
||||
* 入参:phoneNumber、code
|
||||
*/
|
||||
fun loginByPhoneSms(phoneNumber: String, code: String) {
|
||||
val currentView = view ?: return
|
||||
currentView.showLoading()
|
||||
val json = JSONObject()
|
||||
json.put("phoneNumber", phoneNumber.trim())
|
||||
json.put("code", code.trim())
|
||||
loginImpl.loginByPhoneSms(
|
||||
json,
|
||||
createLoginCallback()
|
||||
)
|
||||
}
|
||||
|
||||
private fun createLoginCallback(): LoginContract.Callback<BaseBean<UserEntity>> {
|
||||
return object : LoginContract.Callback<BaseBean<UserEntity>> {
|
||||
override fun success(data: BaseBean<UserEntity>) {
|
||||
val attachedView = view ?: return
|
||||
attachedView.hideLoading()
|
||||
val user = data.data
|
||||
if ((data.code == 0 || data.code == 200) && user != null) {
|
||||
attachedView.onLoginSuccess(user)
|
||||
} else {
|
||||
attachedView.showError(data.message.ifBlank { "登录失败" })
|
||||
}
|
||||
}
|
||||
|
||||
override fun fail(message: String) {
|
||||
view?.apply {
|
||||
hideLoading()
|
||||
showError(message)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
loginImpl.cancel()
|
||||
super.onDestroy()
|
||||
}
|
||||
|
||||
/**
|
||||
* 手机号注册
|
||||
*/
|
||||
fun registerByPhone(phone: String, code: String, password: String) {
|
||||
val attachedView = view ?: return
|
||||
attachedView.showLoading()
|
||||
val json = JSONObject()
|
||||
json.put("phoneNumber", phone.trim())
|
||||
json.put("code", code.trim())
|
||||
json.put("password", password)
|
||||
loginImpl.registerByPhone(
|
||||
json,
|
||||
object : LoginContract.Callback<BaseBean<SendCodeEntity>> {
|
||||
override fun success(data: BaseBean<SendCodeEntity>) {
|
||||
val currentView = view ?: return
|
||||
currentView.hideLoading()
|
||||
if (data.code == 0 || data.code == 200) {
|
||||
currentView.onRegisterSuccess(
|
||||
data.message.ifBlank { "注册成功" }
|
||||
)
|
||||
} else {
|
||||
currentView.showError(data.message.ifBlank { "注册失败" })
|
||||
}
|
||||
}
|
||||
|
||||
override fun fail(message: String) {
|
||||
view?.apply {
|
||||
hideLoading()
|
||||
showError(message)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 手机号 + 验证码修改密码
|
||||
* 入参:phoneNumber、code、newPassword
|
||||
*/
|
||||
fun forgetPsdByPhone(phoneNumber: String, code: String, newPassword: String) {
|
||||
val attachedView = view ?: return
|
||||
attachedView.showLoading()
|
||||
val json = JSONObject()
|
||||
json.put("phoneNumber", phoneNumber.trim())
|
||||
json.put("code", code.trim())
|
||||
json.put("newPassword", newPassword)
|
||||
loginImpl.forgetPsdByPhone(
|
||||
json,
|
||||
object : LoginContract.Callback<BaseBean<UserEntity>> {
|
||||
override fun success(data: BaseBean<UserEntity>) {
|
||||
val currentView = view ?: return
|
||||
currentView.hideLoading()
|
||||
// 重置密码接口 data 可能为空,以 code 判断成功
|
||||
if (data.code == 0 || data.code == 200) {
|
||||
currentView.onForgetPsdSuccess(
|
||||
data.message.ifBlank { "密码修改成功" }
|
||||
)
|
||||
} else {
|
||||
currentView.showError(data.message.ifBlank { "密码修改失败" })
|
||||
}
|
||||
}
|
||||
|
||||
override fun fail(message: String) {
|
||||
view?.apply {
|
||||
hideLoading()
|
||||
showError(message)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取邮箱验证码
|
||||
* 入参:email、scene
|
||||
*/
|
||||
fun getEmailSmsCode(email: String, scene: String) {
|
||||
val json = JSONObject()
|
||||
json.put("email", email.trim())
|
||||
json.put("scene", scene)
|
||||
loginImpl.sendEmailCode(
|
||||
json,
|
||||
object : LoginContract.Callback<BaseBean<SendCodeEntity>> {
|
||||
override fun success(data: BaseBean<SendCodeEntity>) {
|
||||
val attachedView = view ?: return
|
||||
attachedView.hideLoading()
|
||||
if (data.code == 0 || data.code == 200) {
|
||||
attachedView.sendCodeSuccess(
|
||||
data.message.ifBlank { "验证码已发送" }
|
||||
)
|
||||
} else {
|
||||
attachedView.showError(data.message.ifBlank { "服务异常" })
|
||||
}
|
||||
}
|
||||
|
||||
override fun fail(message: String) {
|
||||
view?.apply {
|
||||
hideLoading()
|
||||
showError(message)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 邮箱注册
|
||||
* 入参:email、code、password、nickName
|
||||
*/
|
||||
fun registerByEmail(email: String, code: String, password: String, nickName: String) {
|
||||
val attachedView = view ?: return
|
||||
attachedView.showLoading()
|
||||
val json = JSONObject()
|
||||
json.put("email", email.trim())
|
||||
json.put("code", code.trim())
|
||||
json.put("password", password)
|
||||
json.put("nickName", nickName.trim())
|
||||
loginImpl.registerByEmail(
|
||||
json,
|
||||
object : LoginContract.Callback<BaseBean<SendCodeEntity>> {
|
||||
override fun success(data: BaseBean<SendCodeEntity>) {
|
||||
val currentView = view ?: return
|
||||
currentView.hideLoading()
|
||||
if (data.code == 0 || data.code == 200) {
|
||||
currentView.onRegisterSuccess(
|
||||
data.message.ifBlank { "注册成功" }
|
||||
)
|
||||
} else {
|
||||
currentView.showError(data.message.ifBlank { "注册失败" })
|
||||
}
|
||||
}
|
||||
|
||||
override fun fail(message: String) {
|
||||
view?.apply {
|
||||
hideLoading()
|
||||
showError(message)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 邮箱 + 密码登录
|
||||
* 入参:email、password
|
||||
*/
|
||||
fun loginByEmailPsd(email: String, password: String) {
|
||||
val attachedView = view ?: return
|
||||
attachedView.showLoading()
|
||||
val json = JSONObject()
|
||||
json.put("email", email.trim())
|
||||
json.put("password", password)
|
||||
loginImpl.loginByEmailPsd(
|
||||
json,
|
||||
object : LoginContract.Callback<BaseBean<UserEntity>> {
|
||||
override fun success(data: BaseBean<UserEntity>) {
|
||||
val currentView = view ?: return
|
||||
currentView.hideLoading()
|
||||
val user = data.data
|
||||
if ((data.code == 0 || data.code == 200) && user != null) {
|
||||
currentView.onLoginSuccess(user)
|
||||
} else {
|
||||
currentView.showError(data.message.ifBlank { "登录失败" })
|
||||
}
|
||||
}
|
||||
|
||||
override fun fail(message: String) {
|
||||
view?.apply {
|
||||
hideLoading()
|
||||
showError(message)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 邮箱 + 验证码登录
|
||||
* 入参:email、code
|
||||
*/
|
||||
fun loginByEmailSms(email: String, code: String) {
|
||||
val attachedView = view ?: return
|
||||
attachedView.showLoading()
|
||||
val json = JSONObject()
|
||||
json.put("email", email.trim())
|
||||
json.put("code", code.trim())
|
||||
loginImpl.loginByEmailSms(
|
||||
json,
|
||||
object : LoginContract.Callback<BaseBean<UserEntity>> {
|
||||
override fun success(data: BaseBean<UserEntity>) {
|
||||
val currentView = view ?: return
|
||||
currentView.hideLoading()
|
||||
val user = data.data
|
||||
if ((data.code == 0 || data.code == 200) && user != null) {
|
||||
currentView.onLoginSuccess(user)
|
||||
} else {
|
||||
currentView.showError(data.message.ifBlank { "登录失败" })
|
||||
}
|
||||
}
|
||||
|
||||
override fun fail(message: String) {
|
||||
view?.apply {
|
||||
hideLoading()
|
||||
showError(message)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 邮箱 + 验证码修改密码
|
||||
* 入参:email、code、newPassword
|
||||
*/
|
||||
fun forgetPsdByEmail(email: String, code: String, newPassword: String) {
|
||||
val attachedView = view ?: return
|
||||
attachedView.showLoading()
|
||||
val json = JSONObject()
|
||||
json.put("email", email.trim())
|
||||
json.put("code", code.trim())
|
||||
json.put("newPassword", newPassword)
|
||||
loginImpl.forgetPsdByEmail(
|
||||
json,
|
||||
object : LoginContract.Callback<BaseBean<UserEntity>> {
|
||||
override fun success(data: BaseBean<UserEntity>) {
|
||||
val currentView = view ?: return
|
||||
currentView.hideLoading()
|
||||
if (data.code == 0 || data.code == 200) {
|
||||
currentView.onForgetPsdSuccess(
|
||||
data.message.ifBlank { "密码修改成功" }
|
||||
)
|
||||
} else {
|
||||
currentView.showError(data.message.ifBlank { "密码修改失败" })
|
||||
}
|
||||
}
|
||||
|
||||
override fun fail(message: String) {
|
||||
view?.apply {
|
||||
hideLoading()
|
||||
showError(message)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.juhabi.birds.network
|
||||
|
||||
import com.juhabi.birds.login.model.LoginUser
|
||||
import com.juhabi.birds.login.model.UserEntity
|
||||
import com.juhabi.birds.login.model.SendCodeEntity
|
||||
import com.juhabi.birds.main.model.AppVersionInfo
|
||||
import com.juhabi.birds.mine.model.MineUserInfo
|
||||
import okhttp3.RequestBody
|
||||
@@ -15,8 +16,105 @@ import retrofit2.http.POST
|
||||
* 项目统一接口定义。所有业务接口地址集中维护在这里。
|
||||
*/
|
||||
interface ApiService {
|
||||
@POST("auth/login")
|
||||
fun login(@HeaderMap headers: Map<String, String>, @Body requestBody: RequestBody): Call<BaseBean<LoginUser>>
|
||||
|
||||
|
||||
//发送手机验证码
|
||||
@POST("app/auth/sms/code")
|
||||
fun sendPhoneCode(@HeaderMap headers: Map<String, String>, @Body requestBody: RequestBody): Call<BaseBean<SendCodeEntity>>
|
||||
|
||||
//手机号注册
|
||||
@POST("app/auth/register")
|
||||
fun registerByPhone(@HeaderMap headers: Map<String, String>, @Body requestBody: RequestBody): Call<BaseBean<SendCodeEntity>>
|
||||
|
||||
|
||||
//手机+密码登录
|
||||
/** 入参
|
||||
* {
|
||||
* "phoneNumber": "18764689178",
|
||||
* "password": "Zz123456"
|
||||
* }
|
||||
*/
|
||||
@POST("app/auth/login")
|
||||
fun loginByPhonePsd(@HeaderMap headers: Map<String, String>, @Body requestBody: RequestBody): Call<BaseBean<UserEntity>>
|
||||
|
||||
//手机+验证码
|
||||
/**入参
|
||||
* {
|
||||
* "phoneNumber": "string",
|
||||
* "code": "string"
|
||||
* }
|
||||
*/
|
||||
@POST("app/auth/sms-login")
|
||||
fun loginByPhoneSms(@HeaderMap headers: Map<String, String>, @Body requestBody: RequestBody): Call<BaseBean<UserEntity>>
|
||||
|
||||
//手机号+验证码 修改密码
|
||||
/**
|
||||
* {
|
||||
* "phoneNumber": "string",
|
||||
* "code": "string",
|
||||
* "newPassword": "string"
|
||||
* }
|
||||
*/
|
||||
@POST("app/auth/reset-pwd")
|
||||
fun forgetPsdByPhone(@HeaderMap headers: Map<String, String>, @Body requestBody: RequestBody): Call<BaseBean<UserEntity>>
|
||||
|
||||
|
||||
|
||||
//发送邮箱验证码
|
||||
/**
|
||||
* {
|
||||
* "email": "string",
|
||||
* "scene": "string"
|
||||
* }
|
||||
*/
|
||||
@POST("app/auth/email/code")
|
||||
fun sendEmailCode(@HeaderMap headers: Map<String, String>, @Body requestBody: RequestBody): Call<BaseBean<SendCodeEntity>>
|
||||
|
||||
//邮箱注册
|
||||
/**
|
||||
* {
|
||||
* "email": "string",
|
||||
* "code": "string",
|
||||
* "password": "string",
|
||||
* "nickName": "string"
|
||||
* }
|
||||
*/
|
||||
@POST("app/auth/email/register")
|
||||
fun registerByE(@HeaderMap headers: Map<String, String>, @Body requestBody: RequestBody): Call<BaseBean<SendCodeEntity>>
|
||||
|
||||
|
||||
//邮箱+密码登录
|
||||
/** 入参
|
||||
* {
|
||||
* "email": "string",
|
||||
* "password": "string"
|
||||
* }
|
||||
*/
|
||||
@POST("app/auth/email/login")
|
||||
fun loginByEmailPsd(@HeaderMap headers: Map<String, String>, @Body requestBody: RequestBody): Call<BaseBean<UserEntity>>
|
||||
|
||||
//邮箱+验证码登录
|
||||
/**入参
|
||||
{
|
||||
"email": "string",
|
||||
"code": "string"
|
||||
}
|
||||
*/
|
||||
@POST("app/auth/email/code-login")
|
||||
fun loginByEmailSms(@HeaderMap headers: Map<String, String>, @Body requestBody: RequestBody): Call<BaseBean<UserEntity>>
|
||||
|
||||
//邮箱+验证码 修改密码
|
||||
/**
|
||||
* {
|
||||
* "email": "string",
|
||||
* "code": "string",
|
||||
* "newPassword": "string"
|
||||
* }
|
||||
*/
|
||||
@POST("app/auth/email/reset-pwd")
|
||||
fun forgetPsdByEmail(@HeaderMap headers: Map<String, String>, @Body requestBody: RequestBody): Call<BaseBean<UserEntity>>
|
||||
|
||||
|
||||
|
||||
@GET("app/v1/getUserInfo")
|
||||
fun getMineUserInfo(@HeaderMap headers: Map<String, String>, @QueryMap params: Map<String, String>): Call<BaseBean<MineUserInfo>>
|
||||
|
||||
Reference in New Issue
Block a user