parent
98e8fdbb33
commit
59f950915a
@ -0,0 +1,15 @@ |
|||||||
|
package xyz.fycz.myreader.base |
||||||
|
|
||||||
|
import android.text.TextWatcher |
||||||
|
|
||||||
|
/** |
||||||
|
* @author fengyue |
||||||
|
* @date 2021/12/9 12:32 |
||||||
|
*/ |
||||||
|
abstract class MyTextWatcher : TextWatcher { |
||||||
|
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) { |
||||||
|
} |
||||||
|
|
||||||
|
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) { |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,10 @@ |
|||||||
|
package xyz.fycz.myreader.model.user |
||||||
|
|
||||||
|
/** |
||||||
|
* @author fengyue |
||||||
|
* @date 2021/12/9 10:19 |
||||||
|
*/ |
||||||
|
data class Result( |
||||||
|
val code: Int, |
||||||
|
val result: Any |
||||||
|
) |
@ -0,0 +1,70 @@ |
|||||||
|
package xyz.fycz.myreader.model.user; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author fengyue |
||||||
|
* @date 2020/7/12 17:35 |
||||||
|
*/ |
||||||
|
public class User { |
||||||
|
private Integer userId; |
||||||
|
private String userName; |
||||||
|
private String password; |
||||||
|
private String email; |
||||||
|
|
||||||
|
public User() { |
||||||
|
} |
||||||
|
|
||||||
|
public User(String userName) { |
||||||
|
this.userName = userName; |
||||||
|
} |
||||||
|
|
||||||
|
public User(String userName, String password) { |
||||||
|
this.userName = userName; |
||||||
|
this.password = password; |
||||||
|
} |
||||||
|
|
||||||
|
public User(String userName, String password, String email) { |
||||||
|
this.userName = userName; |
||||||
|
this.password = password; |
||||||
|
this.email = email; |
||||||
|
} |
||||||
|
|
||||||
|
public User(Integer userId, String userName, String password, String email) { |
||||||
|
this.userId = userId; |
||||||
|
this.userName = userName; |
||||||
|
this.password = password; |
||||||
|
this.email = email; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public Integer getUserId() { |
||||||
|
return userId; |
||||||
|
} |
||||||
|
|
||||||
|
public String getUserName() { |
||||||
|
return userName; |
||||||
|
} |
||||||
|
|
||||||
|
public void setUserName(String userName) { |
||||||
|
this.userName = userName; |
||||||
|
} |
||||||
|
|
||||||
|
public String getPassword() { |
||||||
|
return password; |
||||||
|
} |
||||||
|
|
||||||
|
public void setPassword(String password) { |
||||||
|
this.password = password; |
||||||
|
} |
||||||
|
|
||||||
|
public void setUserId(Integer userId) { |
||||||
|
this.userId = userId; |
||||||
|
} |
||||||
|
|
||||||
|
public String getEmail() { |
||||||
|
return email; |
||||||
|
} |
||||||
|
|
||||||
|
public void setEmail(String email) { |
||||||
|
this.email = email; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,171 @@ |
|||||||
|
package xyz.fycz.myreader.model.user |
||||||
|
|
||||||
|
import io.reactivex.Single |
||||||
|
import io.reactivex.SingleOnSubscribe |
||||||
|
import okhttp3.MediaType |
||||||
|
import okhttp3.RequestBody |
||||||
|
import xyz.fycz.myreader.application.App |
||||||
|
import xyz.fycz.myreader.common.APPCONST |
||||||
|
import xyz.fycz.myreader.common.URLCONST |
||||||
|
import xyz.fycz.myreader.model.storage.Backup |
||||||
|
import xyz.fycz.myreader.model.storage.Restore |
||||||
|
import xyz.fycz.myreader.model.storage.Restore.restore |
||||||
|
import xyz.fycz.myreader.util.* |
||||||
|
import xyz.fycz.myreader.util.utils.FileUtils |
||||||
|
import xyz.fycz.myreader.util.utils.GSON |
||||||
|
import xyz.fycz.myreader.util.utils.OkHttpUtils |
||||||
|
import xyz.fycz.myreader.util.utils.RxUtils |
||||||
|
|
||||||
|
/** |
||||||
|
* @author fengyue |
||||||
|
* @date 2021/12/9 10:17 |
||||||
|
*/ |
||||||
|
object UserService2 { |
||||||
|
fun login(user: User): Single<Result> { |
||||||
|
return Single.create(SingleOnSubscribe<Result> { |
||||||
|
val mediaType = MediaType.parse("application/x-www-form-urlencoded") |
||||||
|
val body = "username=${user.userName}" + |
||||||
|
"&password=${user.password}" + |
||||||
|
makeAuth() |
||||||
|
val requestBody = RequestBody.create(mediaType, body) |
||||||
|
val ret = OkHttpUtils.getHtml(URLCONST.USER_URL + "/do/login", requestBody, "UTF-8") |
||||||
|
it.onSuccess(GSON.fromJson(ret, Result::class.java)) |
||||||
|
}).compose { RxUtils.toSimpleSingle(it) } |
||||||
|
} |
||||||
|
|
||||||
|
fun register(user: User, code: String, keyc: String): Single<Result> { |
||||||
|
return Single.create(SingleOnSubscribe<Result> { |
||||||
|
val mediaType = MediaType.parse("application/x-www-form-urlencoded") |
||||||
|
val body = "username=${user.userName}" + |
||||||
|
"&password=${user.password}" + |
||||||
|
"&email=${user.email}" + |
||||||
|
"&code=${code}" + |
||||||
|
"&keyc=${keyc}" + |
||||||
|
"&key=${CyptoUtils.encode(APPCONST.KEY, APPCONST.publicKey)}" + |
||||||
|
makeAuth() |
||||||
|
val requestBody = RequestBody.create(mediaType, body) |
||||||
|
val ret = OkHttpUtils.getHtml(URLCONST.USER_URL + "/do/reg", requestBody, "UTF-8") |
||||||
|
it.onSuccess(GSON.fromJson(ret, Result::class.java)) |
||||||
|
}).compose { RxUtils.toSimpleSingle(it) } |
||||||
|
} |
||||||
|
|
||||||
|
fun bindEmail(user: User, code: String, keyc: String): Single<Result> { |
||||||
|
return Single.create(SingleOnSubscribe<Result> { |
||||||
|
val mediaType = MediaType.parse("application/x-www-form-urlencoded") |
||||||
|
val body = "username=${user.userName}" + |
||||||
|
"&email=${user.email}" + |
||||||
|
"&code=${code}" + |
||||||
|
"&keyc=${keyc}" + |
||||||
|
makeAuth() |
||||||
|
val requestBody = RequestBody.create(mediaType, body) |
||||||
|
val ret = OkHttpUtils.getHtml(URLCONST.USER_URL + "/do/bindEmail", requestBody, "UTF-8") |
||||||
|
it.onSuccess(GSON.fromJson(ret, Result::class.java)) |
||||||
|
}).compose { RxUtils.toSimpleSingle(it) } |
||||||
|
} |
||||||
|
|
||||||
|
fun resetPwd(user: User, code: String, keyc: String): Single<Result> { |
||||||
|
return Single.create(SingleOnSubscribe<Result> { |
||||||
|
val mediaType = MediaType.parse("application/x-www-form-urlencoded") |
||||||
|
val body = "email=${user.email}" + |
||||||
|
"&password=${user.password}" + |
||||||
|
"&code=${code}" + |
||||||
|
"&keyc=${keyc}" + |
||||||
|
makeAuth() |
||||||
|
val requestBody = RequestBody.create(mediaType, body) |
||||||
|
val ret = OkHttpUtils.getHtml(URLCONST.USER_URL + "/do/resetPwd", requestBody, "UTF-8") |
||||||
|
it.onSuccess(GSON.fromJson(ret, Result::class.java)) |
||||||
|
}).compose { RxUtils.toSimpleSingle(it) } |
||||||
|
} |
||||||
|
|
||||||
|
fun sendEmail(email: String, type: String, keyc: String = ""): Single<Result> { |
||||||
|
return Single.create(SingleOnSubscribe<Result> { |
||||||
|
val mediaType = MediaType.parse("application/x-www-form-urlencoded") |
||||||
|
val body = "email=${email}" + |
||||||
|
"&type=${type}" + |
||||||
|
"&keyc=${keyc}" + |
||||||
|
makeAuth() |
||||||
|
val requestBody = RequestBody.create(mediaType, body) |
||||||
|
val ret = OkHttpUtils.getHtml(URLCONST.USER_URL + "/do/sendEmail", requestBody, "UTF-8") |
||||||
|
it.onSuccess(GSON.fromJson(ret, Result::class.java)) |
||||||
|
}).compose { RxUtils.toSimpleSingle(it) } |
||||||
|
} |
||||||
|
|
||||||
|
fun webBackup(user: User): Single<Result> { |
||||||
|
return Single.create(SingleOnSubscribe<Result> { |
||||||
|
Backup.backup(App.getmContext(), APPCONST.FILE_DIR + "webBackup/", |
||||||
|
object : Backup.CallBack { |
||||||
|
override fun backupSuccess() { |
||||||
|
val inputFile = FileUtils.getFile(APPCONST.FILE_DIR + "webBackup") |
||||||
|
val zipFile = FileUtils.getFile(APPCONST.FILE_DIR + "webBackup.zip") |
||||||
|
//压缩文件 |
||||||
|
ZipUtils.zipFile(inputFile, zipFile) |
||||||
|
val ret = OkHttpUtils.upload( |
||||||
|
URLCONST.USER_URL + "/do/bak?" + |
||||||
|
"username=${user.userName}" + |
||||||
|
makeAuth(), |
||||||
|
zipFile.absolutePath, |
||||||
|
zipFile.name |
||||||
|
) |
||||||
|
zipFile.delete() |
||||||
|
it.onSuccess(GSON.fromJson(ret, Result::class.java)) |
||||||
|
} |
||||||
|
|
||||||
|
override fun backupError(msg: String) { |
||||||
|
it.onError(Throwable(msg)) |
||||||
|
} |
||||||
|
|
||||||
|
}) |
||||||
|
}).compose { RxUtils.toSimpleSingle(it) } |
||||||
|
} |
||||||
|
|
||||||
|
fun webRestore(user: User): Single<Result> { |
||||||
|
return Single.create(SingleOnSubscribe<Result> { |
||||||
|
val zipFile = FileUtils.getFile(APPCONST.FILE_DIR + "webBackup.zip") |
||||||
|
val input = OkHttpUtils.getInputStream( |
||||||
|
URLCONST.USER_URL + "/do/ret?" + |
||||||
|
"username=${user.userName}" + |
||||||
|
makeAuth() |
||||||
|
) |
||||||
|
if (FileUtils.writeFile(input.readBytes(), zipFile)) { |
||||||
|
ZipUtils.unzipFile(zipFile.absolutePath, APPCONST.FILE_DIR) |
||||||
|
restore(APPCONST.FILE_DIR + "webBackup/", object : Restore.CallBack { |
||||||
|
override fun restoreSuccess() { |
||||||
|
zipFile.delete() |
||||||
|
it.onSuccess(Result(100, "成功从网络同步到本地")) |
||||||
|
} |
||||||
|
|
||||||
|
override fun restoreError(msg: String) { |
||||||
|
it.onError(Throwable(msg)) |
||||||
|
} |
||||||
|
}) |
||||||
|
} |
||||||
|
}).compose { RxUtils.toSimpleSingle(it) } |
||||||
|
} |
||||||
|
|
||||||
|
fun writeConfig(user: User) { |
||||||
|
FileUtils.write(App.getmContext(), "userConfig.fy", GSON.toJson(user)) |
||||||
|
} |
||||||
|
|
||||||
|
fun readConfig(): User? { |
||||||
|
val config = FileUtils.read(App.getmContext(), "userConfig.fy") |
||||||
|
if ("" != config) { |
||||||
|
return GSON.fromJson(config, User::class.java) |
||||||
|
} |
||||||
|
return null |
||||||
|
} |
||||||
|
|
||||||
|
fun writeUsername(username: String) { |
||||||
|
FileUtils.writeText(username, FileUtils.getFile(APPCONST.QQ_DATA_DIR + "user")) |
||||||
|
} |
||||||
|
|
||||||
|
fun readUsername(): String { |
||||||
|
return FileUtils.readText(APPCONST.QQ_DATA_DIR + "user") |
||||||
|
} |
||||||
|
|
||||||
|
private fun makeAuth(): String { |
||||||
|
return "&signal=" + AppInfoUtils.getSingInfo( |
||||||
|
App.getmContext(), |
||||||
|
App.getApplication().packageName, AppInfoUtils.SHA1 |
||||||
|
) + "&appVersion=" + App.getVersionCode() |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,225 @@ |
|||||||
|
package xyz.fycz.myreader.ui.activity |
||||||
|
|
||||||
|
import android.app.Activity |
||||||
|
import android.content.Intent |
||||||
|
import android.os.Bundle |
||||||
|
import android.text.Editable |
||||||
|
import android.view.View |
||||||
|
import androidx.appcompat.widget.Toolbar |
||||||
|
import io.reactivex.SingleObserver |
||||||
|
import io.reactivex.disposables.Disposable |
||||||
|
import xyz.fycz.myreader.R |
||||||
|
import xyz.fycz.myreader.application.App |
||||||
|
import xyz.fycz.myreader.base.BaseActivity |
||||||
|
import xyz.fycz.myreader.base.BitIntentDataManager |
||||||
|
import xyz.fycz.myreader.base.MyTextWatcher |
||||||
|
import xyz.fycz.myreader.base.observer.MySingleObserver |
||||||
|
import xyz.fycz.myreader.common.APPCONST |
||||||
|
import xyz.fycz.myreader.databinding.ActivityAuthEmailBinding |
||||||
|
import xyz.fycz.myreader.model.user.Result |
||||||
|
import xyz.fycz.myreader.model.user.User |
||||||
|
import xyz.fycz.myreader.model.user.UserService2 |
||||||
|
import xyz.fycz.myreader.model.user.UserService2.bindEmail |
||||||
|
import xyz.fycz.myreader.model.user.UserService2.register |
||||||
|
import xyz.fycz.myreader.model.user.UserService2.resetPwd |
||||||
|
import xyz.fycz.myreader.model.user.UserService2.sendEmail |
||||||
|
import xyz.fycz.myreader.model.user.UserService2.writeUsername |
||||||
|
import xyz.fycz.myreader.ui.dialog.DialogCreator |
||||||
|
import xyz.fycz.myreader.ui.dialog.LoadingDialog |
||||||
|
import xyz.fycz.myreader.util.CyptoUtils |
||||||
|
import xyz.fycz.myreader.util.ToastUtils |
||||||
|
import java.util.* |
||||||
|
|
||||||
|
/** |
||||||
|
* @author fengyue |
||||||
|
* @date 2021/12/9 15:20 |
||||||
|
*/ |
||||||
|
class AuthEmailActivity : BaseActivity(), SingleObserver<Result> { |
||||||
|
|
||||||
|
private lateinit var binding: ActivityAuthEmailBinding |
||||||
|
private var email = "" |
||||||
|
private var password = "" |
||||||
|
private var emailCode = "" |
||||||
|
private var keyc = "" |
||||||
|
private lateinit var dialog: LoadingDialog |
||||||
|
private var disp: Disposable? = null |
||||||
|
private lateinit var operator: String |
||||||
|
private var user: User? = null |
||||||
|
private var isBind: Boolean = false |
||||||
|
override fun bindView() { |
||||||
|
binding = ActivityAuthEmailBinding.inflate(layoutInflater) |
||||||
|
setContentView(binding.root) |
||||||
|
} |
||||||
|
|
||||||
|
override fun initData(savedInstanceState: Bundle?) { |
||||||
|
user = BitIntentDataManager.getInstance().getData(intent) as User? |
||||||
|
isBind = user != null |
||||||
|
operator = if (isBind) "绑定邮箱" else "重置密码" |
||||||
|
dialog = LoadingDialog(this, "正在请求") { |
||||||
|
disp?.dispose() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
override fun setUpToolbar(toolbar: Toolbar?) { |
||||||
|
super.setUpToolbar(toolbar) |
||||||
|
setStatusBarColor(R.color.colorPrimary, true) |
||||||
|
supportActionBar?.title = operator |
||||||
|
} |
||||||
|
|
||||||
|
override fun initWidget() { |
||||||
|
binding.tvTitle.text = operator |
||||||
|
binding.btSubmit.text = operator |
||||||
|
binding.etEmail.editText?.addTextChangedListener(object : MyTextWatcher() { |
||||||
|
override fun afterTextChanged(s: Editable) { |
||||||
|
email = s.toString() |
||||||
|
if (!email.matches("^[_a-z0-9-]+(\\.[_a-z0-9-]+)*@[a-z0-9-]+(\\.[a-z0-9-]+)*(\\.[a-z]{2,})$".toRegex())) { |
||||||
|
showTip("邮箱格式错误") |
||||||
|
} else { |
||||||
|
binding.tvRegisterTip.visibility = View.GONE |
||||||
|
} |
||||||
|
checkNotNone() |
||||||
|
} |
||||||
|
}) |
||||||
|
|
||||||
|
binding.etEmailCode.editText?.addTextChangedListener(object : MyTextWatcher() { |
||||||
|
override fun afterTextChanged(s: Editable) { |
||||||
|
emailCode = s.toString().trim() |
||||||
|
checkNotNone() |
||||||
|
} |
||||||
|
}) |
||||||
|
binding.etPassword.editText!!.addTextChangedListener(object : MyTextWatcher() { |
||||||
|
override fun afterTextChanged(s: Editable) { |
||||||
|
password = s.toString() |
||||||
|
if (password.length < 8 || password.length > 16) { |
||||||
|
showTip("密码必须在8-16位之间") |
||||||
|
} else if (password.matches("^\\d+$".toRegex())) { |
||||||
|
showTip("密码不能是纯数字") |
||||||
|
} else { |
||||||
|
binding.tvRegisterTip.visibility = View.GONE |
||||||
|
} |
||||||
|
checkNotNone() |
||||||
|
} |
||||||
|
}) |
||||||
|
if (!isBind) { |
||||||
|
binding.etPassword.visibility = View.VISIBLE |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
override fun initClick() { |
||||||
|
binding.tvGetEmailCode.setOnClickListener { |
||||||
|
if (!email.matches("^[_a-z0-9-]+(\\.[_a-z0-9-]+)*@[a-z0-9-]+(\\.[a-z0-9-]+)*(\\.[a-z]{2,})$".toRegex())) { |
||||||
|
ToastUtils.showWarring("请正确输入邮箱") |
||||||
|
return@setOnClickListener |
||||||
|
} |
||||||
|
dialog.show() |
||||||
|
dialog.setmMessage("正在发送") |
||||||
|
sendEmail(email, if (isBind) "bind" else "auth", keyc) |
||||||
|
.subscribe(object : MySingleObserver<Result?>() { |
||||||
|
override fun onSubscribe(d: Disposable) { |
||||||
|
addDisposable(d) |
||||||
|
disp = d |
||||||
|
} |
||||||
|
|
||||||
|
override fun onSuccess(result: Result) { |
||||||
|
if (result.code == 106) { |
||||||
|
ToastUtils.showSuccess("验证码发送成功") |
||||||
|
keyc = result.result.toString() |
||||||
|
timeDown(60) |
||||||
|
} else { |
||||||
|
ToastUtils.showWarring(result.result.toString()) |
||||||
|
} |
||||||
|
dialog.dismiss() |
||||||
|
} |
||||||
|
|
||||||
|
override fun onError(e: Throwable) { |
||||||
|
ToastUtils.showError("验证码发送失败:${e.localizedMessage}") |
||||||
|
dialog.dismiss() |
||||||
|
} |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
binding.btSubmit.setOnClickListener { |
||||||
|
if (!isBind && (password.matches("^\\d+$".toRegex()) || !password.matches("^.{8,16}$".toRegex()))) { |
||||||
|
DialogCreator.createTipDialog( |
||||||
|
this, "密码格式错误", |
||||||
|
"密码必须在8-16位之间\n密码不能是纯数字" |
||||||
|
) |
||||||
|
} else if (!email.matches("^[_a-z0-9-]+(\\.[_a-z0-9-]+)*@[a-z0-9-]+(\\.[a-z0-9-]+)*(\\.[a-z]{2,})$".toRegex())) { |
||||||
|
DialogCreator.createTipDialog( |
||||||
|
this, "邮箱格式错误", |
||||||
|
"电子邮箱的正确写法为:用户名@邮箱网站.com(.cn等)" |
||||||
|
) |
||||||
|
} else if ("" == keyc) { |
||||||
|
DialogCreator.createTipDialog(this, "请先获取邮箱验证码") |
||||||
|
} else if (emailCode.length < 6) { |
||||||
|
DialogCreator.createTipDialog(this, "请输入6位邮箱验证码") |
||||||
|
} else { |
||||||
|
dialog.show() |
||||||
|
dialog.setmMessage("正在请求") |
||||||
|
if (isBind) { |
||||||
|
val user = User().apply { |
||||||
|
email = this@AuthEmailActivity.email |
||||||
|
userName = this@AuthEmailActivity.user?.userName |
||||||
|
} |
||||||
|
bindEmail(user, emailCode, keyc) |
||||||
|
.subscribe(this) |
||||||
|
} else { |
||||||
|
val user = User().apply { |
||||||
|
email = this@AuthEmailActivity.email |
||||||
|
password = CyptoUtils.encode(APPCONST.KEY, this@AuthEmailActivity.password) |
||||||
|
} |
||||||
|
resetPwd(user, emailCode, keyc) |
||||||
|
.subscribe(this) |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
fun showTip(tip: String?) { |
||||||
|
binding.tvRegisterTip.visibility = View.VISIBLE |
||||||
|
binding.tvRegisterTip.text = tip |
||||||
|
} |
||||||
|
|
||||||
|
private fun timeDown(time: Int) { |
||||||
|
if (time == 0) { |
||||||
|
binding.tvGetEmailCode.text = getString(R.string.re_get_email_code, "") |
||||||
|
binding.tvGetEmailCode.isEnabled = true |
||||||
|
} else { |
||||||
|
binding.tvGetEmailCode.isEnabled = false |
||||||
|
val timeStr = "($time)" |
||||||
|
binding.tvGetEmailCode.text = getString(R.string.re_get_email_code, timeStr) |
||||||
|
App.getHandler().postDelayed({ timeDown(time - 1) }, 1000) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
fun checkNotNone() { |
||||||
|
binding.btSubmit.isEnabled = "" != email && "" != emailCode && (isBind || "" != password) |
||||||
|
} |
||||||
|
|
||||||
|
override fun onDestroy() { |
||||||
|
dialog.dismiss() |
||||||
|
super.onDestroy() |
||||||
|
} |
||||||
|
|
||||||
|
override fun onSubscribe(d: Disposable) { |
||||||
|
addDisposable(d) |
||||||
|
disp = d |
||||||
|
} |
||||||
|
|
||||||
|
override fun onSuccess(result: Result) { |
||||||
|
if (result.code < 200) { |
||||||
|
ToastUtils.showSuccess(result.result.toString()) |
||||||
|
setResult(Activity.RESULT_OK) |
||||||
|
finish() |
||||||
|
} else { |
||||||
|
ToastUtils.showWarring(result.result.toString()) |
||||||
|
} |
||||||
|
dialog.dismiss() |
||||||
|
} |
||||||
|
|
||||||
|
override fun onError(e: Throwable) { |
||||||
|
ToastUtils.showError("失败:${e.localizedMessage}") |
||||||
|
dialog.dismiss() |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,5 @@ |
|||||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||||
|
<selector xmlns:android="http://schemas.android.com/apk/res/android"> |
||||||
|
<item android:color="@color/textSecondary" android:state_enabled="false" /> |
||||||
|
<item android:color="@color/sys_color"/> |
||||||
|
</selector> |
Before Width: | Height: | Size: 134 KiB |
@ -0,0 +1,125 @@ |
|||||||
|
<?xml version="1.0" encoding="utf-8"?> |
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" |
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto" |
||||||
|
xmlns:tools="http://schemas.android.com/tools" |
||||||
|
android:layout_width="match_parent" |
||||||
|
android:layout_height="match_parent" |
||||||
|
android:fitsSystemWindows="true" |
||||||
|
android:orientation="vertical"> |
||||||
|
|
||||||
|
<include layout="@layout/toolbar" /> |
||||||
|
|
||||||
|
|
||||||
|
<!--添加标题和输入框--> |
||||||
|
<LinearLayout |
||||||
|
android:layout_width="match_parent" |
||||||
|
android:layout_height="wrap_content" |
||||||
|
android:layout_margin="10dp" |
||||||
|
android:orientation="vertical" |
||||||
|
android:padding="10dp"> |
||||||
|
|
||||||
|
<!--标题--> |
||||||
|
|
||||||
|
<TextView |
||||||
|
android:id="@+id/tv_title" |
||||||
|
android:layout_width="match_parent" |
||||||
|
android:layout_height="wrap_content" |
||||||
|
android:text="@string/text_register" |
||||||
|
android:textAlignment="center" |
||||||
|
android:textColor="@color/textPrimary" |
||||||
|
android:textSize="@dimen/text_senior_size" /> |
||||||
|
|
||||||
|
<TextView |
||||||
|
android:id="@+id/tv_register_tip" |
||||||
|
android:layout_width="wrap_content" |
||||||
|
android:layout_height="wrap_content" |
||||||
|
android:layout_marginTop="10dp" |
||||||
|
android:text="" |
||||||
|
android:textColor="@color/textError" |
||||||
|
android:visibility="gone" /> |
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputLayout |
||||||
|
android:id="@+id/et_email" |
||||||
|
android:layout_width="match_parent" |
||||||
|
android:layout_height="wrap_content" |
||||||
|
android:drawablePadding="10dp" |
||||||
|
app:counterEnabled="true" |
||||||
|
app:counterMaxLength="100"> |
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputEditText |
||||||
|
android:layout_width="match_parent" |
||||||
|
android:layout_height="wrap_content" |
||||||
|
android:hint="@string/et_email" |
||||||
|
android:inputType="text" /> |
||||||
|
|
||||||
|
</com.google.android.material.textfield.TextInputLayout> |
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputLayout |
||||||
|
android:id="@+id/et_password" |
||||||
|
android:visibility="gone" |
||||||
|
android:layout_width="match_parent" |
||||||
|
android:layout_height="wrap_content" |
||||||
|
android:drawablePadding="10dp" |
||||||
|
app:counterEnabled="true" |
||||||
|
app:counterMaxLength="16" |
||||||
|
app:passwordToggleEnabled="true" |
||||||
|
app:passwordToggleTintMode="src_in"> |
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputEditText |
||||||
|
android:layout_width="match_parent" |
||||||
|
android:layout_height="wrap_content" |
||||||
|
android:hint="@string/et_new_password_tip" |
||||||
|
android:inputType="textPassword" /> |
||||||
|
|
||||||
|
</com.google.android.material.textfield.TextInputLayout> |
||||||
|
|
||||||
|
<LinearLayout |
||||||
|
android:layout_width="match_parent" |
||||||
|
android:layout_height="wrap_content" |
||||||
|
android:orientation="horizontal"> |
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputLayout |
||||||
|
android:id="@+id/et_email_code" |
||||||
|
android:layout_width="match_parent" |
||||||
|
android:layout_height="wrap_content" |
||||||
|
android:layout_weight="1" |
||||||
|
android:drawablePadding="10dp" |
||||||
|
app:counterEnabled="true" |
||||||
|
app:counterMaxLength="6"> |
||||||
|
|
||||||
|
<com.google.android.material.textfield.TextInputEditText |
||||||
|
android:layout_width="match_parent" |
||||||
|
android:layout_height="wrap_content" |
||||||
|
android:hint="@string/et_email_captcha" |
||||||
|
android:inputType="text" /> |
||||||
|
|
||||||
|
</com.google.android.material.textfield.TextInputLayout> |
||||||
|
|
||||||
|
<TextView |
||||||
|
android:id="@+id/tv_get_email_code" |
||||||
|
android:layout_width="match_parent" |
||||||
|
android:layout_height="match_parent" |
||||||
|
android:layout_weight="2.5" |
||||||
|
android:gravity="center" |
||||||
|
android:text="@string/get_email_code" |
||||||
|
android:textColor="@color/selector_get_emali_code" |
||||||
|
android:textSize="@dimen/text_small_size" /> |
||||||
|
|
||||||
|
</LinearLayout> |
||||||
|
|
||||||
|
<!--登录按钮--> |
||||||
|
<Button |
||||||
|
android:id="@+id/bt_submit" |
||||||
|
android:layout_width="match_parent" |
||||||
|
android:layout_height="50dp" |
||||||
|
android:layout_marginTop="10dp" |
||||||
|
android:background="@drawable/login_btn_selector" |
||||||
|
android:enabled="false" |
||||||
|
android:text="@string/text_register" |
||||||
|
android:textAlignment="center" |
||||||
|
android:textColor="#ffffff" |
||||||
|
android:textSize="@dimen/text_large_size" /> |
||||||
|
|
||||||
|
</LinearLayout> |
||||||
|
|
||||||
|
</LinearLayout> |
@ -1,3 +1,3 @@ |
|||||||
#Fri Jun 18 21:45:31 CST 2021 |
#Fri Jun 18 21:45:31 CST 2021 |
||||||
VERSION_CODE=226 |
VERSION_CODE=227 |
||||||
NEED_CREATE_RELEASE=false |
NEED_CREATE_RELEASE=false |
||||||
|
Loading…
Reference in new issue