登录相关,首次提交
@@ -65,5 +65,5 @@ dependencies {
|
|||||||
androidTestImplementation libs.androidx.espresso.core
|
androidTestImplementation libs.androidx.espresso.core
|
||||||
androidTestImplementation libs.androidx.junit
|
androidTestImplementation libs.androidx.junit
|
||||||
//屏幕适配
|
//屏幕适配
|
||||||
implementation 'me.jessyan:autosize:1.1.2'
|
implementation 'me.jessyan:autosize:1.2.1'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,7 +41,7 @@
|
|||||||
android:exported="false" />
|
android:exported="false" />
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".main.MainActivity"
|
android:name=".login.WelcomeActivity"
|
||||||
android:exported="true">
|
android:exported="true">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
@@ -49,10 +49,24 @@
|
|||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
|
<activity
|
||||||
|
android:name=".main.MainActivity"
|
||||||
|
android:exported="false" />
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".login.LoginActivity"
|
android:name=".login.LoginActivity"
|
||||||
android:exported="false" />
|
android:exported="false" />
|
||||||
|
|
||||||
|
<activity
|
||||||
|
android:name=".login.RegisterActivity"
|
||||||
|
android:exported="false" />
|
||||||
|
|
||||||
|
<activity
|
||||||
|
android:name=".login.ForgetPsdActivity"
|
||||||
|
android:exported="false" />
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<provider
|
<provider
|
||||||
android:name="androidx.core.content.FileProvider"
|
android:name="androidx.core.content.FileProvider"
|
||||||
android:authorities="${applicationId}.fileprovider"
|
android:authorities="${applicationId}.fileprovider"
|
||||||
|
|||||||
@@ -1,11 +1,21 @@
|
|||||||
package com.juhabi.birds
|
package com.juhabi.birds
|
||||||
|
|
||||||
object AppConfig {
|
object AppConfig {
|
||||||
const val BASE_URL = "http://47.97.217.123:8081/"
|
// const val BASE_URL = "http://47.97.217.123:8081"
|
||||||
const val APP_CLIENT_ID = "428a8310cd442757ae699df5d894f051"
|
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 APP_USER_TYPE = "app_user"
|
||||||
const val CONTENT_LANGUAGE = "zh_CN"
|
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
|
@Volatile
|
||||||
var userToken: String = ""
|
var userToken: String = ""
|
||||||
|
//是否登录
|
||||||
|
var USER_LOGIN: Boolean = false;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ import android.app.Application
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import com.juhabi.birds.network.TokenManager
|
||||||
|
import com.juhabi.birds.util.SharedPreferencesUtil
|
||||||
import com.juhabi.birds.util.manager.UserInfoManager
|
import com.juhabi.birds.util.manager.UserInfoManager
|
||||||
import me.jessyan.autosize.AutoSize
|
import me.jessyan.autosize.AutoSize
|
||||||
import me.jessyan.autosize.AutoSizeConfig
|
import me.jessyan.autosize.AutoSizeConfig
|
||||||
@@ -36,9 +38,21 @@ class MyApplication : Application(), Application.ActivityLifecycleCallbacks {
|
|||||||
/** Add application-wide, privacy-safe SDK initialization here. */
|
/** Add application-wide, privacy-safe SDK initialization here. */
|
||||||
private fun initialize() {
|
private fun initialize() {
|
||||||
UserInfoManager.initialize(this)
|
UserInfoManager.initialize(this)
|
||||||
|
restoreLoginSession()
|
||||||
// NetworkManager is created lazily by ApiClient, so it needs no eager initialization.
|
// 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) {
|
override fun onActivityResumed(activity: Activity) {
|
||||||
currentActivity = activity
|
currentActivity = activity
|
||||||
}
|
}
|
||||||
@@ -80,6 +94,8 @@ class MyApplication : Application(), Application.ActivityLifecycleCallbacks {
|
|||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
private const val KEY_USER_LOGIN = "user_login"
|
||||||
|
|
||||||
lateinit var instance: MyApplication
|
lateinit var instance: MyApplication
|
||||||
private set
|
private set
|
||||||
|
|
||||||
|
|||||||
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
|
package com.juhabi.birds.login
|
||||||
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.os.CountDownTimer
|
||||||
|
import android.text.InputType
|
||||||
import android.view.LayoutInflater
|
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.base.BaseActivity
|
||||||
import com.juhabi.birds.databinding.ActivityLoginBinding
|
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.LoginContract
|
||||||
import com.juhabi.birds.login.mvp.LoginImpl
|
import com.juhabi.birds.login.mvp.LoginImpl
|
||||||
import com.juhabi.birds.login.mvp.LoginPresenter
|
import com.juhabi.birds.login.mvp.LoginPresenter
|
||||||
import com.juhabi.birds.network.TokenManager
|
|
||||||
import com.juhabi.birds.mine.MineCenterActivity
|
import com.juhabi.birds.mine.MineCenterActivity
|
||||||
|
import com.juhabi.birds.network.TokenManager
|
||||||
|
import com.juhabi.birds.util.SharedPreferencesUtil
|
||||||
import com.juhabi.birds.util.ToastUtil
|
import com.juhabi.birds.util.ToastUtil
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 登录
|
||||||
|
*/
|
||||||
class LoginActivity : BaseActivity<ActivityLoginBinding, LoginPresenter>(),
|
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 {
|
override fun createBinding(inflater: LayoutInflater): ActivityLoginBinding {
|
||||||
return ActivityLoginBinding.inflate(inflater)
|
return ActivityLoginBinding.inflate(inflater)
|
||||||
@@ -24,48 +39,176 @@ class LoginActivity : BaseActivity<ActivityLoginBinding, LoginPresenter>(),
|
|||||||
return LoginPresenter(LoginImpl())
|
return LoginPresenter(LoginImpl())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun initWindows() {
|
||||||
|
ImmersionBar.with(this)
|
||||||
|
.navigationBarColor(R.color.color_zhu)
|
||||||
|
.navigationBarDarkIcon(true)
|
||||||
|
.init()
|
||||||
|
}
|
||||||
|
|
||||||
override fun initView(savedInstanceState: Bundle?) {
|
override fun initView(savedInstanceState: Bundle?) {
|
||||||
// if (TokenManager.get(this).isNotBlank()) {
|
listOf(
|
||||||
// startActivity(Intent(this, MineCenterActivity::class.java))
|
binding.tvChangeCode,
|
||||||
// finish()
|
binding.forgotPasswordButton,
|
||||||
// return
|
binding.passwordVisibilityButton,
|
||||||
// }
|
binding.getCodeButton,
|
||||||
if(binding.usernameEditText.text.toString().isNotBlank()){
|
binding.loginButton,
|
||||||
ToastUtil.showShort(mContext,"");
|
binding.registerButton,
|
||||||
|
).forEach { button ->
|
||||||
|
button.setOnClickListener(this)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
return
|
||||||
}
|
}
|
||||||
binding.loginButton.setOnClickListener {
|
presenter?.getPhoneSmsCode(phone, AppConfig.SEND_CODE_SCENE_LOGIN)
|
||||||
presenter?.login(
|
}
|
||||||
binding.usernameEditText.text?.toString().orEmpty(),
|
|
||||||
binding.passwordEditText.text?.toString().orEmpty()
|
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) {
|
override fun showUsernameError(message: String) {
|
||||||
binding.usernameLayout.error = message
|
ToastUtil.showShort(mContext, message)
|
||||||
binding.usernameEditText.requestFocus()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun showPasswordError(message: String) {
|
override fun showPasswordError(message: String) {
|
||||||
binding.passwordLayout.error = message
|
ToastUtil.showShort(mContext, message)
|
||||||
binding.passwordEditText.requestFocus()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun clearInputErrors() {
|
override fun clearInputErrors() {
|
||||||
binding.usernameLayout.error = null
|
|
||||||
binding.passwordLayout.error = null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onLoginSuccess(user: LoginUser) {
|
override fun onLoginSuccess(user: UserEntity) {
|
||||||
TokenManager.save(this, user.accessToken)
|
val token = user.token.trim()
|
||||||
binding.resultTextView.text = "登录成功,Token 已保存"
|
// SharedPreferences 持久化 token,并同步到内存 AppConfig.userToken
|
||||||
showMessage("登录成功")
|
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))
|
startActivity(Intent(this, MineCenterActivity::class.java))
|
||||||
finish()
|
finish()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun showError(message: String) {
|
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
@@ -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
@@ -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
@@ -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
|
package com.juhabi.birds.login.mvp
|
||||||
|
|
||||||
import com.juhabi.birds.base.IView
|
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 com.juhabi.birds.network.BaseBean
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
|
|
||||||
@@ -12,15 +13,38 @@ interface LoginContract {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface DataModel {
|
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()
|
fun cancel()
|
||||||
}
|
}
|
||||||
|
|
||||||
interface LoginView : IView {
|
interface LoginView : IView {
|
||||||
|
fun sendCodeSuccess(message: String)
|
||||||
|
fun onRegisterSuccess(message: String)
|
||||||
|
fun onForgetPsdSuccess(message: String)
|
||||||
fun showUsernameError(message: String)
|
fun showUsernameError(message: String)
|
||||||
fun showPasswordError(message: String)
|
fun showPasswordError(message: String)
|
||||||
fun clearInputErrors()
|
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.Handler
|
||||||
import android.os.Looper
|
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.ApiClient
|
||||||
import com.juhabi.birds.network.BaseBean
|
import com.juhabi.birds.network.BaseBean
|
||||||
import com.juhabi.birds.network.NetworkManager
|
import com.juhabi.birds.network.NetworkManager
|
||||||
@@ -13,20 +14,304 @@ import retrofit2.Response
|
|||||||
|
|
||||||
class LoginImpl : LoginContract.DataModel {
|
class LoginImpl : LoginContract.DataModel {
|
||||||
private val mainHandler = Handler(Looper.getMainLooper())
|
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,
|
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?.cancel()
|
||||||
loginCall = ApiClient.apiService
|
loginCall = call
|
||||||
.login(NetworkManager.getToken(), NetworkManager.toRequestBody(json))
|
call.enqueue(object : Callback<BaseBean<UserEntity>> {
|
||||||
.also { call ->
|
|
||||||
call.enqueue(object : Callback<BaseBean<LoginUser>> {
|
|
||||||
override fun onResponse(
|
override fun onResponse(
|
||||||
call: Call<BaseBean<LoginUser>>,
|
call: Call<BaseBean<UserEntity>>,
|
||||||
response: Response<BaseBean<LoginUser>>
|
response: Response<BaseBean<UserEntity>>
|
||||||
) {
|
) {
|
||||||
mainHandler.post {
|
mainHandler.post {
|
||||||
val bean = response.body()
|
val bean = response.body()
|
||||||
@@ -38,7 +323,7 @@ class LoginImpl : LoginContract.DataModel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onFailure(call: Call<BaseBean<LoginUser>>, error: Throwable) {
|
override fun onFailure(call: Call<BaseBean<UserEntity>>, error: Throwable) {
|
||||||
if (!call.isCanceled) {
|
if (!call.isCanceled) {
|
||||||
mainHandler.post {
|
mainHandler.post {
|
||||||
callback.fail(error.message ?: "网络请求失败")
|
callback.fail(error.message ?: "网络请求失败")
|
||||||
@@ -47,11 +332,12 @@ class LoginImpl : LoginContract.DataModel {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
override fun cancel() {
|
override fun cancel() {
|
||||||
loginCall?.cancel()
|
loginCall?.cancel()
|
||||||
loginCall = null
|
loginCall = null
|
||||||
|
calls.forEach { it.cancel() }
|
||||||
|
calls.clear()
|
||||||
mainHandler.removeCallbacksAndMessages(null)
|
mainHandler.removeCallbacksAndMessages(null)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,37 +1,80 @@
|
|||||||
package com.juhabi.birds.login.mvp
|
package com.juhabi.birds.login.mvp
|
||||||
|
|
||||||
import com.juhabi.birds.base.BasePresenter
|
import com.juhabi.birds.base.BasePresenter
|
||||||
import com.juhabi.birds.AppConfig
|
import com.juhabi.birds.login.model.UserEntity
|
||||||
import com.juhabi.birds.login.model.LoginUser
|
import com.juhabi.birds.login.model.SendCodeEntity
|
||||||
import com.juhabi.birds.network.BaseBean
|
import com.juhabi.birds.network.BaseBean
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
|
|
||||||
class LoginPresenter(private val loginImpl: LoginImpl) : BasePresenter<LoginContract.LoginView>() {
|
class LoginPresenter(private val loginImpl: LoginImpl) : BasePresenter<LoginContract.LoginView>() {
|
||||||
|
|
||||||
fun login(username: String, password: String) {
|
|
||||||
val currentView = view ?: return
|
|
||||||
currentView.clearInputErrors()
|
|
||||||
|
|
||||||
if (username.isBlank()) {
|
fun getPhoneSmsCode(phoneNumber: String, sendCodeSceneRegister: String) {
|
||||||
currentView.showUsernameError("请输入账号")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (password.isBlank()) {
|
|
||||||
currentView.showPasswordError("请输入密码")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
currentView.showLoading()
|
|
||||||
val json = JSONObject();
|
val json = JSONObject();
|
||||||
json.put("grantType", "password")
|
json.put("phoneNumber", phoneNumber)
|
||||||
json.put("username", username.trim())
|
json.put("scene", sendCodeSceneRegister)
|
||||||
json.put("password", password)
|
loginImpl.sendPhoneCode(
|
||||||
json.put("clientId", AppConfig.APP_CLIENT_ID)
|
|
||||||
json.put("userType", AppConfig.APP_USER_TYPE)
|
|
||||||
loginImpl.login(
|
|
||||||
json,
|
json,
|
||||||
object : LoginContract.Callback<BaseBean<LoginUser>> {
|
object : LoginContract.Callback<BaseBean<SendCodeEntity>> {
|
||||||
override fun success(data: BaseBean<LoginUser>) {
|
override fun success(data: BaseBean<SendCodeEntity>) {
|
||||||
|
val attachedView = view ?: return
|
||||||
|
attachedView.hideLoading()
|
||||||
|
// 发码接口通常只返回 code/msg,data 可能为 null,不能依赖 data 非空
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 手机 + 密码登录
|
||||||
|
* 入参: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
|
val attachedView = view ?: return
|
||||||
attachedView.hideLoading()
|
attachedView.hideLoading()
|
||||||
val user = data.data
|
val user = data.data
|
||||||
@@ -49,11 +92,257 @@ class LoginPresenter(private val loginImpl: LoginImpl) : BasePresenter<LoginCont
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
loginImpl.cancel()
|
loginImpl.cancel()
|
||||||
super.onDestroy()
|
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
|
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.main.model.AppVersionInfo
|
||||||
import com.juhabi.birds.mine.model.MineUserInfo
|
import com.juhabi.birds.mine.model.MineUserInfo
|
||||||
import okhttp3.RequestBody
|
import okhttp3.RequestBody
|
||||||
@@ -15,8 +16,105 @@ import retrofit2.http.POST
|
|||||||
* 项目统一接口定义。所有业务接口地址集中维护在这里。
|
* 项目统一接口定义。所有业务接口地址集中维护在这里。
|
||||||
*/
|
*/
|
||||||
interface ApiService {
|
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")
|
@GET("app/v1/getUserInfo")
|
||||||
fun getMineUserInfo(@HeaderMap headers: Map<String, String>, @QueryMap params: Map<String, String>): Call<BaseBean<MineUserInfo>>
|
fun getMineUserInfo(@HeaderMap headers: Map<String, String>, @QueryMap params: Map<String, String>): Call<BaseBean<MineUserInfo>>
|
||||||
|
|||||||
31
app/src/main/res/layout/active_welcome.xml
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="@color/color_zhu"
|
||||||
|
android:gravity="center_horizontal">
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="210dp"
|
||||||
|
android:src="@mipmap/icon_app_logo"/>
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="40dp"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:textSize="24sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:text="@string/app_chinese_name"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="40dp"
|
||||||
|
android:gravity="center"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:textSize="12sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:text="@string/app_name"/>
|
||||||
|
</LinearLayout>
|
||||||
@@ -1,88 +1,228 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:background="#F5F7FA"
|
android:background="@color/color_zhu"
|
||||||
android:padding="24dp">
|
android:fillViewport="true"
|
||||||
|
android:overScrollMode="never">
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/loginContent"
|
android:layout_width="match_parent"
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
android:paddingStart="10dp"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
android:paddingEnd="10dp"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
android:paddingBottom="32dp">
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
|
||||||
app:layout_constraintVertical_bias="0.38">
|
|
||||||
|
|
||||||
<TextView
|
<ImageView
|
||||||
|
android:id="@+id/brandLogo"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/login_title"
|
android:layout_gravity="center_horizontal"
|
||||||
android:textColor="#18212F"
|
android:layout_marginTop="110dp"
|
||||||
android:textSize="28sp"
|
android:contentDescription="@string/app_chinese_name"
|
||||||
android:textStyle="bold" />
|
android:src="@mipmap/icon_app_logo" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:layout_width="wrap_content"
|
android:id="@+id/brandName"
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="8dp"
|
|
||||||
android:text="@string/login_subtitle"
|
|
||||||
android:textColor="#667085"
|
|
||||||
android:textSize="15sp" />
|
|
||||||
|
|
||||||
<com.google.android.material.textfield.TextInputLayout
|
|
||||||
android:id="@+id/usernameLayout"
|
|
||||||
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="32dp"
|
|
||||||
android:hint="@string/login_username">
|
|
||||||
|
|
||||||
<com.google.android.material.textfield.TextInputEditText
|
|
||||||
android:id="@+id/usernameEditText"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:inputType="phone"
|
|
||||||
android:maxLines="1" />
|
|
||||||
</com.google.android.material.textfield.TextInputLayout>
|
|
||||||
|
|
||||||
<com.google.android.material.textfield.TextInputLayout
|
|
||||||
android:id="@+id/passwordLayout"
|
|
||||||
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
|
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="16dp"
|
android:layout_marginTop="16dp"
|
||||||
android:hint="@string/login_password"
|
android:gravity="center"
|
||||||
app:endIconMode="password_toggle">
|
android:text="@string/app_chinese_name"
|
||||||
|
android:textColor="@color/color_white"
|
||||||
<com.google.android.material.textfield.TextInputEditText
|
android:textSize="23sp"
|
||||||
android:id="@+id/passwordEditText"
|
android:textStyle="bold" />
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:inputType="textPassword"
|
|
||||||
android:maxLines="1" />
|
|
||||||
</com.google.android.material.textfield.TextInputLayout>
|
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
|
||||||
android:id="@+id/loginButton"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="52dp"
|
|
||||||
android:layout_marginTop="24dp"
|
|
||||||
android:text="@string/login_button"
|
|
||||||
android:textSize="16sp" />
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/resultTextView"
|
android:id="@+id/brandSubtitle"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="20dp"
|
android:layout_marginTop="20dp"
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:text="@string/login_demo_hint"
|
android:text="@string/app_name"
|
||||||
android:textColor="#667085"
|
android:textColor="@color/color_DDE6F5"
|
||||||
android:textSize="14sp" />
|
android:textSize="14sp" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="50dp"
|
||||||
|
android:layout_marginTop="54dp"
|
||||||
|
android:background="@drawable/shape_login_field_bg"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:paddingStart="22dp"
|
||||||
|
android:paddingEnd="16dp">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:contentDescription="@null"
|
||||||
|
android:src="@mipmap/icon_login_phone" />
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/accountEditText"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_marginStart="10dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:background="@null"
|
||||||
|
android:hint="@string/register_account_hint"
|
||||||
|
android:inputType="text"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:textColor="@color/color_2E2E2E"
|
||||||
|
android:textColorHint="@color/color_999999"
|
||||||
|
android:textSize="15sp" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
<LinearLayout
|
||||||
|
android:id="@+id/linear_psd"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="50dp"
|
||||||
|
android:layout_marginTop="20dp"
|
||||||
|
android:background="@drawable/shape_login_field_bg"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:paddingStart="22dp"
|
||||||
|
android:paddingEnd="16dp">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:contentDescription="@null"
|
||||||
|
android:src="@mipmap/icon_login_code" />
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/passwordEditText"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_marginStart="10dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:background="@null"
|
||||||
|
android:hint="@string/register_password_hint"
|
||||||
|
android:inputType="textPassword"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:textColor="@color/color_2E2E2E"
|
||||||
|
android:textColorHint="@color/color_999999"
|
||||||
|
android:textSize="15sp" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/passwordVisibilityButton"
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:contentDescription="@string/register_show_password"
|
||||||
|
android:src="@mipmap/icon_login_show" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/linear_code"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="50dp"
|
||||||
|
android:layout_marginTop="20dp"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:background="@drawable/shape_login_field_bg"
|
||||||
|
android:paddingStart="14dp"
|
||||||
|
android:paddingEnd="10dp"
|
||||||
|
android:visibility="gone">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="28dp"
|
||||||
|
android:layout_height="28dp"
|
||||||
|
android:src="@mipmap/icon_login_code"
|
||||||
|
android:contentDescription="@null" />
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/codeEditText"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:background="@null"
|
||||||
|
android:hint="请输入验证码"
|
||||||
|
android:inputType="number"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:textColorHint="@color/color_999999"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/getCodeButton"
|
||||||
|
android:layout_width="100dp"
|
||||||
|
android:layout_height="38dp"
|
||||||
|
android:background="@drawable/shape_register_code_bg"
|
||||||
|
android:backgroundTint="@null"
|
||||||
|
android:stateListAnimator="@null"
|
||||||
|
android:gravity="center"
|
||||||
|
android:text="获取验证码"
|
||||||
|
android:textAllCaps="false"
|
||||||
|
android:textColor="@color/color_white"
|
||||||
|
android:textSize="12sp" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:layout_marginTop="12dp"
|
||||||
|
android:gravity="center_vertical">
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tvChangeCode"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:layout_gravity="end"
|
||||||
|
android:layout_marginEnd="20dp"
|
||||||
|
android:layout_marginStart="20dp"
|
||||||
|
android:text="@string/register_change_code_login"
|
||||||
|
android:textColor="@color/color_DDE6F5"
|
||||||
|
android:textSize="13sp" />
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/forgotPasswordButton"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="end"
|
||||||
|
android:layout_marginEnd="20dp"
|
||||||
|
android:text="@string/register_forgot_password"
|
||||||
|
android:textColor="@color/color_DDE6F5"
|
||||||
|
android:textSize="13sp" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/loginButton"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="40dp"
|
||||||
|
android:layout_marginStart="15dp"
|
||||||
|
android:layout_marginTop="78dp"
|
||||||
|
android:layout_marginEnd="15dp"
|
||||||
|
android:background="@drawable/shape_login_field_bg"
|
||||||
|
android:backgroundTint="@null"
|
||||||
|
android:stateListAnimator="@null"
|
||||||
|
android:gravity="center"
|
||||||
|
android:text="@string/login_button"
|
||||||
|
android:textAllCaps="false"
|
||||||
|
android:textColor="@color/color_zhu"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/agreementText"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="12dp"
|
||||||
|
android:gravity="center"
|
||||||
|
android:text="@string/register_agreement"
|
||||||
|
android:textColor="@color/color_DDE6F5"
|
||||||
|
android:textSize="12sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/registerButton"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_horizontal"
|
||||||
|
android:layout_marginTop="54dp"
|
||||||
|
android:text="@string/register_prompt"
|
||||||
|
android:textColor="@color/color_DDE6F5"
|
||||||
|
android:textSize="14sp" />
|
||||||
|
</LinearLayout>
|
||||||
|
</ScrollView>
|
||||||
|
|||||||
277
app/src/main/res/layout/forget_psd_layout.xml
Normal file
@@ -0,0 +1,277 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:background="@color/color_zhu">
|
||||||
|
<View
|
||||||
|
android:id="@+id/statusBarView"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:background="@color/color_zhu" />
|
||||||
|
<RelativeLayout
|
||||||
|
android:id="@+id/rl_title"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="48dp">
|
||||||
|
|
||||||
|
<include
|
||||||
|
android:id="@+id/included_title"
|
||||||
|
layout="@layout/include_activity_back_gray_layout" />
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
<ScrollView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:fillViewport="true">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:paddingStart="20dp"
|
||||||
|
android:paddingEnd="20dp"
|
||||||
|
android:paddingBottom="32dp">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="50dp"
|
||||||
|
android:layout_marginTop="57dp"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:background="@drawable/shape_login_field_bg"
|
||||||
|
android:paddingStart="14dp">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="28dp"
|
||||||
|
android:layout_height="28dp"
|
||||||
|
android:src="@mipmap/icon_login_phone"
|
||||||
|
android:contentDescription="@null" />
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:gravity="center_vertical">
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/areaCodeButton"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:text="+86"
|
||||||
|
android:textColor="@color/color_2E2E2E"
|
||||||
|
android:textSize="14sp" />
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="10dp"
|
||||||
|
android:layout_height="10dp"
|
||||||
|
android:layout_marginStart="2dp"
|
||||||
|
android:src="@mipmap/icon_login_point_down"/>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/phoneEditText"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:background="@null"
|
||||||
|
android:hint="请输入手机号"
|
||||||
|
android:inputType="phone"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:textColorHint="@color/color_999999"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="50dp"
|
||||||
|
android:layout_marginTop="20dp"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:background="@drawable/shape_login_field_bg"
|
||||||
|
android:paddingStart="14dp"
|
||||||
|
android:paddingEnd="10dp">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="28dp"
|
||||||
|
android:layout_height="28dp"
|
||||||
|
android:src="@mipmap/icon_login_code"
|
||||||
|
android:contentDescription="@null" />
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/codeEditText"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:background="@null"
|
||||||
|
android:hint="请输入验证码"
|
||||||
|
android:inputType="number"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:textColorHint="@color/color_999999"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/getCodeButton"
|
||||||
|
android:layout_width="100dp"
|
||||||
|
android:layout_height="38dp"
|
||||||
|
android:background="@drawable/shape_register_code_bg"
|
||||||
|
android:backgroundTint="@null"
|
||||||
|
android:stateListAnimator="@null"
|
||||||
|
android:gravity="center"
|
||||||
|
android:text="获取验证码"
|
||||||
|
android:textAllCaps="false"
|
||||||
|
android:textColor="@color/color_white"
|
||||||
|
android:textSize="12sp" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="50dp"
|
||||||
|
android:layout_marginTop="20dp"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:background="@drawable/shape_login_field_bg"
|
||||||
|
android:paddingStart="44dp"
|
||||||
|
android:paddingEnd="16dp">
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/passwordEditText"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:background="@null"
|
||||||
|
android:hint="请输入8-20位密码"
|
||||||
|
android:inputType="textPassword"
|
||||||
|
android:textColorHint="@color/color_999999"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/passwordVisibilityButton"
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:src="@mipmap/icon_login_show"
|
||||||
|
android:contentDescription="显示密码" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="50dp"
|
||||||
|
android:layout_marginTop="20dp"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:background="@drawable/shape_login_field_bg"
|
||||||
|
android:paddingStart="44dp"
|
||||||
|
android:paddingEnd="16dp">
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/confirmPasswordEditText"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:background="@null"
|
||||||
|
android:hint="请再次输入新密码"
|
||||||
|
android:inputType="textPassword"
|
||||||
|
android:textColorHint="@color/color_999999"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/confirmPasswordVisibilityButton"
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:src="@mipmap/icon_login_show"
|
||||||
|
android:contentDescription="显示密码" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="26dp"
|
||||||
|
android:layout_marginEnd="26dp"
|
||||||
|
android:layout_marginTop="36dp"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:paddingStart="18dp"
|
||||||
|
android:paddingVertical="10dp"
|
||||||
|
android:background="@drawable/shape_register_rule_bg">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="密码规则"
|
||||||
|
android:textColor="@color/color_white"
|
||||||
|
android:textSize="18sp" />
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:gravity="center">
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="15dp"
|
||||||
|
android:layout_height="15dp"
|
||||||
|
android:layout_marginVertical="5dp"
|
||||||
|
android:src="@mipmap/icon_login_select"/>
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="6dp"
|
||||||
|
android:text="长度在8-20个字符之间"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:textSize="14sp" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:gravity="center">
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="15dp"
|
||||||
|
android:layout_height="15dp"
|
||||||
|
android:layout_marginVertical="5dp"
|
||||||
|
android:src="@mipmap/icon_login_select"/>
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="6dp"
|
||||||
|
android:text="包含大小写字母和数字"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:textSize="14sp" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:gravity="center">
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="15dp"
|
||||||
|
android:layout_height="15dp"
|
||||||
|
android:layout_marginVertical="5dp"
|
||||||
|
android:src="@mipmap/icon_login_tips"/>
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="6dp"
|
||||||
|
android:text="不能与当前密码相同"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:textSize="14sp" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/confirmButton"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="40dp"
|
||||||
|
android:layout_marginStart="5dp"
|
||||||
|
android:layout_marginEnd="5dp"
|
||||||
|
android:layout_marginTop="84dp"
|
||||||
|
android:gravity="center"
|
||||||
|
android:background="@drawable/shape_login_field_bg"
|
||||||
|
android:backgroundTint="@null"
|
||||||
|
android:stateListAnimator="@null"
|
||||||
|
android:text="确定"
|
||||||
|
android:textAllCaps="false"
|
||||||
|
android:textColor="@color/color_zhu"
|
||||||
|
android:textSize="17sp" />
|
||||||
|
</LinearLayout>
|
||||||
|
</ScrollView>
|
||||||
|
</LinearLayout>
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
<RelativeLayout
|
||||||
|
android:id="@+id/relative_title"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="48dp"
|
||||||
|
android:background="@color/color_zhu">
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/img_back"
|
||||||
|
android:layout_width="22dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:src="@mipmap/img_back_black"
|
||||||
|
android:layout_marginStart="10dp"/>
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_title"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center"
|
||||||
|
android:textSize="18sp"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:text=""
|
||||||
|
android:layout_marginStart="10dp"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:layout_centerHorizontal="true"/>
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_title_info"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:layout_toRightOf="@+id/tv_title"
|
||||||
|
android:textSize="14sp"
|
||||||
|
android:textColor="@color/color_2E2E2E"
|
||||||
|
android:text="(剩余时间)"
|
||||||
|
android:layout_marginStart="5dp"
|
||||||
|
android:visibility="gone"/>
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_title_right"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:layout_alignParentRight="true"
|
||||||
|
android:layout_marginRight="10dp"
|
||||||
|
android:textSize="14sp"
|
||||||
|
android:textColor="@color/color_333333"
|
||||||
|
android:text=""
|
||||||
|
android:layout_marginStart="5dp"
|
||||||
|
android:visibility="visible"/>
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/img_setting"
|
||||||
|
android:layout_width="20dp"
|
||||||
|
android:layout_height="20dp"
|
||||||
|
android:layout_centerVertical="true"
|
||||||
|
android:layout_alignParentRight="true"
|
||||||
|
android:src="@mipmap/ic_launcher"
|
||||||
|
android:layout_marginEnd="20dp"
|
||||||
|
android:visibility="gone"/>
|
||||||
|
</RelativeLayout>
|
||||||
|
</RelativeLayout>
|
||||||
258
app/src/main/res/layout/register_layout.xml
Normal file
@@ -0,0 +1,258 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:background="@color/color_zhu">
|
||||||
|
<View
|
||||||
|
android:id="@+id/statusBarView"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:background="@color/color_zhu" />
|
||||||
|
<RelativeLayout
|
||||||
|
android:id="@+id/rl_title"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="48dp">
|
||||||
|
|
||||||
|
<include
|
||||||
|
android:id="@+id/included_title"
|
||||||
|
layout="@layout/include_activity_back_gray_layout" />
|
||||||
|
</RelativeLayout>
|
||||||
|
|
||||||
|
<ScrollView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:fillViewport="true">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:paddingStart="20dp"
|
||||||
|
android:paddingEnd="20dp"
|
||||||
|
android:paddingBottom="32dp">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="50dp"
|
||||||
|
android:layout_marginTop="57dp"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:background="@drawable/shape_login_field_bg"
|
||||||
|
android:paddingStart="14dp">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="28dp"
|
||||||
|
android:layout_height="28dp"
|
||||||
|
android:src="@mipmap/icon_login_phone"
|
||||||
|
android:contentDescription="@null" />
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:gravity="center_vertical">
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/areaCodeButton"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:text="+86"
|
||||||
|
android:textColor="@color/color_2E2E2E"
|
||||||
|
android:textSize="14sp" />
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="10dp"
|
||||||
|
android:layout_height="10dp"
|
||||||
|
android:layout_marginStart="2dp"
|
||||||
|
android:src="@mipmap/icon_login_point_down"/>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/phoneEditText"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:background="@null"
|
||||||
|
android:hint="请输入手机号"
|
||||||
|
android:inputType="phone"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:textColorHint="@color/color_999999"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="50dp"
|
||||||
|
android:layout_marginTop="20dp"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:background="@drawable/shape_login_field_bg"
|
||||||
|
android:paddingStart="14dp"
|
||||||
|
android:paddingEnd="10dp">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="28dp"
|
||||||
|
android:layout_height="28dp"
|
||||||
|
android:src="@mipmap/icon_login_code"
|
||||||
|
android:contentDescription="@null" />
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/codeEditText"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:background="@null"
|
||||||
|
android:hint="请输入验证码"
|
||||||
|
android:inputType="number"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:textColorHint="@color/color_999999"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/getCodeButton"
|
||||||
|
android:layout_width="100dp"
|
||||||
|
android:layout_height="38dp"
|
||||||
|
android:background="@drawable/shape_register_code_bg"
|
||||||
|
android:backgroundTint="@null"
|
||||||
|
android:stateListAnimator="@null"
|
||||||
|
android:gravity="center"
|
||||||
|
android:text="@string/register_get_code"
|
||||||
|
android:textAllCaps="false"
|
||||||
|
android:textColor="@color/color_white"
|
||||||
|
android:textSize="12sp" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="50dp"
|
||||||
|
android:layout_marginTop="20dp"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:background="@drawable/shape_login_field_bg"
|
||||||
|
android:paddingStart="44dp"
|
||||||
|
android:paddingEnd="16dp">
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/passwordEditText"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:background="@null"
|
||||||
|
android:hint="请输入8-20位密码"
|
||||||
|
android:inputType="textPassword"
|
||||||
|
android:textColorHint="@color/color_999999"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/passwordVisibilityButton"
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:src="@mipmap/icon_login_show"
|
||||||
|
android:contentDescription="显示密码" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="50dp"
|
||||||
|
android:layout_marginTop="20dp"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:background="@drawable/shape_login_field_bg"
|
||||||
|
android:paddingStart="44dp"
|
||||||
|
android:paddingEnd="16dp">
|
||||||
|
|
||||||
|
<EditText
|
||||||
|
android:id="@+id/confirmPasswordEditText"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:background="@null"
|
||||||
|
android:hint="请再次输入新密码"
|
||||||
|
android:inputType="textPassword"
|
||||||
|
android:textColorHint="@color/color_999999"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/confirmPasswordVisibilityButton"
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:src="@mipmap/icon_login_show"
|
||||||
|
android:contentDescription="显示密码" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="98dp"
|
||||||
|
android:layout_marginStart="26dp"
|
||||||
|
android:layout_marginEnd="26dp"
|
||||||
|
android:layout_marginTop="36dp"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:paddingStart="18dp"
|
||||||
|
android:paddingTop="10dp"
|
||||||
|
android:background="@drawable/shape_register_rule_bg">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="密码规则"
|
||||||
|
android:textColor="@color/color_white"
|
||||||
|
android:textSize="18sp" />
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:gravity="center">
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="15dp"
|
||||||
|
android:layout_height="15dp"
|
||||||
|
android:layout_marginVertical="5dp"
|
||||||
|
android:src="@mipmap/icon_login_select"/>
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="6dp"
|
||||||
|
android:text="长度在8-20个字符之间"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:textSize="14sp" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:gravity="center">
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="15dp"
|
||||||
|
android:layout_height="15dp"
|
||||||
|
android:layout_marginVertical="5dp"
|
||||||
|
android:src="@mipmap/icon_login_select"/>
|
||||||
|
<TextView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="6dp"
|
||||||
|
android:text="包含大小写字母和数字"
|
||||||
|
android:textColor="@color/white"
|
||||||
|
android:textSize="14sp" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/confirmButton"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="40dp"
|
||||||
|
android:layout_marginStart="5dp"
|
||||||
|
android:layout_marginEnd="5dp"
|
||||||
|
android:layout_marginTop="84dp"
|
||||||
|
android:gravity="center"
|
||||||
|
android:background="@drawable/shape_login_field_bg"
|
||||||
|
android:backgroundTint="@null"
|
||||||
|
android:stateListAnimator="@null"
|
||||||
|
android:text="确定"
|
||||||
|
android:textAllCaps="false"
|
||||||
|
android:textColor="@color/color_zhu"
|
||||||
|
android:textSize="17sp" />
|
||||||
|
</LinearLayout>
|
||||||
|
</ScrollView>
|
||||||
|
</LinearLayout>
|
||||||
BIN
app/src/main/res/mipmap-hdpi/img_back_black.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
app/src/main/res/mipmap-xhdpi/icon_app_logo.png
Normal file
|
After Width: | Height: | Size: 3.6 KiB |
BIN
app/src/main/res/mipmap-xhdpi/icon_login_code.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
app/src/main/res/mipmap-xhdpi/icon_login_phone.png
Normal file
|
After Width: | Height: | Size: 532 B |
BIN
app/src/main/res/mipmap-xhdpi/icon_login_point_down.png
Normal file
|
After Width: | Height: | Size: 285 B |
BIN
app/src/main/res/mipmap-xhdpi/icon_login_select.png
Normal file
|
After Width: | Height: | Size: 564 B |
BIN
app/src/main/res/mipmap-xhdpi/icon_login_show.png
Normal file
|
After Width: | Height: | Size: 636 B |
BIN
app/src/main/res/mipmap-xhdpi/icon_login_tips.png
Normal file
|
After Width: | Height: | Size: 1.0 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/icon_app_logo.png
Normal file
|
After Width: | Height: | Size: 5.9 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/icon_login_code.png
Normal file
|
After Width: | Height: | Size: 3.0 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/icon_login_phone.png
Normal file
|
After Width: | Height: | Size: 1.0 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/icon_login_point_down.png
Normal file
|
After Width: | Height: | Size: 482 B |
BIN
app/src/main/res/mipmap-xxhdpi/icon_login_select.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/icon_login_show.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
app/src/main/res/mipmap-xxhdpi/icon_login_tips.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
app/src/main/res/mipmap-xxxhdpi/icon_app_logo.png
Normal file
|
After Width: | Height: | Size: 6.3 KiB |
BIN
app/src/main/res/mipmap-xxxhdpi/icon_login_code.png
Normal file
|
After Width: | Height: | Size: 3.1 KiB |
BIN
app/src/main/res/mipmap-xxxhdpi/icon_login_phone.png
Normal file
|
After Width: | Height: | Size: 501 B |
BIN
app/src/main/res/mipmap-xxxhdpi/icon_login_point_down.png
Normal file
|
After Width: | Height: | Size: 461 B |
BIN
app/src/main/res/mipmap-xxxhdpi/icon_login_select.png
Normal file
|
After Width: | Height: | Size: 831 B |
BIN
app/src/main/res/mipmap-xxxhdpi/icon_login_show.png
Normal file
|
After Width: | Height: | Size: 694 B |
BIN
app/src/main/res/mipmap-xxxhdpi/icon_login_tips.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
app/src/main/res/mipmap-xxxhdpi/img_back_black.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
@@ -46,7 +46,7 @@
|
|||||||
<!--视频准备页面,背景半透明颜色-->
|
<!--视频准备页面,背景半透明颜色-->
|
||||||
<color name="color_1d76fe">#1D76FE</color>
|
<color name="color_1d76fe">#1D76FE</color>
|
||||||
<color name="color_1a72ff">#1A72FF</color>
|
<color name="color_1a72ff">#1A72FF</color>
|
||||||
<color name="color_zhu">#00CA9D</color>
|
<color name="color_zhu">#005431</color>
|
||||||
<color name="color_c8c8c8">#C8C8C8</color>
|
<color name="color_c8c8c8">#C8C8C8</color>
|
||||||
<color name="color_F6F6F6">#F6F6F6</color>
|
<color name="color_F6F6F6">#F6F6F6</color>
|
||||||
<color name="color_2E2E2E">#2E2E2E</color>
|
<color name="color_2E2E2E">#2E2E2E</color>
|
||||||
@@ -117,7 +117,6 @@
|
|||||||
<color name="color_F0F8F1">#F0F8F1</color>
|
<color name="color_F0F8F1">#F0F8F1</color>
|
||||||
<color name="color_FFFCEB">#FFFCEB</color>
|
<color name="color_FFFCEB">#FFFCEB</color>
|
||||||
<color name="color_1D90FF">#1D90FF</color>
|
<color name="color_1D90FF">#1D90FF</color>
|
||||||
|
|
||||||
<color name="color_8000CA9D">#8000CA9D</color>
|
<color name="color_8000CA9D">#8000CA9D</color>
|
||||||
|
|
||||||
|
|
||||||
@@ -139,6 +138,7 @@
|
|||||||
<color name="page_background">#F7F8FA</color>
|
<color name="page_background">#F7F8FA</color>
|
||||||
<color name="bottom_nav_background">#FFFFFFFF</color>
|
<color name="bottom_nav_background">#FFFFFFFF</color>
|
||||||
<color name="plan_top_image_color">#C51609</color>
|
<color name="plan_top_image_color">#C51609</color>
|
||||||
|
<color name="register_psd_rule">#286F51</color>
|
||||||
|
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -1,10 +1,52 @@
|
|||||||
<resources>
|
<resources>
|
||||||
<string name="app_name">KotMvpProject</string>
|
<string name="app_chinese_name">聚哈比‑萨克尔GPS智能隼眼罩</string>
|
||||||
|
<string name="app_name">JUMHABI Saqr GPS Smart Falcon Hood</string>
|
||||||
<string name="login_title">账号登录</string>
|
<string name="login_title">账号登录</string>
|
||||||
<string name="login_subtitle">请输入账号和密码</string>
|
<string name="login_subtitle">请输入账号和密码</string>
|
||||||
<string name="login_username">手机号</string>
|
<string name="login_username">手机号</string>
|
||||||
<string name="login_password">密码</string>
|
<string name="login_password">密码</string>
|
||||||
<string name="login_button">登录</string>
|
<string name="login_button">登录</string>
|
||||||
|
<string name="login_register">手机注册</string>
|
||||||
|
<string name="register_account_hint">请输入账号</string>
|
||||||
|
<string name="register_password_hint">请输入密码</string>
|
||||||
|
<string name="register_show_password">显示密码</string>
|
||||||
|
<string name="register_forgot_password">忘记密码?</string>
|
||||||
|
<string name="forget_password_title">忘记密码</string>
|
||||||
|
<string name="register_change_code_login">切换手机号验证码登录</string>
|
||||||
|
<string name="register_change_psd_login">切换密码登录</string>
|
||||||
|
<string name="register_agreement">我已阅读并同意用户协议和隐私政策以及定制条款</string>
|
||||||
|
<string name="register_prompt">没有账号?立即注册</string>
|
||||||
|
<string name="register_get_code">获取验证码</string>
|
||||||
|
<string name="register_code_countdown">%1$d秒后重新获取</string>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<string name="login_demo_hint">登录成功后将自动保存 Token</string>
|
<string name="login_demo_hint">登录成功后将自动保存 Token</string>
|
||||||
<string name="mine_open_login">前往登录页面</string>
|
<string name="mine_open_login">前往登录页面</string>
|
||||||
<string name="plan_top_image_description">计划页顶部背景图</string>
|
<string name="plan_top_image_description">计划页顶部背景图</string>
|
||||||
|
|||||||