用户注册与登录

master
fengyuecanzhu 3 years ago
parent 98e8fdbb33
commit 59f950915a
  1. 7
      .idea/misc.xml
  2. 2
      app/build.gradle
  3. 1
      app/src/main/AndroidManifest.xml
  4. 4
      app/src/main/java/xyz/fycz/myreader/application/App.java
  5. 15
      app/src/main/java/xyz/fycz/myreader/base/MyTextWatcher.kt
  6. 5
      app/src/main/java/xyz/fycz/myreader/common/APPCONST.java
  7. 8
      app/src/main/java/xyz/fycz/myreader/common/URLCONST.java
  8. 10
      app/src/main/java/xyz/fycz/myreader/model/user/Result.kt
  9. 70
      app/src/main/java/xyz/fycz/myreader/model/user/User.java
  10. 6
      app/src/main/java/xyz/fycz/myreader/model/user/UserService.java
  11. 171
      app/src/main/java/xyz/fycz/myreader/model/user/UserService2.kt
  12. 225
      app/src/main/java/xyz/fycz/myreader/ui/activity/AuthEmailActivity.kt
  13. 138
      app/src/main/java/xyz/fycz/myreader/ui/activity/LoginActivity.java
  14. 263
      app/src/main/java/xyz/fycz/myreader/ui/activity/RegisterActivity.java
  15. 2
      app/src/main/java/xyz/fycz/myreader/ui/activity/SearchWordActivity.kt
  16. 102
      app/src/main/java/xyz/fycz/myreader/ui/fragment/MineFragment.java
  17. 9
      app/src/main/java/xyz/fycz/myreader/ui/presenter/BookcasePresenter.java
  18. 8
      app/src/main/java/xyz/fycz/myreader/util/help/StringHelper.java
  19. 2
      app/src/main/java/xyz/fycz/myreader/util/utils/AdUtils.java
  20. 2
      app/src/main/java/xyz/fycz/myreader/util/utils/FileUtils.java
  21. 5
      app/src/main/res/color/selector_get_emali_code.xml
  22. BIN
      app/src/main/res/drawable-xhdpi/bg_login.jpg
  23. 2
      app/src/main/res/drawable/login_btn_selector.xml
  24. 125
      app/src/main/res/layout/activity_auth_email.xml
  25. 290
      app/src/main/res/layout/activity_login.xml
  26. 292
      app/src/main/res/layout/activity_register.xml
  27. 4
      app/src/main/res/layout/fragment_mine.xml
  28. 1
      app/src/main/res/values/dimens.xml
  29. 13
      app/src/main/res/values/strings.xml
  30. 2
      app/version_code.properties

@ -6,21 +6,28 @@
<entry key="..\:/android/FYReader/app/src/main/res/drawable/ic_delete.xml" value="0.18518518518518517" />
<entry key="..\:/android/FYReader/app/src/main/res/drawable/ic_re_seg.xml" value="0.1962962962962963" />
<entry key="..\:/android/FYReader/app/src/main/res/drawable/ic_search_word.xml" value="0.21944444444444444" />
<entry key="..\:/android/FYReader/app/src/main/res/drawable/login_btn_selector.xml" value="0.17777777777777778" />
<entry key="..\:/android/FYReader/app/src/main/res/drawable/selector_btn_add.xml" value="0.17777777777777778" />
<entry key="..\:/android/FYReader/app/src/main/res/layout/activity_about.xml" value="0.12132725430597771" />
<entry key="..\:/android/FYReader/app/src/main/res/layout/activity_auth_email.xml" value="0.1897644927536232" />
<entry key="..\:/android/FYReader/app/src/main/res/layout/activity_donate.xml" value="0.536" />
<entry key="..\:/android/FYReader/app/src/main/res/layout/activity_feedback.xml" value="0.12132725430597771" />
<entry key="..\:/android/FYReader/app/src/main/res/layout/activity_file_picker.xml" value="0.2318840579710145" />
<entry key="..\:/android/FYReader/app/src/main/res/layout/activity_group_manager.xml" value="0.12132725430597771" />
<entry key="..\:/android/FYReader/app/src/main/res/layout/activity_login.xml" value="0.176" />
<entry key="..\:/android/FYReader/app/src/main/res/layout/activity_manage_group.xml" value="0.21195652173913043" />
<entry key="..\:/android/FYReader/app/src/main/res/layout/activity_more_setting.xml" value="0.264" />
<entry key="..\:/android/FYReader/app/src/main/res/layout/activity_read.xml" value="0.17028985507246377" />
<entry key="..\:/android/FYReader/app/src/main/res/layout/activity_register.xml" value="0.2796934865900383" />
<entry key="..\:/android/FYReader/app/src/main/res/layout/activity_search_book.xml" value="0.12132725430597771" />
<entry key="..\:/android/FYReader/app/src/main/res/layout/activity_search_word.xml" value="0.144" />
<entry key="..\:/android/FYReader/app/src/main/res/layout/dialog_loading.xml" value="0.1" />
<entry key="..\:/android/FYReader/app/src/main/res/layout/dialog_textview.xml" value="0.1947463768115942" />
<entry key="..\:/android/FYReader/app/src/main/res/layout/fingerprint_dialog.xml" value="0.20425724637681159" />
<entry key="..\:/android/FYReader/app/src/main/res/layout/fragment_file_category.xml" value="0.2318840579710145" />
<entry key="..\:/android/FYReader/app/src/main/res/layout/fragment_find_book_2.xml" value="0.12132725430597771" />
<entry key="..\:/android/FYReader/app/src/main/res/layout/fragment_local_source.xml" value="0.1947463768115942" />
<entry key="..\:/android/FYReader/app/src/main/res/layout/fragment_mine.xml" value="0.176" />
<entry key="..\:/android/FYReader/app/src/main/res/layout/fragment_private_bookcase.xml" value="0.21195652173913043" />
<entry key="..\:/android/FYReader/app/src/main/res/layout/fragment_webdav_setting.xml" value="0.4" />
<entry key="..\:/android/FYReader/app/src/main/res/layout/gridview_book_detailed_item.xml" value="0.1947463768115942" />

@ -185,8 +185,6 @@ dependencies {
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'io.alterac.blurkit:blurkit:1.1.0'
implementation 'com.google.android.material:material:1.1.0'
//Scroller

@ -121,6 +121,7 @@
<activity android:name=".ui.activity.FindBookActivity" />
<activity android:name=".ui.activity.GroupManagerActivity" />
<activity android:name=".ui.activity.SearchWordActivity" />
<activity android:name=".ui.activity.AuthEmailActivity" />
<receiver android:name=".util.notification.NotificationClickReceiver" />
<receiver android:name=".ui.presenter.BookcasePresenter$cancelDownloadReceiver" />

@ -247,7 +247,6 @@ public class App extends Application {
try {
PackageManager manager = application.getPackageManager();
PackageInfo info = manager.getPackageInfo(application.getPackageName(), 0);
return info.versionCode;
} catch (Exception e) {
e.printStackTrace();
@ -335,6 +334,9 @@ public class App extends Application {
forceUpdateVersion = Integer.parseInt(contents[8].substring(contents[8].indexOf(":") + 1));
spu.putInt("forceUpdateVersion", forceUpdateVersion);
String domain = contents[9].substring(contents[9].indexOf(":") + 1);
spu.putString("domain", domain);
int versionCode = getVersionCode();
isForceUpdate = isForceUpdate && forceUpdateVersion > versionCode;

@ -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) {
}
}

@ -21,8 +21,8 @@ import javax.script.ScriptEngineManager;
public class APPCONST {
public static String publicKey = "";//服务端公钥
public static final String KEY = "";
public static String publicKey = "fyds2.0";//服务端公钥
public static final String KEY = "readerByFengyue";
public static final String[] STORAGE_PERMISSIONS = new String[]{Permission.WRITE_EXTERNAL_STORAGE,
Permission.READ_EXTERNAL_STORAGE};
@ -99,6 +99,7 @@ public class APPCONST {
public static final int REQUEST_EDIT_BOOK = 1013;
public static final int REQUEST_GROUP_MANAGER = 1014;
public static final int REQUEST_SEARCH_WORD = 1015;
public static final int REQUEST_AUTH_EMAIL = 1016;
public static final int REQUEST_READ = 1;

@ -1,5 +1,7 @@
package xyz.fycz.myreader.common;
import xyz.fycz.myreader.util.SharedPreUtils;
public class URLCONST {
public static final String OFFICIAL_WEB = "https://reader.fycz.tk/";
@ -19,11 +21,15 @@ public class URLCONST {
public static final String YOU_DAO_SEARCH = "http://m.youdao.com/dict?le=eng&q={key}";
public static final String FY_READER_URL = "https://fyreader.fycz.tk";
public static final String DEFAULT_DOMAIN =
SharedPreUtils.getInstance().getString("domain", "fycz.tk");
public static final String FY_READER_URL = "https://fyreader." + DEFAULT_DOMAIN;
public static final String AD_URL = FY_READER_URL + "/ad";
public static final String LOG_UPLOAD_URL = FY_READER_URL + "/logUpload";
public static final String THANKS_URL = FY_READER_URL + "/thanks/";
public static final String USER_URL = "https://user." + DEFAULT_DOMAIN;
public static final String DONATE = "https://gitee.com/fengyuecanzhu/Donate/raw/master";

@ -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;
}
}

@ -1,4 +1,6 @@
package xyz.fycz.myreader.model.backup;
package xyz.fycz.myreader.model.user;
import android.content.Context;
import io.reactivex.annotations.NonNull;
import xyz.fycz.myreader.application.App;
@ -111,7 +113,7 @@ public class UserService {
public static boolean writeConfig(Map<String,String> userLoginInfo){
FileOutputStream fos = null;
try {
fos = App.getApplication().openFileOutput("userConfig.fy", App.getApplication().MODE_PRIVATE);
fos = App.getApplication().openFileOutput("userConfig.fy", Context.MODE_PRIVATE);
String userInfo = "username='" + userLoginInfo.get("loginName") + "',\npassword='" + userLoginInfo.get("loginPwd") + "'";
byte[] bs = userInfo.getBytes();
fos.write(bs);

@ -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()
}
}

@ -13,17 +13,26 @@ import android.view.MotionEvent;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.Toolbar;
import java.util.HashMap;
import java.util.Map;
import io.reactivex.disposables.Disposable;
import xyz.fycz.myreader.R;
import xyz.fycz.myreader.base.BaseActivity;
import xyz.fycz.myreader.base.BitIntentDataManager;
import xyz.fycz.myreader.base.observer.MySingleObserver;
import xyz.fycz.myreader.common.APPCONST;
import xyz.fycz.myreader.databinding.ActivityLoginBinding;
import xyz.fycz.myreader.model.backup.UserService;
import xyz.fycz.myreader.model.user.Result;
import xyz.fycz.myreader.model.user.User;
import xyz.fycz.myreader.model.user.UserService;
import xyz.fycz.myreader.model.user.UserService2;
import xyz.fycz.myreader.ui.dialog.DialogCreator;
import xyz.fycz.myreader.ui.dialog.LoadingDialog;
import xyz.fycz.myreader.util.CodeUtil;
import xyz.fycz.myreader.util.CyptoUtils;
import xyz.fycz.myreader.util.ToastUtils;
@ -40,23 +49,9 @@ public class LoginActivity extends BaseActivity implements TextWatcher {
private ActivityLoginBinding binding;
private String code;
@SuppressLint("HandlerLeak")
private Handler mHandler = new Handler() {
@SuppressLint("HandlerLeak")
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case 1:
binding.btLogin.setEnabled(true);
break;
case 2:
createCaptcha();
break;
}
}
};
private Disposable loginDisp;
private LoadingDialog dialog;
private User user;
@Override
protected void bindView() {
@ -74,13 +69,18 @@ public class LoginActivity extends BaseActivity implements TextWatcher {
@Override
protected void initData(Bundle savedInstanceState) {
super.initData(savedInstanceState);
dialog = new LoadingDialog(this, "正在登录", () -> {
if (loginDisp != null) {
loginDisp.dispose();
}
});
}
@Override
protected void initWidget() {
super.initWidget();
mHandler.sendMessage(mHandler.obtainMessage(2));
String username = UserService.readUsername();
createCaptcha();
String username = UserService2.INSTANCE.readUsername();
binding.etUser.getEditText().setText(username);
binding.etUser.getEditText().requestFocus(username.length());
//监听内容改变 -> 控制按钮的点击状态
@ -92,11 +92,10 @@ public class LoginActivity extends BaseActivity implements TextWatcher {
@Override
protected void initClick() {
super.initClick();
binding.ivCaptcha.setOnClickListener(v -> mHandler.sendMessage(mHandler.obtainMessage(2)));
binding.ivCaptcha.setOnClickListener(v -> createCaptcha());
binding.btLogin.setOnClickListener(v -> {
mHandler.sendMessage(mHandler.obtainMessage(2));
if (!code.toLowerCase().equals(binding.etCaptcha.getEditText().getText().toString().toLowerCase())){
if (!code.equalsIgnoreCase(binding.etCaptcha.getEditText().getText().toString())) {
DialogCreator.createTipDialog(this, "验证码错误!");
return;
}
@ -104,46 +103,48 @@ public class LoginActivity extends BaseActivity implements TextWatcher {
ToastUtils.showError("无网络连接!");
return;
}
ProgressUtils.show(this, "正在登陆...");
binding.btLogin.setEnabled(false);
final String loginName = binding.etUser.getEditText().getText().toString().trim();
String loginPwd = binding.etPassword.getEditText().getText().toString();
final Map<String, String> userLoginInfo = new HashMap<>();
userLoginInfo.put("loginName", loginName);
userLoginInfo.put("loginPwd", CyptoUtils.encode(APPCONST.KEY, loginPwd));
//验证用户名和密码
UserService.login(userLoginInfo, new ResultCallback() {
user = new User(loginName, CyptoUtils.encode(APPCONST.KEY, loginPwd));
dialog.show();
UserService2.INSTANCE.login(user).subscribe(new MySingleObserver<Result>() {
@Override
public void onFinish(Object o, int code) {
String result = (String) o;
String[] info = result.split(":");
int resultCode = Integer.parseInt(info[0].trim());
String resultName = info[1].trim();
//最后输出结果
if (resultCode == 102) {
UserService.writeConfig(userLoginInfo);
UserService.writeUsername(loginName);
Intent intent = new Intent();
intent.putExtra("isLogin", true);
setResult(Activity.RESULT_OK, intent);
finish();
ToastUtils.showSuccess(resultName);
public void onSubscribe(Disposable d) {
addDisposable(d);
loginDisp = d;
}
@Override
public void onSuccess(@NonNull Result result) {
if (result.getCode() == 102) {
loginSuccess();
ToastUtils.showSuccess(result.getResult().toString());
} else if (result.getCode() == 301) {
Intent intent = new Intent(LoginActivity.this, AuthEmailActivity.class);
BitIntentDataManager.getInstance().putData(intent, user);
startActivityForResult(intent, APPCONST.REQUEST_AUTH_EMAIL);
ToastUtils.showWarring(result.getResult().toString());
} else {
mHandler.sendMessage(mHandler.obtainMessage(1));
ProgressUtils.dismiss();
ToastUtils.showWarring(resultName);
ToastUtils.showWarring(result.getResult().toString());
}
binding.btLogin.setEnabled(false);
dialog.dismiss();
}
@Override
public void onError(Exception e) {
public void onError(Throwable e) {
ToastUtils.showError("登录失败\n" + e.getLocalizedMessage());
mHandler.sendMessage(mHandler.obtainMessage(1));
ProgressUtils.dismiss();
binding.btLogin.setEnabled(false);
dialog.dismiss();
createCaptcha();
}
});
});
binding.tvForgotPwd.setOnClickListener(v -> {
Intent intent = new Intent(LoginActivity.this, AuthEmailActivity.class);
startActivity(intent);
});
binding.tvRegister.setOnClickListener(v -> {
@ -152,6 +153,15 @@ public class LoginActivity extends BaseActivity implements TextWatcher {
});
}
private void loginSuccess() {
UserService2.INSTANCE.writeConfig(user);
UserService2.INSTANCE.writeUsername(user.getUserName());
Intent intent = new Intent();
intent.putExtra("isLogin", true);
setResult(Activity.RESULT_OK, intent);
finish();
}
public void createCaptcha() {
code = CodeUtil.getInstance().createCode();
Bitmap codeBitmap = CodeUtil.getInstance().createBitmap(code);
@ -163,21 +173,21 @@ public class LoginActivity extends BaseActivity implements TextWatcher {
* 当有控件获得焦点focus 自动弹出键盘
* 1. 点击软键盘的enter键 自动收回键盘
* 2. 代码控制 InputMethodManager
* requestFocus
* showSoftInput:显示键盘 必须先让这个view成为焦点requestFocus
*
* hideSoftInputFromWindow 隐藏键盘
* requestFocus
* showSoftInput:显示键盘 必须先让这个view成为焦点requestFocus
* <p>
* hideSoftInputFromWindow 隐藏键盘
*/
@Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN){
if (event.getAction() == MotionEvent.ACTION_DOWN) {
//隐藏键盘
//1.获取系统输入的管理器
InputMethodManager inputManager =
(InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
//2.隐藏键盘
inputManager.hideSoftInputFromWindow(binding.etUser.getWindowToken(),0);
inputManager.hideSoftInputFromWindow(binding.etUser.getWindowToken(), 0);
//3.取消焦点
View focusView = getCurrentFocus();
@ -209,18 +219,28 @@ public class LoginActivity extends BaseActivity implements TextWatcher {
//判断两个输入框是否有内容
if (binding.etUser.getEditText().getText().toString().length() > 0 &&
binding.etPassword.getEditText().getText().toString().length() > 0 &&
binding.etCaptcha.getEditText().getText().toString().length() > 0){
binding.etCaptcha.getEditText().getText().toString().length() > 0) {
//按钮可以点击
binding.btLogin.setEnabled(true);
}else{
} else {
//按钮不能点击
binding.btLogin.setEnabled(false);
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == Activity.RESULT_OK) {
if (requestCode == APPCONST.REQUEST_AUTH_EMAIL) {
loginSuccess();
}
}
}
@Override
protected void onDestroy() {
dialog.dismiss();
super.onDestroy();
ProgressUtils.dismiss();
}
}

@ -2,6 +2,7 @@ package xyz.fycz.myreader.ui.activity;
import android.annotation.SuppressLint;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.text.Editable;
@ -9,17 +10,28 @@ import android.text.TextWatcher;
import android.text.method.LinkMovementMethod;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.appcompat.widget.Toolbar;
import java.util.HashMap;
import java.util.Map;
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.MyTextWatcher;
import xyz.fycz.myreader.base.observer.MySingleObserver;
import xyz.fycz.myreader.common.APPCONST;
import xyz.fycz.myreader.databinding.ActivityRegisterBinding;
import xyz.fycz.myreader.model.backup.UserService;
import xyz.fycz.myreader.model.user.Result;
import xyz.fycz.myreader.model.user.User;
import xyz.fycz.myreader.model.user.UserService;
import xyz.fycz.myreader.model.user.UserService2;
import xyz.fycz.myreader.ui.dialog.DialogCreator;
import xyz.fycz.myreader.ui.dialog.LoadingDialog;
import xyz.fycz.myreader.util.CodeUtil;
import xyz.fycz.myreader.util.CyptoUtils;
import xyz.fycz.myreader.util.ToastUtils;
import xyz.fycz.myreader.util.utils.ProgressUtils;
import xyz.fycz.myreader.util.utils.StringUtils;
@ -36,27 +48,12 @@ public class RegisterActivity extends BaseActivity {
private String code;
private String username = "";
private String password = "";
private String rpPassword = "";
private String email = "";
private String emailCode = "";
private String keyc = "";
private String inputCode = "";
@SuppressLint("HandlerLeak")
private Handler mHandler = new Handler() {
@SuppressLint("HandlerLeak")
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case 1:
createCaptcha();
break;
case 2:
showTip((String) msg.obj);
break;
case 3:
binding.tvRegisterTip.setVisibility(View.GONE);
break;
}
}
};
private LoadingDialog dialog;
private Disposable disp;
@Override
protected void bindView() {
@ -71,164 +68,178 @@ public class RegisterActivity extends BaseActivity {
getSupportActionBar().setTitle("注册");
}
@Override
protected void initData(Bundle savedInstanceState) {
dialog = new LoadingDialog(this, "正在注册", () -> {
if (disp != null) {
disp.dispose();
}
});
}
@Override
protected void initWidget() {
super.initWidget();
mHandler.sendMessage(mHandler.obtainMessage(1));
createCaptcha();
binding.etUsername.requestFocus();
binding.etUsername.getEditText().addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
binding.etUsername.getEditText().addTextChangedListener(new MyTextWatcher() {
@Override
public void afterTextChanged(Editable s) {
StringUtils.isNotChinese(s);
username = s.toString();
if (username.length() < 6 || username.length() >14){
mHandler.sendMessage(mHandler.obtainMessage(2, "用户名必须在6-14位之间"));
} else if(!username.substring(0, 1).matches("^[A-Za-z]$")){
mHandler.sendMessage(mHandler.obtainMessage(2,
"用户名只能以字母开头"));
}else if(!username.matches("^[A-Za-z0-9-_]+$")){
mHandler.sendMessage(mHandler.obtainMessage(2,
"用户名只能由数字、字母、下划线、减号组成"));
}else {
mHandler.sendMessage(mHandler.obtainMessage(3));
if (username.length() < 6 || username.length() > 14) {
showTip("用户名必须在6-14位之间");
} else if (!username.substring(0, 1).matches("^[A-Za-z]$")) {
showTip("用户名只能以字母开头");
} else if (!username.matches("^[A-Za-z0-9-_]+$")) {
showTip("用户名只能由数字、字母、下划线、减号组成");
} else {
binding.tvRegisterTip.setVisibility(View.GONE);
}
checkNotNone();
}
});
binding.etPassword.getEditText().addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
binding.etPassword.getEditText().addTextChangedListener(new MyTextWatcher() {
@Override
public void afterTextChanged(Editable s) {
password = s.toString();
if (password.length() < 8 || password.length() > 16){
mHandler.sendMessage(mHandler.obtainMessage(2, "密码必须在8-16位之间"));
} else if(password.matches("^\\d+$")){
mHandler.sendMessage(mHandler.obtainMessage(2, "密码不能是纯数字"));
if (password.length() < 8 || password.length() > 16) {
showTip("密码必须在8-16位之间");
} else if (password.matches("^\\d+$")) {
showTip("密码不能是纯数字");
} else {
mHandler.sendMessage(mHandler.obtainMessage(3));
binding.tvRegisterTip.setVisibility(View.GONE);
}
checkNotNone();
}
});
binding.etRpPassword.getEditText().addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
binding.etEmail.getEditText().addTextChangedListener(new MyTextWatcher() {
@Override
public void afterTextChanged(Editable s) {
rpPassword = s.toString();
if (!rpPassword.equals(password)){
mHandler.sendMessage(mHandler.obtainMessage(2, "两次输入的密码不一致"));
email = s.toString();
if (!email.matches("^[_a-z0-9-]+(\\.[_a-z0-9-]+)*@[a-z0-9-]+(\\.[a-z0-9-]+)*(\\.[a-z]{2,})$")) {
showTip("邮箱格式错误");
} else {
mHandler.sendMessage(mHandler.obtainMessage(3));
binding.tvRegisterTip.setVisibility(View.GONE);
}
checkNotNone();
}
});
binding.etCaptcha.getEditText().addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
binding.etEmailCode.getEditText().addTextChangedListener(new MyTextWatcher() {
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
public void afterTextChanged(Editable s) {
emailCode = s.toString().trim();
checkNotNone();
}
});
binding.etCaptcha.getEditText().addTextChangedListener(new MyTextWatcher() {
@Override
public void afterTextChanged(Editable s) {
inputCode = s.toString().trim().toLowerCase();
if (!inputCode.equals(code.toLowerCase())){
mHandler.sendMessage(mHandler.obtainMessage(2, "验证码错误"));
if (!inputCode.equals(code.toLowerCase())) {
showTip("验证码错误");
} else {
mHandler.sendMessage(mHandler.obtainMessage(3));
binding.tvRegisterTip.setVisibility(View.GONE);
}
checkNotNone();
}
});
binding.tvAgreement.setMovementMethod(LinkMovementMethod.getInstance());
binding.cbAgreement.setMovementMethod(LinkMovementMethod.getInstance());
}
@Override
protected void initClick() {
super.initClick();
binding.ivCaptcha.setOnClickListener(v -> mHandler.sendMessage(mHandler.obtainMessage(1)));
binding.ivCaptcha.setOnClickListener(v -> createCaptcha());
binding.tvGetEmailCode.setOnClickListener(v -> {
if (!email.matches("^[_a-z0-9-]+(\\.[_a-z0-9-]+)*@[a-z0-9-]+(\\.[a-z0-9-]+)*(\\.[a-z]{2,})$")) {
ToastUtils.showWarring("请正确输入邮箱");
return;
}
dialog.show();
dialog.setmMessage("正在发送");
UserService2.INSTANCE.sendEmail(email, "reg", keyc).subscribe(new MySingleObserver<Result>() {
@Override
public void onSubscribe(Disposable d) {
addDisposable(d);
disp = d;
}
@Override
public void onSuccess(@NonNull Result result) {
if (result.getCode() == 106) {
ToastUtils.showSuccess("验证码发送成功");
keyc = result.getResult().toString();
timeDown(60);
} else {
ToastUtils.showWarring(result.getResult().toString());
}
dialog.dismiss();
}
@Override
public void onError(Throwable e) {
ToastUtils.showError("验证码发送失败:\n" + e.getLocalizedMessage());
dialog.dismiss();
}
});
});
binding.btRegister.setOnClickListener(v -> {
if (!username.matches("^[A-Za-z][A-Za-z0-9]{5,13}$")){
if (!username.matches("^[A-Za-z][A-Za-z0-9]{5,13}$")) {
DialogCreator.createTipDialog(this, "用户名格式错误",
"用户名必须在6-14位之间\n用户名只能以字母开头\n用户名只能由数字、字母、下划线、减号组成");
}else if(password.matches("^\\d+$") || !password.matches("^.{8,16}$")){
} else if (password.matches("^\\d+$") || !password.matches("^.{8,16}$")) {
DialogCreator.createTipDialog(this, "密码格式错误",
"密码必须在8-16位之间\n密码不能是纯数字");
}else if(!password.equals(rpPassword)){
DialogCreator.createTipDialog(this, "重复密码错误",
"两次输入的密码不一致");
}else if(!inputCode.trim().toLowerCase().equals(code.toLowerCase())){
} else if (!email.matches("^[_a-z0-9-]+(\\.[_a-z0-9-]+)*@[a-z0-9-]+(\\.[a-z0-9-]+)*(\\.[a-z]{2,})$")) {
DialogCreator.createTipDialog(this, "邮箱格式错误",
"电子邮箱的正确写法为:用户名@邮箱网站.com(.cn等)");
} else if ("".equals(keyc)) {
DialogCreator.createTipDialog(this, "请先获取邮箱验证码");
} else if (emailCode.length() < 6) {
DialogCreator.createTipDialog(this, "请输入6位邮箱验证码");
} else if (!inputCode.trim().equalsIgnoreCase(code)) {
DialogCreator.createTipDialog(this, "验证码错误");
}else if(!binding.cbAgreement.isChecked()){
} else if (!binding.cbAgreement.isChecked()) {
DialogCreator.createTipDialog(this, "请勾选同意《用户服务协议》");
}else {
ProgressUtils.show(this, "正在注册...");
Map<String, String> userRegisterInfo = new HashMap<>();
userRegisterInfo.put("username", username);
userRegisterInfo.put("password", password);
UserService.register(userRegisterInfo, new ResultCallback() {
} else {
dialog.show();
dialog.setmMessage("正在注册");
User user = new User(username, CyptoUtils.encode(APPCONST.KEY, password), email);
UserService2.INSTANCE.register(user, emailCode, keyc).subscribe(new MySingleObserver<Result>() {
@Override
public void onFinish(Object o, int code) {
String[] info = ((String) o).split(":");
int result = Integer.parseInt(info[0].trim());
if (result == 101){
UserService.writeUsername(username);
ToastUtils.showSuccess(info[1]);
public void onSubscribe(Disposable d) {
addDisposable(d);
disp = d;
}
@Override
public void onSuccess(@NonNull Result result) {
if (result.getCode() == 101) {
UserService2.INSTANCE.writeUsername(user.getUserName());
ToastUtils.showSuccess(result.getResult().toString());
finish();
}else {
ToastUtils.showWarring(info[1]);
} else {
ToastUtils.showWarring(result.getResult().toString());
}
ProgressUtils.dismiss();
dialog.dismiss();
}
@Override
public void onError(Exception e) {
public void onError(Throwable e) {
ToastUtils.showError("注册失败:\n" + e.getLocalizedMessage());
ProgressUtils.dismiss();
dialog.dismiss();
createCaptcha();
}
});
}
mHandler.sendMessage(mHandler.obtainMessage(1));
});
}
public void createCaptcha() {
@ -242,17 +253,29 @@ public class RegisterActivity extends BaseActivity {
binding.tvRegisterTip.setText(tip);
}
public void checkNotNone(){
if ("".equals(username) || "".equals(password) || "".equals(rpPassword) || "".equals(inputCode)){
binding.btRegister.setEnabled(false);
}else {
binding.btRegister.setEnabled(true);
private void timeDown(int time) {
if (time == 0) {
binding.tvGetEmailCode.setText(getString(R.string.re_get_email_code, ""));
binding.tvGetEmailCode.setEnabled(true);
} else {
binding.tvGetEmailCode.setEnabled(false);
String timeStr = "(" + time + ")";
binding.tvGetEmailCode.setText(getString(R.string.re_get_email_code, timeStr));
App.getHandler().postDelayed(() -> timeDown(time - 1), 1000);
}
}
public void checkNotNone() {
binding.btRegister.setEnabled(!"".equals(username) &&
!"".equals(password) &&
!"".equals(email) &&
!"".equals(emailCode) &&
!"".equals(inputCode));
}
@Override
protected void onDestroy() {
dialog.dismiss();
super.onDestroy();
ProgressUtils.dismiss();
}
}

@ -165,7 +165,7 @@ class SearchWordActivity : BaseActivity() {
private fun search() {
val keyword = binding.etSearchKey.text.toString()
if (keyword.isNotEmpty() && this.keyword != keyword) {
if (keyword.isNotEmpty() && (this.keyword != keyword || adapter.itemSize == 0)) {
this.keyword = keyword
adapter.clear()
binding.fabSearchStop.visibility = View.VISIBLE

@ -2,7 +2,6 @@ package xyz.fycz.myreader.ui.fragment;
import android.annotation.SuppressLint;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
@ -13,12 +12,12 @@ import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import com.kongzue.dialogx.dialogs.BottomMenu;
import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
@ -37,30 +36,29 @@ import xyz.fycz.myreader.common.APPCONST;
import xyz.fycz.myreader.databinding.FragmentMineBinding;
import xyz.fycz.myreader.entity.Setting;
import xyz.fycz.myreader.greendao.entity.Book;
import xyz.fycz.myreader.greendao.entity.ReadRecord;
import xyz.fycz.myreader.greendao.service.BookService;
import xyz.fycz.myreader.model.backup.UserService;
import xyz.fycz.myreader.model.storage.Backup;
import xyz.fycz.myreader.model.user.Result;
import xyz.fycz.myreader.model.user.User;
import xyz.fycz.myreader.model.user.UserService;
import xyz.fycz.myreader.model.storage.BackupRestoreUi;
import xyz.fycz.myreader.model.storage.BackupRestoreUiKt;
import xyz.fycz.myreader.model.storage.Restore;
import xyz.fycz.myreader.model.storage.WebDavHelp;
import xyz.fycz.myreader.model.user.UserService2;
import xyz.fycz.myreader.ui.activity.AboutActivity;
import xyz.fycz.myreader.ui.activity.AdSettingActivity;
import xyz.fycz.myreader.ui.activity.BookSourceActivity;
import xyz.fycz.myreader.ui.activity.DonateActivity;
import xyz.fycz.myreader.ui.activity.FeedbackActivity;
import xyz.fycz.myreader.ui.activity.LoginActivity;
import xyz.fycz.myreader.ui.activity.MainActivity;
import xyz.fycz.myreader.ui.activity.MoreSettingActivity;
import xyz.fycz.myreader.ui.activity.ReadRecordActivity;
import xyz.fycz.myreader.ui.dialog.DialogCreator;
import xyz.fycz.myreader.ui.dialog.LoadingDialog;
import xyz.fycz.myreader.ui.dialog.MyAlertDialog;
import xyz.fycz.myreader.util.SharedPreUtils;
import xyz.fycz.myreader.util.ToastUtils;
import xyz.fycz.myreader.util.utils.GsonExtensionsKt;
import xyz.fycz.myreader.util.utils.ImageLoader;
import xyz.fycz.myreader.util.utils.NetworkUtils;
import xyz.fycz.myreader.util.utils.StoragePermissionUtils;
import xyz.fycz.myreader.webapi.ResultCallback;
import static android.app.Activity.RESULT_OK;
@ -73,20 +71,23 @@ public class MineFragment extends BaseFragment {
private FragmentMineBinding binding;
//private boolean isLogin;
private boolean isLogin;
private Setting mSetting;
// private String[] webSynMenu;
private String[] webSynMenu;
private String[] backupMenu;
// private AlertDialog themeModeDia;
private int themeMode;
private String[] themeModeArr;
private User user;
private Disposable disp;
private LoadingDialog dialog;
@SuppressLint("HandlerLeak")
private Handler mHandler = new Handler() {
@Override
public void handleMessage(@NonNull Message msg) {
switch (msg.what) {
case 1:
//binding.tvUser.setText("登录/注册");
binding.tvUser.setText("登录/注册");
break;
case 2:
backup();
@ -110,34 +111,40 @@ public class MineFragment extends BaseFragment {
@Override
protected void initData(Bundle savedInstanceState) {
super.initData(savedInstanceState);
//isLogin = UserService.isLogin();
user = UserService2.INSTANCE.readConfig();
isLogin = user != null && !TextUtils.isEmpty(user.getUserName());
mSetting = SysManager.getSetting();
/*webSynMenu = new String[]{
webSynMenu = new String[]{
App.getmContext().getString(R.string.menu_backup_webBackup),
App.getmContext().getString(R.string.menu_backup_webRestore),
App.getmContext().getString(R.string.menu_backup_autoSyn)
};*/
};
backupMenu = new String[]{
App.getmContext().getResources().getString(R.string.menu_backup_backup),
App.getmContext().getResources().getString(R.string.menu_backup_restore),
};
themeMode = App.getApplication().isNightFS() ? 0 : mSetting.isDayStyle() ? 1 : 2;
themeModeArr = getResources().getStringArray(R.array.theme_mode_arr);
dialog = new LoadingDialog(getContext(), "正在同步", (LoadingDialog.OnCancelListener) () -> {
if (disp != null) {
disp.dispose();
}
});
}
@Override
protected void initWidget(Bundle savedInstanceState) {
super.initWidget(savedInstanceState);
/*if (isLogin) {
binding.tvUser.setText(UserService.readUsername());
}*/
if (isLogin) {
binding.tvUser.setText(user.getUserName());
}
binding.tvThemeModeSelect.setText(themeModeArr[themeMode]);
}
@Override
protected void initClick() {
super.initClick();
/*binding.mineRlUser.setOnClickListener(v -> {
binding.mineRlUser.setOnClickListener(v -> {
if (isLogin) {
DialogCreator.createCommonDialog(getActivity(), "退出登录", "确定要退出登录吗?"
, true, (dialog, which) -> {
@ -156,7 +163,7 @@ public class MineFragment extends BaseFragment {
Intent intent = new Intent(getActivity(), LoginActivity.class);
getActivity().startActivityForResult(intent, APPCONST.REQUEST_LOGIN);
}
});*/
});
binding.mineRlWebdav.setOnClickListener(v -> {
Intent intent = new Intent(getActivity(), MoreSettingActivity.class);
@ -164,7 +171,7 @@ public class MineFragment extends BaseFragment {
startActivity(intent);
});
binding.mineRlSyn.setOnClickListener(v -> {
/*binding.mineRlSyn.setOnClickListener(v -> {
String account = SharedPreUtils.getInstance().getString("webdavAccount");
String password = SharedPreUtils.getInstance().getString("webdavPassword");
if (TextUtils.isEmpty(account) || TextUtils.isEmpty(password)) {
@ -182,6 +189,7 @@ public class MineFragment extends BaseFragment {
public void onSubscribe(Disposable d) {
addDisposable(d);
}
@Override
public void onSuccess(ArrayList<String> strings) {
if (!WebDavHelp.INSTANCE.showRestoreDialog(strings, new Restore.CallBack() {
@ -204,7 +212,7 @@ public class MineFragment extends BaseFragment {
}
}
});
});
});*/
binding.mineRlBookSource.setOnClickListener(v -> {
startActivity(new Intent(getContext(), BookSourceActivity.class));
});
@ -239,8 +247,8 @@ public class MineFragment extends BaseFragment {
return false;
}).setCancelButton(R.string.cancel);
});
/*binding.mineRlSyn.setOnClickListener(v -> {
if (!UserService.isLogin()) {
binding.mineRlSyn.setOnClickListener(v -> {
if (!isLogin) {
ToastUtils.showWarring("请先登录!");
Intent loginIntent = new Intent(getActivity(), LoginActivity.class);
getActivity().startActivityForResult(loginIntent, APPCONST.REQUEST_LOGIN);
@ -278,7 +286,7 @@ public class MineFragment extends BaseFragment {
.setNegativeButton(null, null)
.setPositiveButton(null, null)
.show();
});*/
});
binding.mineRlReadRecord.setOnClickListener(v -> {
startActivity(new Intent(getContext(), ReadRecordActivity.class));
@ -470,10 +478,17 @@ public class MineFragment extends BaseFragment {
SharedPreUtils spb = SharedPreUtils.getInstance();
String synTime = spb.getString(getString(R.string.synTime));
if (!nowTimeStr.equals(synTime) || !isAutoSyn) {
UserService.webBackup(new ResultCallback() {
dialog.show();
UserService2.INSTANCE.webBackup(user).subscribe(new MySingleObserver<Result>() {
@Override
public void onSubscribe(Disposable d) {
addDisposable(d);
disp = d;
}
@Override
public void onFinish(Object o, int code) {
if ((boolean) o) {
public void onSuccess(@NonNull Result result) {
if (result.getCode() == 104) {
spb.putString(getString(R.string.synTime), nowTimeStr);
if (!isAutoSyn) {
DialogCreator.createTipDialog(getContext(), "成功将书架同步至网络!");
@ -483,16 +498,19 @@ public class MineFragment extends BaseFragment {
DialogCreator.createTipDialog(getContext(), "同步失败,请重试!");
}
}
dialog.dismiss();
}
@Override
public void onError(Exception e) {
public void onError(Throwable e) {
if (!isAutoSyn) {
DialogCreator.createTipDialog(getContext(), "同步失败,请重试!\n" + e.getLocalizedMessage());
}
dialog.dismiss();
}
});
}
}
/**
@ -516,10 +534,17 @@ public class MineFragment extends BaseFragment {
} else {
DialogCreator.createTipDialog(getContext(), "未找到同步文件,同步失败!");
}*/
UserService.webRestore(new ResultCallback() {
dialog.show();
UserService2.INSTANCE.webRestore(user).subscribe(new MySingleObserver<Result>() {
@Override
public void onFinish(Object o, int code) {
if ((boolean) o) {
public void onSubscribe(Disposable d) {
addDisposable(d);
disp = d;
}
@Override
public void onSuccess(@NonNull Result result) {
if (result.getCode() < 200) {
mHandler.sendMessage(mHandler.obtainMessage(7));
// DialogCreator.createTipDialog(mMainActivity,
// "恢复成功!\n注意:本功能属于实验功能,书架恢复后,书籍初次加载时可能加载失败,返回重新加载即可!");、
@ -532,10 +557,12 @@ public class MineFragment extends BaseFragment {
} else {
DialogCreator.createTipDialog(getContext(), "未找到同步文件,同步失败!");
}
dialog.dismiss();
}
@Override
public void onError(Exception e) {
public void onError(Throwable e) {
DialogCreator.createTipDialog(getContext(), "未找到同步文件,同步失败!\n" + e.getLocalizedMessage());
DialogCreator.createTipDialog(getContext(), "未找到同步文件,同步失败!\n" + e.getLocalizedMessage());
}
});
@ -547,13 +574,14 @@ public class MineFragment extends BaseFragment {
public void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
if (resultCode == RESULT_OK) {
switch (requestCode) {
/*case APPCONST.REQUEST_LOGIN:
case APPCONST.REQUEST_LOGIN:
assert data != null;
isLogin = data.getBooleanExtra("isLogin", false);
if (isLogin) {
binding.tvUser.setText(UserService.readUsername());
user = UserService2.INSTANCE.readConfig();
if (isLogin && user != null) {
binding.tvUser.setText(user.getUserName());
}
break;*/
break;
}
}
}

@ -6,23 +6,19 @@ import android.app.Notification;
import android.app.PendingIntent;
import android.content.*;
import android.graphics.BitmapFactory;
import android.os.Build;
import android.os.Handler;
import android.os.Message;
import android.text.TextUtils;
import android.view.Gravity;
import android.view.MenuItem;
import android.view.View;
import android.widget.PopupMenu;
import androidx.core.app.ActivityCompat;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.ItemTouchHelper;
import androidx.recyclerview.widget.LinearLayoutManager;
import com.hjq.permissions.OnPermissionCallback;
import com.hjq.permissions.Permission;
import com.hjq.permissions.XXPermissions;
import com.kongzue.dialogx.dialogs.BottomMenu;
@ -31,7 +27,6 @@ import org.jetbrains.annotations.NotNull;
import java.text.Collator;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.List;
@ -39,7 +34,6 @@ import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import io.reactivex.Observable;
import io.reactivex.Observer;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
import xyz.fycz.myreader.R;
@ -55,12 +49,11 @@ import xyz.fycz.myreader.webapi.ResultCallback;
import xyz.fycz.myreader.common.APPCONST;
import xyz.fycz.myreader.greendao.entity.BookGroup;
import xyz.fycz.myreader.greendao.service.BookGroupService;
import xyz.fycz.myreader.model.backup.UserService;
import xyz.fycz.myreader.model.user.UserService;
import xyz.fycz.myreader.ui.activity.*;
import xyz.fycz.myreader.webapi.crawler.base.ReadCrawler;
import xyz.fycz.myreader.webapi.crawler.ReadCrawlerUtil;
import xyz.fycz.myreader.ui.dialog.DialogCreator;
import xyz.fycz.myreader.widget.custom.DragSortGridView;
import xyz.fycz.myreader.entity.Setting;
import xyz.fycz.myreader.enums.BookcaseStyle;
import xyz.fycz.myreader.greendao.entity.Book;

@ -88,7 +88,7 @@ public class StringHelper {
//生成随机数字和字母,
public static String getStringRandom(int length) {
String val = "";
StringBuilder val = new StringBuilder();
Random random = new Random();
//参数length,表示生成几位随机数
@ -98,12 +98,12 @@ public class StringHelper {
if( "char".equalsIgnoreCase(charOrNum) ) {
//输出是大写字母还是小写字母
int temp = random.nextInt(2) % 2 == 0 ? 65 : 97;
val += (char)(random.nextInt(26) + temp);
val.append((char) (random.nextInt(26) + temp));
} else if( "num".equalsIgnoreCase(charOrNum) ) {
val += String.valueOf(random.nextInt(10));
val.append(String.valueOf(random.nextInt(10)));
}
}
return val;
return val.toString();
}
public static String jidToUsername(String jid){

@ -13,7 +13,7 @@ import okhttp3.MediaType;
import okhttp3.RequestBody;
import xyz.fycz.myreader.base.observer.MySingleObserver;
import xyz.fycz.myreader.common.URLCONST;
import xyz.fycz.myreader.model.backup.UserService;
import xyz.fycz.myreader.model.user.UserService;
import xyz.fycz.myreader.util.SharedPreUtils;
import xyz.fycz.myreader.util.help.DateHelper;

@ -316,12 +316,10 @@ public class FileUtils {
public static void write(Context context, String fileName, String content) {
if (content == null)
content = "";
try {
FileOutputStream fos = context.openFileOutput(fileName,
Context.MODE_PRIVATE);
fos.write(content.getBytes());
fos.close();
} catch (Exception e) {
e.printStackTrace();

@ -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>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 134 KiB

@ -4,7 +4,7 @@
<item android:state_enabled="false">
<shape android:shape="rectangle">
<corners android:radius="5dp"/>
<solid android:color="#666666"/>
<solid android:color="@color/textSecondary"/>
</shape>
</item>

@ -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,241 +1,133 @@
<?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:background="@color/colorBackground"
android:fitsSystemWindows="true"
android:orientation="vertical">
<include layout="@layout/toolbar" />
<RelativeLayout
<!--添加标题和输入框-->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<!--背景图片-->
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="fitXY"
app:srcCompat="@drawable/bg_login" />
<!--添加虚化层-->
<io.alterac.blurkit.BlurLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
app:blk_blurRadius="5"
app:blk_fps="0" />
<!-- 猫头鹰-->
<!-- <RelativeLayout-->
<!-- android:layout_width="300dp"-->
<!-- android:layout_height="200dp"-->
<!-- android:layout_centerHorizontal="true"-->
<!-- android:layout_alignTop="@+id/bg"-->
<!-- android:layout_marginTop="-75dp">-->
<!-- &lt;!&ndash;头像&ndash;&gt;-->
<!-- <ImageView-->
<!-- android:id="@+id/iv_head"-->
<!-- android:layout_width="wrap_content"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:src="@drawable/owl_head"-->
<!-- android:layout_centerHorizontal="true"-->
<!-- />-->
<!-- &lt;!&ndash;手掌&ndash;&gt;-->
<!-- <ImageView-->
<!-- android:id="@+id/iv_left_hand"-->
<!-- android:layout_width="50dp"-->
<!-- android:layout_height="60dp"-->
<!-- android:src="@drawable/icon_hand"-->
<!-- android:layout_alignParentLeft="true"-->
<!-- android:layout_alignBottom="@+id/iv_head"-->
<!-- android:layout_marginBottom="-25dp"-->
<!-- android:layout_marginLeft="10dp"/>-->
<!-- <ImageView-->
<!-- android:id="@+id/iv_right_hand"-->
<!-- android:layout_width="50dp"-->
<!-- android:layout_height="60dp"-->
<!-- android:src="@drawable/icon_hand"-->
<!-- android:layout_alignParentRight="true"-->
<!-- android:layout_alignBottom="@+id/iv_head"-->
<!-- android:layout_marginBottom="-25dp"-->
<!-- android:layout_marginRight="10dp"/>-->
<!-- &lt;!&ndash;翅膀&ndash;&gt;-->
<!-- <ImageView-->
<!-- android:id="@+id/iv_left_arm"-->
<!-- android:layout_width="65dp"-->
<!-- android:layout_height="40dp"-->
<!-- android:src="@drawable/arm_left"-->
<!-- android:layout_below="@+id/iv_head"-->
<!-- android:layout_alignParentLeft="true"-->
<!-- android:layout_marginLeft="20dp"/>-->
<!-- <ImageView-->
<!-- android:id="@+id/iv_right_arm"-->
<!-- android:layout_width="65dp"-->
<!-- android:layout_height="40dp"-->
<!-- android:src="@drawable/arm_right"-->
<!-- android:layout_below="@+id/iv_head"-->
<!-- android:layout_alignParentRight="true"-->
<!-- android:layout_marginRight="20dp"/>-->
<!-- </RelativeLayout>-->
<View
android:id="@+id/bg"
android:layout_width="match_parent"
android:layout_height="280dp"
android:layout_centerInParent="true"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:background="@drawable/input_bg_shape" />
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:orientation="vertical"
android:padding="10dp">
<io.alterac.blurkit.BlurLayout
<!--标题-->
<TextView
android:layout_width="match_parent"
android:layout_height="280dp"
android:layout_centerInParent="true"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
app:blk_blurRadius="20"
app:blk_fps="0" />
<!--添加标题和输入框-->
<LinearLayout
android:layout_height="wrap_content"
android:text="@string/text_login"
android:textAlignment="center"
android:textColor="@color/textPrimary"
android:textSize="@dimen/text_senior_size" />
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/et_user"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:orientation="vertical"
android:padding="20dp">
android:layout_marginTop="20dp"
android:drawablePadding="10dp"
app:counterEnabled="true"
app:counterMaxLength="14">
<!--标题-->
<TextView
<com.google.android.material.textfield.TextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/text_login"
android:textAlignment="center"
android:textColor="@color/textSecondary"
android:textSize="20dp" />
<!--添加输入框-->
<!--<EditText
android:id="@+id/et_user"
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="@drawable/editview_shape"
android:drawableStart="@drawable/iconfont_user"
android:drawablePadding="10dp"
android:hint="@string/et_account_tip"
android:inputType="text"
android:maxLines="1"
android:paddingStart="10dp"
android:textSize="18dp" />-->
android:inputType="text" />
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/et_user"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:drawablePadding="10dp"
app:counterEnabled="true"
app:counterMaxLength="14">
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/et_account_tip"
android:inputType="text"/>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/et_password"
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.TextInputLayout>
<!--<EditText
android:id="@+id/et_password"
style="@style/EditTextStyle"
android:background="@drawable/editview_shape"
android:drawableStart="@drawable/iconfont_password"
<com.google.android.material.textfield.TextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/et_password_tip"
android:inputType="textPassword"
android:textSize="18dp" />-->
android:inputType="textPassword" />
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/et_password"
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.TextInputLayout>
<com.google.android.material.textfield.TextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/et_password_tip"
android:inputType="textPassword"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
</com.google.android.material.textfield.TextInputLayout>
<LinearLayout
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/et_captcha"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
android:layout_weight="1"
android:drawablePadding="10dp"
app:counterEnabled="true"
app:counterMaxLength="4">
<!--<EditText
android:id="@+id/et_captcha"
style="@style/EditTextStyle"
android:layout_width="match_parent"
android:layout_weight="1"
android:background="@drawable/editview_shape"
android:hint="@string/et_rp_captcha"
android:inputType="text"
android:textSize="18dp" />-->
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/et_captcha"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:drawablePadding="10dp"
app:counterEnabled="true"
app:counterMaxLength="4">
<com.google.android.material.textfield.TextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/et_rp_captcha"
android:inputType="text"/>
</com.google.android.material.textfield.TextInputLayout>
<ImageView
android:id="@+id/iv_captcha"
<com.google.android.material.textfield.TextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="3"
android:layout_gravity="center_vertical"
android:paddingStart="7dp" />
</LinearLayout>
<!--登录按钮-->
<Button
android:id="@+id/bt_login"
android:hint="@string/et_rp_captcha"
android:inputType="text" />
</com.google.android.material.textfield.TextInputLayout>
<ImageView
android:id="@+id/iv_captcha"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_marginTop="20dp"
android:background="@drawable/login_btn_selector"
android:enabled="false"
android:text="@string/text_login"
android:textAlignment="center"
android:textColor="@color/textPrimaryInverted"
android:textSize="25dp" />
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_weight="2"
android:paddingStart="7dp"
tools:ignore="RtlSymmetry" />
</LinearLayout>
<!--登录按钮-->
<Button
android:id="@+id/bt_login"
android:layout_width="match_parent"
android:layout_height="45dp"
android:layout_marginTop="20dp"
android:background="@drawable/login_btn_selector"
android:enabled="false"
android:text="@string/text_login"
android:textAlignment="center"
android:textColor="@color/textPrimaryInverted"
android:textSize="@dimen/text_large_size" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp">
<TextView
android:id="@+id/tv_register"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:text="@string/tv_register"
android:textColor="@color/colorAccent" />
</LinearLayout>
</RelativeLayout>
<TextView
android:id="@+id/tv_forgot_pwd"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:text="@string/tv_forget_pwd"
android:textColor="@color/colorAccent" />
</RelativeLayout>
</LinearLayout>
</LinearLayout>

@ -1,6 +1,7 @@
<?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"
@ -8,198 +9,177 @@
<include layout="@layout/toolbar" />
<RelativeLayout
<!--添加标题和输入框-->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<!--背景图片-->
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="fitXY"
app:srcCompat="@drawable/bg_login" />
<!--添加虚化层-->
<io.alterac.blurkit.BlurLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
app:blk_blurRadius="5"
app:blk_fps="0" />
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:orientation="vertical"
android:padding="10dp">
<View
android:id="@+id/bg"
android:layout_width="match_parent"
android:layout_height="280dp"
android:layout_centerInParent="true"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:background="@drawable/input_bg_shape" />
<!--标题-->
<io.alterac.blurkit.BlurLayout
<TextView
android:layout_width="match_parent"
android:layout_height="400dp"
android:layout_centerInParent="true"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
app:blk_blurRadius="20"
app:blk_fps="0" />
<!--添加标题和输入框-->
<LinearLayout
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_username"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:orientation="vertical"
android:padding="20dp">
android:layout_marginTop="10dp"
android:drawablePadding="10dp"
app:counterEnabled="true"
app:counterMaxLength="14">
<!--标题-->
<TextView
<com.google.android.material.textfield.TextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/text_register"
android:textAlignment="center"
android:textColor="@color/sys_word_little"
android:textSize="20dp" />
android:hint="@string/et_account_tip"
android:inputType="text" />
</com.google.android.material.textfield.TextInputLayout>
<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_username"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:drawablePadding="10dp"
app:counterEnabled="true"
app:counterMaxLength="14">
<com.google.android.material.textfield.TextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/et_account_tip"
android:inputType="text"/>
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/et_password"
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_password_tip"
android:inputType="textPassword" />
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/et_password"
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.TextInputLayout>
<com.google.android.material.textfield.TextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/et_password_tip"
android:inputType="textPassword"/>
<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.TextInputLayout>
<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>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/et_rp_password"
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">
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_password_tip"
android:inputType="textPassword"/>
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>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/et_captcha"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:drawablePadding="10dp"
app:counterEnabled="true"
app:counterMaxLength="4">
<TextView
android:id="@+id/tv_get_email_code"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:textColor="@color/selector_get_emali_code"
android:text="@string/get_email_code"
android:textSize="@dimen/text_small_size"
android:layout_weight="2.5" />
<com.google.android.material.textfield.TextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="@string/et_rp_captcha"
android:inputType="text"/>
</LinearLayout>
</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_captcha"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:drawablePadding="10dp"
app:counterEnabled="true"
app:counterMaxLength="4">
<ImageView
android:id="@+id/iv_captcha"
<com.google.android.material.textfield.TextInputEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_weight="3"
android:paddingStart="7dp" />
android:hint="@string/et_rp_captcha"
android:inputType="text" />
</com.google.android.material.textfield.TextInputLayout>
</LinearLayout>
<!--登录按钮-->
<Button
android:id="@+id/bt_register"
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="25dp" />
<LinearLayout
<ImageView
android:id="@+id/iv_captcha"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:orientation="horizontal">
<CheckBox
android:id="@+id/cb_agreement"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/text_agreement_tip"
android:textColor="@color/textSecondaryInverted"
android:theme="@style/MyCheckBox" />
android:layout_gravity="center_vertical"
android:layout_weight="2.5"
android:paddingStart="7dp"
tools:ignore="RtlSymmetry" />
<TextView
android:id="@+id/tv_agreement"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/link_agreement"
android:textColor="@color/colorAccent"
android:textSize="14dp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="》"
android:textColor="@color/textSecondaryInverted" />
</LinearLayout>
</LinearLayout>
</RelativeLayout>
<!--登录按钮-->
<Button
android:id="@+id/bt_register"
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" />
<CheckBox
android:id="@+id/cb_agreement"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:textColorLink="@color/colorAccent"
android:text="@string/text_agreement_tip"
android:textColor="@color/textPrimary"
android:theme="@style/MyCheckBox" />
</LinearLayout>
</LinearLayout>

@ -13,7 +13,7 @@
android:layout_height="match_parent"
android:orientation="vertical">
<!--<RelativeLayout
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="25dp"
android:paddingLeft="5dp"
@ -56,7 +56,7 @@
android:textSize="@dimen/text_medium_size"
android:text="登录/注册"/>
</RelativeLayout>-->
</RelativeLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="25dp"

@ -22,6 +22,7 @@
<dimen name="text_small_size">14sp</dimen>
<dimen name="text_normal_size">16sp</dimen>
<dimen name="text_medium_size">18sp</dimen>
<dimen name="text_senior_size">20sp</dimen>
<dimen name="text_large_size">22sp</dimen>
<dimen name="default_padding_top">5dp</dimen>
<dimen name="default_padding_bottom">5dp</dimen>

@ -89,15 +89,16 @@
<string name="stop_download_tip">停止</string>
<string name="text_login">登录</string>
<string name="tv_register">新用户注册</string>
<string name="tv_forget_pwd">忘记密码</string>
<string name="et_password_tip">请输入密码</string>
<string name="et_rp_password_tip">请再次输入密码</string>
<string name="et_new_password_tip">请输入新密码</string>
<string name="et_email">请输入邮箱</string>
<string name="et_rp_captcha">请输入验证码</string>
<string name="et_email_captcha">请输入邮箱验证码</string>
<string name="et_account_tip">请输入用户名</string>
<string name="text_register">注册</string>
<string name="text_agreement_tip">我已阅读并同意《</string>
<string name="link_agreement">
<a href="https://shimo.im/docs/RgkDpd3D3Gp6t3rD">用户服务协议</a>
</string>
<string name="text_agreement_tip">我已阅读并同意《<a href="https://shimo.im/docs/RgkDpd3D3Gp6t3rD">用户服务协议</a></string>
<string name="add_book_mark">添加书签</string>
<string name="share_app">分享软件</string>
<string name="update_log">更新日志</string>
@ -515,6 +516,8 @@
<string name="search_word">内容搜索</string>
<string name="search_word_tip">搜索书籍已缓存的内容</string>
<string name="clear_result">清除搜索结果</string>
<string name="get_email_code">发送验证码</string>
<string name="re_get_email_code">重新发送%s</string>
<string-array name="reset_screen_time">

@ -1,3 +1,3 @@
#Fri Jun 18 21:45:31 CST 2021
VERSION_CODE=226
VERSION_CODE=227
NEED_CREATE_RELEASE=false

Loading…
Cancel
Save