Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

增加短信登录方式 #50

Merged
merged 3 commits into from
Nov 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -112,4 +112,5 @@ dependencies {
implementation 'io.github.lucksiege:camerax:v3.10.9'
//
implementation 'jp.wasabeef:recyclerview-animators:4.0.2'
implementation "org.apache.directory.studio:org.apache.commons.codec:1.8"
}
1 change: 1 addition & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
<activity android:name=".mapsetting.MapActivity" />
<activity android:name=".photo.PhotoSignActivity" />
<activity android:name=".record.SignRecordActivity" />
<activity android:name=".login.sms.SMSActivity"/>

<service android:name="com.amap.api.location.APSService" />
</application>
Expand Down
8 changes: 8 additions & 0 deletions app/src/main/java/com/cofbro/qian/data/URL.kt
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,16 @@ object URL {
fun getWorkEncPath(courseId: String, classId: String, cpi: String): String =
"https://mooc1-2.chaoxing.com/mooc-ans/visit/stucoursemiddle?courseid=$courseId&clazzid=$classId&vc=1&cpi=$cpi&ismooc2=1&v=2"

// 作业列表
fun getHomeworkListPath(courseId: String, classId: String, cpi: String, workEnc: String): String =
"https://mooc1.chaoxing.com/mooc2/work/list?courseId=$courseId&classId=$classId&cpi=$cpi&ut=s&enc=$workEnc"

// 用户信息
fun getUserInfo(): String = "http://i.chaoxing.com/base"

// 验证码
fun getSendCaptchaUrl(): String = "https://passport2-api.chaoxing.com/api/sendcaptcha"

fun getLoginWithSmsUrl(): String = "https://passport2-api.chaoxing.com/v11/loginregister?cx_xxt_passport=json"

}
24 changes: 23 additions & 1 deletion app/src/main/java/com/cofbro/qian/login/LoginActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ package com.cofbro.qian.login

import android.content.Intent
import android.os.Bundle
import android.util.Log
import androidx.lifecycle.lifecycleScope
import com.cofbro.hymvvmutils.base.BaseActivity
import com.cofbro.hymvvmutils.base.getBySp
import com.cofbro.hymvvmutils.base.saveUsedSp
import com.cofbro.qian.data.URL
import com.cofbro.qian.databinding.ActivityLoginBinding
import com.cofbro.qian.login.sms.SMSActivity
import com.cofbro.qian.main.MainActivity
import com.cofbro.qian.utils.CacheUtils
import com.cofbro.qian.utils.safeParseToJson
Expand Down Expand Up @@ -89,6 +89,16 @@ class LoginActivity : BaseActivity<LoginViewModel, ActivityLoginBinding>() {
autoClearFocus()
// 登录
login()
// 手机号登录
phoneLogin()
}

private fun phoneLogin() {
binding?.tvPhoneLogin?.setOnClickListener {
lifecycleScope.launch(Dispatchers.IO) {
toVerifyCodeActivity()
}
}
}

private fun login() {
Expand All @@ -101,6 +111,18 @@ class LoginActivity : BaseActivity<LoginViewModel, ActivityLoginBinding>() {
}
}

private fun toVerifyCodeActivity() {
val phoneNumber = binding?.ipUsername?.getTextString() ?: ""
if (phoneNumber.isEmpty()) {
ToastUtils.show("请先输入手机号")
return
}
val intent = Intent(this, SMSActivity::class.java)
intent.putExtra("phoneNumber", phoneNumber)
CacheUtils.activities["LoginActivity"] = this
startActivity(intent)
}

private fun autoClearFocus() {
binding?.root!!.setOnClickListener {
it.clearFocus()
Expand Down
2 changes: 0 additions & 2 deletions app/src/main/java/com/cofbro/qian/login/LoginViewModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package com.cofbro.qian.login
import androidx.lifecycle.viewModelScope
import com.cofbro.hymvvmutils.base.BaseViewModel
import com.cofbro.hymvvmutils.base.ResponseMutableLiveData
import com.cofbro.qian.utils.DefaultRepository
import com.cofbro.qian.utils.NetworkUtils
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
Expand All @@ -23,7 +22,6 @@ open class LoginViewModel : BaseViewModel<LoginRepository>() {
val request = NetworkUtils.buildServerRequest(url)
NetworkUtils.request(request)
}

}
}
}
193 changes: 193 additions & 0 deletions app/src/main/java/com/cofbro/qian/login/sms/SMSActivity.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
package com.cofbro.qian.login.sms

import android.annotation.SuppressLint
import android.content.Intent
import android.os.Bundle
import android.view.ViewGroup.MarginLayoutParams
import androidx.lifecycle.lifecycleScope
import com.alibaba.fastjson.JSONObject
import com.cofbro.hymvvmutils.base.BaseActivity
import com.cofbro.qian.data.URL
import com.cofbro.qian.databinding.ActivitySmsBinding
import com.cofbro.qian.main.MainActivity
import com.cofbro.qian.utils.CacheUtils
import com.cofbro.qian.utils.PhoneLoginUtil
import com.cofbro.qian.utils.dp2px
import com.cofbro.qian.utils.getStatusBarHeight
import com.cofbro.qian.utils.getStringExt
import com.cofbro.qian.utils.safeParseToJson
import com.hjq.toast.ToastUtils
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import java.util.Timer
import java.util.TimerTask

class SMSActivity : BaseActivity<SMSViewModel, ActivitySmsBinding>() {
private var phoneNumber = ""
private var timer: Timer? = null
override fun onActivityCreated(savedInstanceState: Bundle?) {
initArgs()
initObserver()
initView()
initEvent()
doNetwork()
}

private fun initEvent() {
binding?.tvCodeResend?.setOnClickListener {
sendSMS()
}
}

override fun onDestroy() {
cancelSMSTimer()
super.onDestroy()
}

private fun initObserver() {
// 发送短信
viewModel.smsSendLiveData.observe(this) {
lifecycleScope.launch(Dispatchers.IO) {
val data = it.data?.body?.string()?.safeParseToJson() ?: JSONObject()
val status = data.getStringExt("status")
if (status == "true") {
responseSuccessfully()
}
}
}

// 登录
viewModel.loginLiveData.observe(this) { response ->
val data = response.data ?: return@observe
lifecycleScope.launch(Dispatchers.IO) {
val body = data.body?.string()?.safeParseToJson() ?: JSONObject()
if (body.getStringExt("status") == "true") {
val list: List<String> = data.headers.values("Set-Cookie")
val cookies = StringBuilder()
var uid: String? = null
var fid: String? = null
if (list.isNotEmpty()) {
for (i in list.indices) {
val temp = list[i].split(";".toRegex()).dropLastWhile { it.isEmpty() }
.toTypedArray()[0]
cookies.append(temp).append(";")
if (temp.startsWith("UID")) uid = temp.substring(4)
//if (temp.startsWith("JSESSIONID")) continue
if (temp.startsWith("fid")) fid = temp.substring(4)
}
} else {
ToastUtils.show("Cookies获取失败!")
}
CacheUtils.cache["uid"] = uid ?: ""
CacheUtils.cache["cookies"] = cookies.toString()
CacheUtils.cache["fid"] = fid ?: ""
lifecycleScope.launch(Dispatchers.Main) {
toMainActivity()
}
}
}
}
}

private fun doNetwork() {
sendSMS()
}

private fun saveCookies(cookies: String) {
val uid = cookies.substringAfter("UID=").substringBefore(";")
val fid = cookies.substringAfter("fid=").substringBefore(";")
if (uid.isNotEmpty() && fid.isNotEmpty()) {
CacheUtils.cache["uid"] = uid
CacheUtils.cache["cookies"] = cookies
CacheUtils.cache["fid"] = fid
}
}

private fun toMainActivity() {
val intent = Intent(this, MainActivity::class.java)
startActivity(intent)
CacheUtils.activities["LoginActivity"]?.finish()
finish()
}

private fun responseSuccessfully() {
ToastUtils.show("验证码发送成功!")
startSmsTimer()
}

private fun startSmsTimer() {
var seconds = 60
timer = Timer()
timer?.apply {
schedule(object : TimerTask() {
override fun run() {
runOnUiThread {
seconds--
setSMSTips(seconds)
if (seconds <= 0) {
cancelSMSTimer()
}
}
}
}, 0, 1000)
}
}

private fun sendSMS() {
if (phoneNumber.isNotEmpty()) {
val smsBody = PhoneLoginUtil.getSendSMSBody(phoneNumber)
viewModel.sendSMS(URL.getSendCaptchaUrl(), smsBody)
}
}

private fun login(code: String) {
val loginInfo = PhoneLoginUtil.chaoXingHexCipher(username = phoneNumber, code = code)
val body = PhoneLoginUtil.getLoginBody(loginInfo ?: "", true)
viewModel.login(URL.getLoginWithSmsUrl(), body)
}

private fun cancelSMSTimer() {
timer?.let {
it.cancel()
timer = null
}
}

@SuppressLint("SetTextI18n")
private fun setSMSTips(seconds: Int) {
if (seconds <= 0) {
binding?.tvCodeResend?.text = "重新发送"
binding?.tvCodeResend?.isClickable = true
} else {
binding?.tvCodeResend?.text = "${seconds}秒后 重发验证码"
binding?.tvCodeResend?.isClickable = false
}
}

private fun initArgs() {
phoneNumber = intent.getStringExtra("phoneNumber") ?: ""
}

private fun initView() {
initToolBar()
initPhoneNumber()
initVerifyCodeView()
}

private fun initVerifyCodeView() {
binding?.verifyCodeView?.setCodeCallback {
login(it)
}
}

private fun initPhoneNumber() {
binding?.tvPhoneNumber?.text = phoneNumber
}

private fun initToolBar() {
val height = getStatusBarHeight(this) + dp2px(this, 5)
val params = binding?.ivBack?.layoutParams as MarginLayoutParams
params.topMargin = height
binding?.ivBack?.layoutParams = params
}
}
31 changes: 31 additions & 0 deletions app/src/main/java/com/cofbro/qian/login/sms/SMSViewModel.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.cofbro.qian.login.sms

import androidx.lifecycle.viewModelScope
import com.cofbro.hymvvmutils.base.BaseViewModel
import com.cofbro.hymvvmutils.base.ResponseMutableLiveData
import com.cofbro.qian.utils.DefaultRepository
import com.cofbro.qian.utils.NetworkUtils
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import okhttp3.Response

class SMSViewModel : BaseViewModel<DefaultRepository>() {
var smsSendLiveData = ResponseMutableLiveData<Response>()
var loginLiveData = ResponseMutableLiveData<Response>()

fun sendSMS(url: String, bodyString: String) {
viewModelScope.launch(Dispatchers.IO) {
repository.request(smsSendLiveData, false) {
NetworkUtils.postForLogin(bodyString, url)
}
}
}

fun login(url: String, bodyString: String) {
viewModelScope.launch(Dispatchers.IO) {
repository.request(loginLiveData, false) {
NetworkUtils.postForLogin(bodyString, url)
}
}
}
}
15 changes: 8 additions & 7 deletions app/src/main/java/com/cofbro/qian/record/SignRecordAdapter.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import androidx.recyclerview.widget.RecyclerView
import com.alibaba.fastjson.JSONObject
import com.cofbro.qian.R
import com.cofbro.qian.databinding.ItemRecordSignBinding
import com.cofbro.qian.utils.Constants
import com.cofbro.qian.utils.getIntExt
import com.cofbro.qian.utils.getJSONArrayExt
import com.cofbro.qian.utils.getStringExt
Expand Down Expand Up @@ -43,7 +44,7 @@ class SignRecordAdapter : RecyclerView.Adapter<SignRecordAdapter.SignRecordViewH
}

override fun getItemCount(): Int {
return recordData?.getIntExt("size") ?: 0
return recordData?.getIntExt(Constants.Recorder.SIZE) ?: 0
}

override fun onBindViewHolder(holder: SignRecordViewHolder, position: Int) {
Expand All @@ -54,24 +55,24 @@ class SignRecordAdapter : RecyclerView.Adapter<SignRecordAdapter.SignRecordViewH
RecyclerView.ViewHolder(binding.root) {
@SuppressLint("SetTextI18n")
fun bind(position: Int) {
val size = recordData?.getIntExt("size") ?: 0
val record = recordData?.getJSONArrayExt("records")
val size = recordData?.getIntExt(Constants.Recorder.SIZE) ?: 0
val record = recordData?.getJSONArrayExt(Constants.Recorder.RECORDS)
?.getOrNull(size - position - 1) as? JSONObject
?: JSONObject()

// uid
binding.tvRecordUsername.text = "uid: ${record.getStringExt("uid")}"
binding.tvRecordUsername.text = "uid: ${record.getStringExt(Constants.Recorder.UID)}"

// 签到状态
val status = record.getStringExt("status")
val status = record.getStringExt(Constants.Recorder.STATUS)
binding.tvRecordStatus.text = status
bindTextColor(status)

// 课程名称
binding.tvRecordCourseName.text = record.getStringExt("courseName")
binding.tvRecordCourseName.text = record.getStringExt(Constants.Recorder.COURSE_NAME)

// 绑定时间
val dateStr = record.getStringExt("time")
val dateStr = record.getStringExt(Constants.Recorder.TIME)
binding.tvRecordTime.text = dateStr
val dateArray = splitDateStr(dateStr)
binding.tvBookReocrdYear.text = dateArray[0]
Expand Down
Loading
Loading