1470 lines
57 KiB
Kotlin
1470 lines
57 KiB
Kotlin
@file:Suppress("SameParameterValue")
|
||
|
||
package com.img.rabbit.pages
|
||
|
||
import android.annotation.SuppressLint
|
||
import android.app.Activity
|
||
import android.content.Context
|
||
import android.util.Log
|
||
import android.view.LayoutInflater
|
||
import android.widget.CheckBox
|
||
import android.widget.TextView
|
||
import android.widget.Toast
|
||
import androidx.compose.foundation.Image
|
||
import androidx.compose.foundation.background
|
||
import androidx.compose.foundation.border
|
||
import androidx.compose.foundation.clickable
|
||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||
import androidx.compose.foundation.layout.Arrangement
|
||
import androidx.compose.foundation.layout.Box
|
||
import androidx.compose.foundation.layout.Column
|
||
import androidx.compose.foundation.layout.Row
|
||
import androidx.compose.foundation.layout.fillMaxHeight
|
||
import androidx.compose.foundation.layout.fillMaxSize
|
||
import androidx.compose.foundation.layout.fillMaxWidth
|
||
import androidx.compose.foundation.layout.height
|
||
import androidx.compose.foundation.layout.padding
|
||
import androidx.compose.foundation.layout.size
|
||
import androidx.compose.foundation.layout.width
|
||
import androidx.compose.foundation.layout.wrapContentHeight
|
||
import androidx.compose.foundation.layout.wrapContentWidth
|
||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||
import androidx.compose.foundation.text.BasicTextField
|
||
import androidx.compose.foundation.text.ClickableText
|
||
import androidx.compose.material3.Checkbox
|
||
import androidx.compose.material3.Scaffold
|
||
import androidx.compose.material3.Text
|
||
import androidx.compose.runtime.Composable
|
||
import androidx.compose.runtime.LaunchedEffect
|
||
import androidx.compose.runtime.collectAsState
|
||
import androidx.compose.runtime.getValue
|
||
import androidx.compose.runtime.livedata.observeAsState
|
||
import androidx.compose.runtime.mutableIntStateOf
|
||
import androidx.compose.runtime.mutableStateOf
|
||
import androidx.compose.runtime.remember
|
||
import androidx.compose.runtime.setValue
|
||
import androidx.compose.ui.Alignment
|
||
import androidx.compose.ui.Modifier
|
||
import androidx.compose.ui.draw.scale
|
||
import androidx.compose.ui.graphics.Brush
|
||
import androidx.compose.ui.graphics.Color
|
||
import androidx.compose.ui.layout.ContentScale
|
||
import androidx.compose.ui.platform.LocalContext
|
||
import androidx.compose.ui.res.painterResource
|
||
import androidx.compose.ui.res.stringResource
|
||
import androidx.compose.ui.text.SpanStyle
|
||
import androidx.compose.ui.text.buildAnnotatedString
|
||
import androidx.compose.ui.text.font.FontWeight
|
||
import androidx.compose.ui.text.withStyle
|
||
import androidx.compose.ui.tooling.preview.Preview
|
||
import androidx.compose.ui.unit.dp
|
||
import androidx.compose.ui.unit.sp
|
||
import androidx.compose.ui.viewinterop.AndroidView
|
||
import androidx.constraintlayout.widget.ConstraintLayout
|
||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||
import androidx.navigation.NavHostController
|
||
import androidx.navigation.compose.rememberNavController
|
||
import com.img.rabbit.R
|
||
import com.img.rabbit.utils.AgreementTextHelper
|
||
import com.img.rabbit.viewmodel.GeneralViewModel
|
||
import com.img.rabbit.viewmodel.LoginViewModel
|
||
import com.g.gysdk.EloginActivityParam
|
||
import com.g.gysdk.GYManager
|
||
import com.g.gysdk.GYResponse
|
||
import com.g.gysdk.GyCallBack
|
||
import com.img.rabbit.bean.local.toAlipayResult
|
||
import com.img.rabbit.config.Constants.agreementUrl
|
||
import com.img.rabbit.config.Constants.privacyUrl
|
||
import com.img.rabbit.pages.toolbar.TitleBar
|
||
import com.img.rabbit.provider.storage.GlobalStateManager
|
||
import com.img.rabbit.provider.storage.PreferenceUtil
|
||
import com.img.rabbit.utils.StringUtils
|
||
import com.img.rabbit.utils.UrlLinkUtils.openAgreement
|
||
import kotlinx.coroutines.delay
|
||
import org.json.JSONObject
|
||
|
||
|
||
@SuppressLint("UnrememberedMutableState")
|
||
@Composable
|
||
fun LoginScreen(navController: NavHostController? = null, generalViewModel: GeneralViewModel, loginViewModel: LoginViewModel, isVisibilityBreak: Boolean) {
|
||
val context = LocalContext.current
|
||
val networkStatus by generalViewModel.networkStatus.observeAsState(initial = true)
|
||
var showNetworkDisconnected by remember { mutableStateOf(false) }
|
||
|
||
// 网络状态监听
|
||
LaunchedEffect(networkStatus) {
|
||
if (!networkStatus) {
|
||
// 网络断开时的处理
|
||
Log.w("NetworkStatus","网络断开")
|
||
}else{
|
||
Log.w("NetworkStatus","网络已连接")
|
||
}
|
||
}
|
||
|
||
// 登录成功后,保存 token
|
||
LaunchedEffect(loginViewModel.loginState.value) {
|
||
if (loginViewModel.loginState.value !=null && loginViewModel.loginState.value?.data?.token != null) {
|
||
//登录成功
|
||
PreferenceUtil.saveAccessToken(loginViewModel.loginState.value?.data?.token)
|
||
|
||
loginViewModel.setLogin(true)
|
||
//更新登录状态
|
||
GlobalStateManager(context).storeGlobalLoginNotify(true)
|
||
//清理loginState
|
||
loginViewModel.loginState.value = null
|
||
//提示登录成功
|
||
Toast.makeText(context, "登录成功", Toast.LENGTH_SHORT).show()
|
||
// 当允许返回上一页时,登录成功后,返回上一页
|
||
if(isVisibilityBreak){
|
||
navController?.popBackStack()
|
||
}
|
||
}else if(loginViewModel.loginState.value !=null && loginViewModel.loginState.value?.data?.token == null){
|
||
//登录失败
|
||
loginViewModel.setLogin(false)
|
||
Log.w("LoginScreen","登录失败,无有效的Token")
|
||
Toast.makeText(context, "登录失败,请重新登录", Toast.LENGTH_SHORT).show()
|
||
}
|
||
}
|
||
|
||
var globalWxAuthorization by mutableStateOf(GlobalStateManager(context).globalWxAuthorizationFlow().collectAsState(initial = ""))
|
||
LaunchedEffect(globalWxAuthorization.value) {
|
||
if(globalWxAuthorization.value?.isNotEmpty() == true){
|
||
loginViewModel.requestWxLogin(globalWxAuthorization.value!!)
|
||
//清理globalWxAuthorization
|
||
GlobalStateManager(context).storeGlobalWxAuthorization("")
|
||
}
|
||
}
|
||
|
||
LaunchedEffect(loginViewModel.authInfoForAlipay.value) {
|
||
if(loginViewModel.authInfoForAlipay.value.isEmpty()) return@LaunchedEffect
|
||
loginViewModel.loginWithAliPay(context){rawResult ->
|
||
Log.i("loginWithAliPay", "支付宝登录结果:$rawResult")
|
||
val alipayResult = rawResult.toAlipayResult()
|
||
// 处理支付宝登录结果
|
||
when (alipayResult.resultStatus) {
|
||
"9000" -> {
|
||
// 登录成功,result 字段中包含 auth_code
|
||
val authCode = StringUtils.parseAlipayResult(alipayResult.result ?: "")["auth_code"] ?: ""
|
||
loginViewModel.requestAlipayLogin(authCode)
|
||
}
|
||
|
||
"6001" -> {
|
||
"用户取消登录"
|
||
}
|
||
|
||
else -> {
|
||
alipayResult.memo ?: "登录失败"
|
||
}
|
||
}
|
||
//清理authInfoForAlipay
|
||
loginViewModel.authInfoForAlipay.value = ""
|
||
}
|
||
}
|
||
|
||
Scaffold{
|
||
Box(
|
||
modifier = Modifier.fillMaxSize()
|
||
) {
|
||
Image(
|
||
painter = painterResource(id = R.mipmap.ic_main_previous_mask),
|
||
contentDescription = null,
|
||
contentScale = ContentScale.FillWidth,
|
||
modifier = Modifier
|
||
.fillMaxWidth()
|
||
.wrapContentHeight()
|
||
)
|
||
|
||
Column(
|
||
modifier = Modifier
|
||
.fillMaxSize()
|
||
) {
|
||
Box(modifier = Modifier.fillMaxSize()){
|
||
when(loginViewModel.loginScreenType.value){
|
||
LoginScreenType.LOGIN_ONE_KEY -> {
|
||
//一键登录
|
||
OneKeyLoginScreen(context, loginViewModel, generalViewModel)
|
||
}
|
||
LoginScreenType.LOGIN_WX -> {
|
||
//微信登录
|
||
Box(modifier = Modifier.align(Alignment.Center).padding(bottom = 100.dp)){
|
||
WxLoginScreen(context, loginViewModel, generalViewModel)
|
||
}
|
||
|
||
}
|
||
LoginScreenType.LOGIN_ALIPAY -> {
|
||
//支付宝登录
|
||
Box(modifier = Modifier.align(Alignment.Center).padding(bottom = 100.dp)){
|
||
AliPayLoginScreen(context, loginViewModel)
|
||
}
|
||
|
||
}
|
||
else -> {
|
||
//默认验证码登录
|
||
CaptchaLoginScreen(context, loginViewModel, generalViewModel)
|
||
}
|
||
}
|
||
|
||
// 其他登录方式Bar
|
||
Column (
|
||
modifier = Modifier
|
||
.fillMaxSize()
|
||
.padding(top = 27.dp),
|
||
verticalArrangement = Arrangement.Bottom
|
||
){
|
||
OtherLoginBar(viewModel = loginViewModel)
|
||
}
|
||
}
|
||
}
|
||
|
||
LaunchedEffect(networkStatus) {
|
||
delay(1000L)
|
||
showNetworkDisconnected = true
|
||
}
|
||
if(showNetworkDisconnected){
|
||
if(!networkStatus){
|
||
NetworkDisconnectedPage(onNetworkStatus = {isNetworkAvailable->
|
||
if(isNetworkAvailable){
|
||
Toast.makeText(context, "网络已连接", Toast.LENGTH_SHORT).show()
|
||
}else{
|
||
Toast.makeText(context, "网络已断开", Toast.LENGTH_SHORT).show()
|
||
}
|
||
generalViewModel.setNetworkStatus(isNetworkAvailable)
|
||
})
|
||
}
|
||
}
|
||
|
||
// 顶部栏
|
||
TitleBar(navController = navController, paddingValues = it, title = "", showSave = false, showBreak = isVisibilityBreak)
|
||
}
|
||
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 验证码登录
|
||
*/
|
||
@Composable
|
||
private fun CaptchaLoginScreen(context: Context, viewModel: LoginViewModel, generalViewModel: GeneralViewModel) {
|
||
val gradientBrush = Brush.verticalGradient(
|
||
colors = listOf(
|
||
Color(0xFF91FEFA), // 浅蓝色
|
||
Color(0x0091FEFA) // 半透明
|
||
),
|
||
startY = 0f,
|
||
endY = Float.POSITIVE_INFINITY
|
||
)
|
||
// 验证码倒计时
|
||
var isCaptchaCountdown by remember { mutableStateOf(false) }
|
||
// 倒计时秒数
|
||
var captchaCountdown by remember { mutableIntStateOf(60) }
|
||
|
||
if (isCaptchaCountdown) {
|
||
LaunchedEffect(key1 = isCaptchaCountdown) {
|
||
while (captchaCountdown > 0) {
|
||
delay(1000) // 等待1秒
|
||
captchaCountdown--
|
||
}
|
||
isCaptchaCountdown = false
|
||
captchaCountdown = 60 // 重置倒计时
|
||
}
|
||
}
|
||
|
||
Column {
|
||
//登录标签
|
||
Row(
|
||
modifier = Modifier
|
||
.fillMaxWidth()
|
||
.wrapContentHeight()
|
||
.padding(start = 38.dp, end = 38.dp, top = 150.dp)
|
||
) {
|
||
Box(
|
||
modifier = Modifier
|
||
.width(4.dp)
|
||
.height(55.dp)
|
||
.background(gradientBrush)
|
||
)
|
||
Column() {
|
||
Text(
|
||
text = "欢迎登录",
|
||
modifier = Modifier.padding(start = 12.dp),
|
||
fontSize =18.sp,
|
||
fontWeight = FontWeight.Bold,
|
||
color = Color(0xFF000000)
|
||
)
|
||
Text(
|
||
text = stringResource(R.string.app_name),
|
||
modifier = Modifier.padding(start = 12.dp),
|
||
fontSize =32.sp,
|
||
fontWeight = FontWeight.Bold,
|
||
color = Color(0xFF000000)
|
||
)
|
||
}
|
||
}
|
||
//登录框
|
||
Column(
|
||
modifier = Modifier
|
||
.fillMaxWidth()
|
||
.wrapContentHeight()
|
||
.padding(start = 38.dp, end = 38.dp, top = 80.dp)
|
||
) {
|
||
// 用户名框(手机号)
|
||
Box(
|
||
modifier = Modifier
|
||
.fillMaxWidth()
|
||
.height(50.dp)
|
||
.background(
|
||
Color(0x4DE3E0ED),
|
||
shape = RoundedCornerShape(12.dp),
|
||
)
|
||
){
|
||
Row(
|
||
modifier = Modifier
|
||
.fillMaxHeight()
|
||
.fillMaxWidth()
|
||
) {
|
||
Text(
|
||
text = "+86",
|
||
modifier = Modifier
|
||
.padding(start = 14.dp, end = 12.dp)
|
||
.align(Alignment.CenterVertically),
|
||
fontSize =14.sp,
|
||
fontWeight = FontWeight.Normal,
|
||
color = Color(0xFF3D3D3D)
|
||
)
|
||
|
||
Image(
|
||
painter = painterResource(id = R.mipmap.ic_vertical_divider_dotted_line),
|
||
contentDescription = null,
|
||
modifier = Modifier
|
||
.height(29.dp)
|
||
.width(1.dp)
|
||
.align(Alignment.CenterVertically)
|
||
)
|
||
|
||
BasicTextField(
|
||
value = viewModel.userName.value,
|
||
onValueChange = { viewModel.setUserName(it) },
|
||
modifier = Modifier
|
||
.fillMaxWidth()
|
||
.background(Color.Transparent)
|
||
.padding(horizontal = 12.dp)
|
||
.align(Alignment.CenterVertically),
|
||
textStyle = androidx.compose.ui.text.TextStyle(
|
||
color = Color.Black,
|
||
fontSize = 16.sp
|
||
),
|
||
singleLine = true,
|
||
maxLines = 1,
|
||
keyboardOptions = androidx.compose.foundation.text.KeyboardOptions(
|
||
keyboardType = androidx.compose.ui.text.input.KeyboardType.Phone,
|
||
imeAction = androidx.compose.ui.text.input.ImeAction.Done
|
||
),
|
||
decorationBox = { innerTextField ->
|
||
Box(
|
||
modifier = Modifier
|
||
.fillMaxWidth()
|
||
.background(Color.Transparent)
|
||
) {
|
||
if (viewModel.userName.value.isEmpty()) {
|
||
Text(
|
||
"请输入手机号",
|
||
color = Color.Gray,
|
||
fontSize = 16.sp
|
||
)
|
||
}
|
||
innerTextField()
|
||
}
|
||
},
|
||
)
|
||
}
|
||
}
|
||
// 分割线
|
||
Box(
|
||
modifier = Modifier
|
||
.fillMaxWidth()
|
||
.height(20.dp)
|
||
.background(Color.Transparent)
|
||
)
|
||
// 验证码框
|
||
Box(
|
||
modifier = Modifier
|
||
.fillMaxWidth()
|
||
.height(50.dp)
|
||
.background(
|
||
Color(0x4DE3E0ED),
|
||
shape = RoundedCornerShape(12.dp),
|
||
)
|
||
) {
|
||
Row(
|
||
modifier = Modifier
|
||
.fillMaxHeight()
|
||
.fillMaxWidth()
|
||
.padding(end = 5.dp),
|
||
horizontalArrangement = Arrangement.End
|
||
|
||
) {
|
||
|
||
BasicTextField(
|
||
value = viewModel.captcha.value,
|
||
onValueChange = { viewModel.setCaptcha(it) },
|
||
modifier = Modifier
|
||
.weight(1f)
|
||
.align(Alignment.CenterVertically)
|
||
.background(Color.Transparent),
|
||
textStyle = androidx.compose.ui.text.TextStyle(
|
||
color = Color.Black,
|
||
fontSize = 16.sp
|
||
),
|
||
singleLine = true,
|
||
maxLines = 1,
|
||
keyboardOptions = androidx.compose.foundation.text.KeyboardOptions(
|
||
keyboardType = androidx.compose.ui.text.input.KeyboardType.Text,
|
||
imeAction = androidx.compose.ui.text.input.ImeAction.Done
|
||
),
|
||
decorationBox = { innerTextField ->
|
||
Box(
|
||
modifier = Modifier
|
||
.fillMaxWidth()
|
||
.align(Alignment.CenterVertically)
|
||
.padding(horizontal = 14.dp)
|
||
.background(Color.Transparent)
|
||
) {
|
||
if (viewModel.captcha.value.isEmpty()) {
|
||
Text(
|
||
"请输入验证码",
|
||
color = Color.Gray,
|
||
fontSize = 16.sp
|
||
)
|
||
}
|
||
innerTextField()
|
||
}
|
||
}
|
||
)
|
||
|
||
Box(
|
||
modifier = Modifier
|
||
.height(40.dp)
|
||
.width(98.dp)
|
||
.align(Alignment.CenterVertically)
|
||
.background(
|
||
if (isCaptchaCountdown) Color(0xFFE0E0E0) else Color(0xFFFFFFFF),
|
||
shape = RoundedCornerShape(8.dp)
|
||
)
|
||
.clickable(enabled = !isCaptchaCountdown) {
|
||
// 点击获取验证码
|
||
if (validatePhoneEmpty(
|
||
context = context,
|
||
viewModel = viewModel,
|
||
showToast = true
|
||
)
|
||
) {
|
||
// 请求验证码(请完善requestCaptcha函数)
|
||
viewModel.requestCaptcha(viewModel.userName.value)
|
||
|
||
// 开始倒计时(倒计时应该在requestCaptcha完成后开始)
|
||
isCaptchaCountdown = true
|
||
return@clickable
|
||
}
|
||
}
|
||
){
|
||
if (isCaptchaCountdown) {
|
||
// 倒计时文本(倒计时从60秒开始)
|
||
Text(
|
||
"${captchaCountdown}秒",
|
||
color = Color(0xFF3D3D3D),
|
||
fontSize = 12.sp,
|
||
modifier = Modifier
|
||
.align(Alignment.Center)
|
||
)
|
||
} else {
|
||
Text(
|
||
"获取验证码",
|
||
color = Color(0xFF3D3D3D),
|
||
fontSize = 12.sp,
|
||
modifier = Modifier
|
||
.align(Alignment.Center)
|
||
)
|
||
}
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
}
|
||
|
||
// 登录按钮
|
||
Box(
|
||
modifier = Modifier
|
||
.fillMaxWidth()
|
||
.wrapContentHeight()
|
||
.padding(start = 30.dp, end = 30.dp, top = 46.dp)
|
||
.background(
|
||
Color(0xFF252525),
|
||
shape = RoundedCornerShape(359.dp),
|
||
)
|
||
.clickable(
|
||
indication = null,
|
||
interactionSource = remember { MutableInteractionSource() }
|
||
) {
|
||
// 点击登录
|
||
if (validateCaptchaLoginEmpty(
|
||
context = context,
|
||
viewModel = viewModel,
|
||
showToast = true
|
||
)
|
||
) {
|
||
// 验证通过(通过验证码验证),请求登录
|
||
viewModel.requestLoginForCaptcha(
|
||
viewModel.userName.value,
|
||
viewModel.captcha.value
|
||
)
|
||
}
|
||
}
|
||
) {
|
||
Text(
|
||
"登录",
|
||
color = Color(0xFFC2FF43),
|
||
fontSize = 16.sp,
|
||
fontWeight = FontWeight.Bold,
|
||
modifier = Modifier
|
||
.padding(vertical = 12.dp)
|
||
.align(Alignment.Center)
|
||
)
|
||
}
|
||
Row(
|
||
modifier = Modifier
|
||
.fillMaxWidth()
|
||
.wrapContentHeight()
|
||
.padding(start = 30.dp, end = 30.dp, top = 14.dp)
|
||
) {
|
||
Checkbox(
|
||
checked = viewModel.isPolicyAgreement.value,
|
||
onCheckedChange = { isChecked ->
|
||
viewModel.setIsPolicyAgreement(isChecked)
|
||
},
|
||
modifier = Modifier
|
||
.size(16.dp)
|
||
.scale(0.35f)
|
||
.padding(start = 6.dp)
|
||
.background(
|
||
if (viewModel.isPolicyAgreement.value) Color(0xFF252525)
|
||
else Color.Transparent,
|
||
shape = RoundedCornerShape(36.dp)
|
||
)
|
||
.border(
|
||
width = 1.dp,
|
||
color = if (viewModel.isPolicyAgreement.value) Color(0xFF252525)
|
||
else Color(0xFFCCCCCC),
|
||
shape = RoundedCornerShape(36.dp)
|
||
)
|
||
.align(Alignment.CenterVertically),
|
||
colors = androidx.compose.material3.CheckboxDefaults.colors(
|
||
checkedColor = Color.Transparent, // 隐藏默认背景
|
||
uncheckedColor = Color.Transparent, // 隐藏默认背景
|
||
checkmarkColor = Color.White
|
||
)
|
||
|
||
)
|
||
val annotatedText = buildAnnotatedString {
|
||
append("我已阅读并同意")
|
||
|
||
// 用户协议部分
|
||
pushStringAnnotation(tag = "USER_AGREEMENT", annotation = "user_agreement")
|
||
withStyle(style = SpanStyle(
|
||
color = Color(0xFF767676),
|
||
fontWeight = FontWeight.Bold,
|
||
//textDecoration = TextDecoration.Underline
|
||
)) {
|
||
append("《用户协议》")
|
||
}
|
||
pop()
|
||
|
||
append("和")
|
||
|
||
// 隐私政策部分
|
||
pushStringAnnotation(tag = "PRIVACY_POLICY", annotation = "privacy_policy")
|
||
withStyle(style = SpanStyle(
|
||
color = Color(0xFF767676),
|
||
fontWeight = FontWeight.Bold,
|
||
//textDecoration = TextDecoration.Underline
|
||
)) {
|
||
append("《隐私政策》")
|
||
}
|
||
pop()
|
||
}
|
||
ClickableText(
|
||
text = annotatedText,
|
||
onClick = { offset ->
|
||
annotatedText.getStringAnnotations(offset, offset)
|
||
.firstOrNull()?.let { annotation ->
|
||
when (annotation.tag) {
|
||
"USER_AGREEMENT" -> {
|
||
// 打开用户协议
|
||
openAgreement(context = context, title = "用户协议", url = agreementUrl)
|
||
}
|
||
"PRIVACY_POLICY" -> {
|
||
// 打开隐私政策
|
||
openAgreement(context = context, title = "隐私政策", url = privacyUrl)
|
||
}
|
||
}
|
||
}
|
||
},
|
||
style = androidx.compose.ui.text.TextStyle(
|
||
fontSize = 12.sp,
|
||
color = Color.Gray
|
||
),
|
||
modifier = Modifier
|
||
.padding(start = 4.dp)
|
||
.align(Alignment.CenterVertically)
|
||
)
|
||
}
|
||
}
|
||
}
|
||
/**
|
||
* 一键登录页
|
||
* 至少包含号码栏(NumberTextview)、品牌露出(SloganTextview)、登录按钮(LoginButton)、隐私确认(PrivacyCheckbox)、隐私标题(PrivacyTextview)
|
||
*/
|
||
@SuppressLint("UseKtx", "InflateParams", "SetTextI18n")
|
||
@Composable
|
||
private fun OneKeyLoginScreen(context: Context, viewModel: LoginViewModel, generalViewModel: GeneralViewModel) {
|
||
val ONEKEY_TAG = "OneKeyLoginScreen"
|
||
|
||
val preLoginResult = GYManager.getInstance().preLoginResult
|
||
val phoneNumber = viewModel.oneKeyPreLogin?.number ?: ""
|
||
val operator = preLoginResult.operator//运营商,CM 移动,CT 电信,CU 联通
|
||
val privacyName = "《${preLoginResult.privacyName}》"
|
||
val privacyUrl = preLoginResult.privacyUrl
|
||
|
||
// 详细打印preLoginResult信息
|
||
Log.w(ONEKEY_TAG, "=== preLoginResult 详细信息 ===")
|
||
Log.w(ONEKEY_TAG, "preLoginResult对象: $preLoginResult")
|
||
Log.w(ONEKEY_TAG, "operator: ${preLoginResult.operator}")
|
||
Log.w(ONEKEY_TAG, "isValid: ${preLoginResult.isValid}")
|
||
Log.w(ONEKEY_TAG, "privacyName: ${preLoginResult.privacyName}")
|
||
Log.w(ONEKEY_TAG, "privacyUrl: ${preLoginResult.privacyUrl}")
|
||
Log.w(ONEKEY_TAG, "================================")
|
||
|
||
|
||
val agreementText = "登录即认可${privacyName}、《用户协议》和《隐私政策》并使用本机号码登录"
|
||
Column(
|
||
modifier = Modifier
|
||
.fillMaxWidth()
|
||
.wrapContentHeight()
|
||
) {
|
||
// 使用AndroidView嵌入XML布局
|
||
@Suppress("COMPOSE_APPLIER_CALL_MISMATCH")
|
||
AndroidView(
|
||
factory = { context ->
|
||
LayoutInflater.from(context).inflate(
|
||
R.layout.layout_one_key_login,
|
||
null,
|
||
false
|
||
) as ConstraintLayout
|
||
},
|
||
modifier = Modifier.fillMaxSize(),
|
||
update = { view ->
|
||
// 动态更新XML布局中的内容
|
||
val phoneTextView = view.findViewById<TextView>(R.id.layout_one_key_login_tv_phone)
|
||
phoneTextView.text = phoneNumber // 需要回去手机号码
|
||
|
||
val serviceTextView = view.findViewById<TextView>(R.id.layout_one_key_login_tv_service)
|
||
val serviceText = when (operator) {
|
||
"CT" -> {//运营商,CM 移动,CT 电信,CU 联通
|
||
"天翼账号提供认证服务"
|
||
}
|
||
"CU" -> {//联通
|
||
"联通账号提供认证服务"
|
||
}
|
||
else -> {//移动
|
||
"移动账号提供认证服务"
|
||
}
|
||
}
|
||
serviceTextView.text = serviceText // 品牌露出,如:“天翼账号提供认证服务”
|
||
|
||
val checkbox = view.findViewById<CheckBox>(R.id.layout_one_key_login_agreement_checkbox)
|
||
checkbox.isChecked = viewModel.isPolicyAgreement.value
|
||
checkbox.setOnCheckedChangeListener { _, isChecked ->
|
||
viewModel.setIsPolicyAgreement(isChecked)
|
||
}
|
||
|
||
val agreementTextView = view.findViewById<TextView>(R.id.layout_one_key_login_agreement_tv)
|
||
//TODO 服务协议,如:“登录即认可《天翼账号服务与隐私协议》、《用户协议》和《隐私政策》并使用本机号码登录”
|
||
|
||
val targets = mapOf(
|
||
"serviceAgreement" to privacyName,
|
||
"userAgreement" to "《用户协议》",
|
||
"privacyAgreement" to "《隐私政策》"
|
||
)
|
||
// 设置可点击的协议文本
|
||
AgreementTextHelper.setupAgreementTextView(agreementText, targets, agreementTextView, isUnderlineText = false) { agreementType ->
|
||
when (agreementType) {
|
||
"serviceAgreement" -> openAgreement(context = context, title = privacyName, url = privacyUrl)
|
||
"userAgreement" -> openAgreement(context = context, title = "用户协议", url = agreementUrl)
|
||
"privacyAgreement" -> openAgreement(context = context, title = "隐私政策", url = privacyUrl)
|
||
}
|
||
}
|
||
|
||
val loginButton = view.findViewById<TextView>(R.id.layout_one_key_login_btn)
|
||
loginButton.setOnClickListener {
|
||
// 处理登录点击
|
||
oneKeyLogin(
|
||
context = context,
|
||
numberTv = phoneTextView,
|
||
sloganTv = serviceTextView,
|
||
loginBtn = loginButton,
|
||
checkBox = checkbox,
|
||
privacyTv = agreementTextView,
|
||
viewModel = viewModel
|
||
)
|
||
}
|
||
}
|
||
)
|
||
}
|
||
}
|
||
|
||
@Composable
|
||
private fun WxLoginScreen(
|
||
context: Context,
|
||
viewModel: LoginViewModel,
|
||
generalViewModel: GeneralViewModel
|
||
) {
|
||
Column {
|
||
Image(
|
||
painter = painterResource(id = R.mipmap.ic_launcher_logo),
|
||
contentDescription = null,
|
||
modifier = Modifier
|
||
.size(86.dp)
|
||
.align(Alignment.CenterHorizontally)
|
||
)
|
||
Text(
|
||
text = "截图兔",
|
||
fontWeight = FontWeight.Bold,
|
||
fontSize = 16.sp,
|
||
color = Color(0xFF1A1A1A),
|
||
modifier = Modifier
|
||
.wrapContentWidth()
|
||
.wrapContentHeight()
|
||
.align(Alignment.CenterHorizontally)
|
||
)
|
||
|
||
Text(
|
||
text = "为了更好地为您提供服务,请先完成微信授权",
|
||
fontWeight = FontWeight.Bold,
|
||
fontSize = 12.sp,
|
||
color = Color(0xFFAAAAAA),
|
||
modifier = Modifier
|
||
.wrapContentWidth()
|
||
.wrapContentHeight()
|
||
.padding(start = 30.dp, end = 30.dp, top = 46.dp)
|
||
.align(Alignment.CenterHorizontally)
|
||
)
|
||
|
||
// 登录按钮
|
||
Box(
|
||
modifier = Modifier
|
||
.fillMaxWidth()
|
||
.wrapContentHeight()
|
||
.padding(start = 30.dp, end = 30.dp, top = 8.dp)
|
||
.background(
|
||
Color(0xFF252525),
|
||
shape = RoundedCornerShape(359.dp),
|
||
)
|
||
.clickable(
|
||
indication = null,
|
||
interactionSource = remember { MutableInteractionSource() }
|
||
) {
|
||
// 启动微信验证,请求登录
|
||
if (viewModel.isPolicyAgreement.value) {
|
||
//打开微信登录
|
||
viewModel.loginWithWechat(context, generalViewModel.api)
|
||
} else {
|
||
Toast.makeText(
|
||
context,
|
||
"请先同意用户协议和隐私政策",
|
||
Toast.LENGTH_SHORT
|
||
).show()
|
||
}
|
||
}
|
||
) {
|
||
Row(
|
||
modifier = Modifier
|
||
.align(Alignment.Center)
|
||
) {
|
||
Image(
|
||
painter = painterResource(id = R.drawable.ic_wx_icon),
|
||
contentDescription = null,
|
||
modifier = Modifier
|
||
.size(32.dp)
|
||
.padding(start = 12.dp)
|
||
.align(Alignment.CenterVertically)
|
||
)
|
||
|
||
Text(
|
||
"微信授权登录",
|
||
color = Color(0xFFC2FF43),
|
||
fontSize = 16.sp,
|
||
fontWeight = FontWeight.Bold,
|
||
modifier = Modifier
|
||
.padding(vertical = 12.dp)
|
||
)
|
||
}
|
||
}
|
||
Row(
|
||
modifier = Modifier
|
||
.fillMaxWidth()
|
||
.wrapContentHeight()
|
||
.padding(start = 30.dp, end = 30.dp, top = 14.dp)
|
||
) {
|
||
Checkbox(
|
||
checked = viewModel.isPolicyAgreement.value,
|
||
onCheckedChange = { isChecked ->
|
||
viewModel.setIsPolicyAgreement(isChecked)
|
||
},
|
||
modifier = Modifier
|
||
.size(16.dp)
|
||
.scale(0.35f)
|
||
.padding(start = 6.dp)
|
||
.background(
|
||
if (viewModel.isPolicyAgreement.value) Color(0xFF252525)
|
||
else Color.Transparent,
|
||
shape = RoundedCornerShape(36.dp)
|
||
)
|
||
.border(
|
||
width = 1.dp,
|
||
color = if (viewModel.isPolicyAgreement.value) Color(0xFF252525)
|
||
else Color(0xFFCCCCCC),
|
||
shape = RoundedCornerShape(36.dp)
|
||
)
|
||
.align(Alignment.CenterVertically),
|
||
colors = androidx.compose.material3.CheckboxDefaults.colors(
|
||
checkedColor = Color.Transparent, // 隐藏默认背景
|
||
uncheckedColor = Color.Transparent, // 隐藏默认背景
|
||
checkmarkColor = Color.White
|
||
)
|
||
|
||
)
|
||
val annotatedText = buildAnnotatedString {
|
||
append("我已阅读并同意")
|
||
|
||
// 用户协议部分
|
||
pushStringAnnotation(tag = "USER_AGREEMENT", annotation = "user_agreement")
|
||
withStyle(style = SpanStyle(
|
||
color = Color(0xFF767676),
|
||
fontWeight = FontWeight.Bold,
|
||
//textDecoration = TextDecoration.Underline
|
||
)) {
|
||
append("《用户协议》")
|
||
}
|
||
pop()
|
||
|
||
append("和")
|
||
|
||
// 隐私政策部分
|
||
pushStringAnnotation(tag = "PRIVACY_POLICY", annotation = "privacy_policy")
|
||
withStyle(style = SpanStyle(
|
||
color = Color(0xFF767676),
|
||
fontWeight = FontWeight.Bold,
|
||
//textDecoration = TextDecoration.Underline
|
||
)) {
|
||
append("《隐私政策》")
|
||
}
|
||
pop()
|
||
}
|
||
ClickableText(
|
||
text = annotatedText,
|
||
onClick = { offset ->
|
||
annotatedText.getStringAnnotations(offset, offset)
|
||
.firstOrNull()?.let { annotation ->
|
||
when (annotation.tag) {
|
||
"USER_AGREEMENT" -> {
|
||
// 打开用户协议
|
||
openAgreement(context = context, title = "用户协议", url = agreementUrl)
|
||
}
|
||
"PRIVACY_POLICY" -> {
|
||
// 打开隐私政策
|
||
openAgreement(context = context, title = "隐私政策", url = privacyUrl)
|
||
}
|
||
}
|
||
}
|
||
},
|
||
style = androidx.compose.ui.text.TextStyle(
|
||
fontSize = 12.sp,
|
||
color = Color.Gray
|
||
),
|
||
modifier = Modifier
|
||
.padding(start = 4.dp)
|
||
.align(Alignment.CenterVertically)
|
||
)
|
||
}
|
||
}
|
||
}
|
||
|
||
@Composable
|
||
private fun AliPayLoginScreen(
|
||
context: Context,
|
||
viewModel: LoginViewModel,
|
||
) {
|
||
Column{
|
||
Image(
|
||
painter = painterResource(id = R.mipmap.ic_launcher_logo),
|
||
contentDescription = null,
|
||
modifier = Modifier
|
||
.size(86.dp)
|
||
.align(Alignment.CenterHorizontally)
|
||
)
|
||
Text(
|
||
text = "截图兔",
|
||
fontWeight = FontWeight.Bold,
|
||
fontSize = 16.sp,
|
||
color = Color(0xFF1A1A1A),
|
||
modifier = Modifier
|
||
.wrapContentWidth()
|
||
.wrapContentHeight()
|
||
.align(Alignment.CenterHorizontally)
|
||
)
|
||
|
||
Text(
|
||
text = "为了更好地为您提供服务,请先完成支付宝授权",
|
||
fontWeight = FontWeight.Bold,
|
||
fontSize = 12.sp,
|
||
color = Color(0xFFAAAAAA),
|
||
modifier = Modifier
|
||
.wrapContentWidth()
|
||
.wrapContentHeight()
|
||
.padding(start = 30.dp, end = 30.dp, top = 46.dp)
|
||
.align(Alignment.CenterHorizontally)
|
||
)
|
||
// 登录按钮
|
||
Box(
|
||
modifier = Modifier
|
||
.fillMaxWidth()
|
||
.wrapContentHeight()
|
||
.padding(start = 30.dp, end = 30.dp, top = 8.dp)
|
||
.background(
|
||
Color(0xFF252525),
|
||
shape = RoundedCornerShape(359.dp),
|
||
)
|
||
.clickable(
|
||
indication = null,
|
||
interactionSource = remember { MutableInteractionSource() }
|
||
) {
|
||
// 启动支付宝验证,请求登录
|
||
if (viewModel.isPolicyAgreement.value) {
|
||
// 打开支付宝登录
|
||
viewModel.requestAliPayAuthParam()
|
||
} else {
|
||
Toast.makeText(
|
||
context,
|
||
"请先同意用户协议和隐私政策",
|
||
Toast.LENGTH_SHORT
|
||
).show()
|
||
}
|
||
}
|
||
) {
|
||
Row(
|
||
modifier = Modifier
|
||
.align(Alignment.Center)
|
||
) {
|
||
Image(
|
||
painter = painterResource(id = R.drawable.ic_alipay_icon),
|
||
contentDescription = null,
|
||
modifier = Modifier
|
||
.size(32.dp)
|
||
.padding(start = 12.dp)
|
||
.align(Alignment.CenterVertically)
|
||
)
|
||
|
||
Text(
|
||
"支付宝授权登录",
|
||
color = Color(0xFFC2FF43),
|
||
fontSize = 16.sp,
|
||
fontWeight = FontWeight.Bold,
|
||
modifier = Modifier
|
||
.padding(vertical = 12.dp)
|
||
)
|
||
}
|
||
}
|
||
Row(
|
||
modifier = Modifier
|
||
.fillMaxWidth()
|
||
.wrapContentHeight()
|
||
.padding(start = 30.dp, end = 30.dp, top = 14.dp)
|
||
) {
|
||
Checkbox(
|
||
checked = viewModel.isPolicyAgreement.value,
|
||
onCheckedChange = { isChecked ->
|
||
viewModel.setIsPolicyAgreement(isChecked)
|
||
},
|
||
modifier = Modifier
|
||
.size(16.dp)
|
||
.scale(0.35f)
|
||
.padding(start = 6.dp)
|
||
.background(
|
||
if (viewModel.isPolicyAgreement.value) Color(0xFF252525)
|
||
else Color.Transparent,
|
||
shape = RoundedCornerShape(36.dp)
|
||
)
|
||
.border(
|
||
width = 1.dp,
|
||
color = if (viewModel.isPolicyAgreement.value) Color(0xFF252525)
|
||
else Color(0xFFCCCCCC),
|
||
shape = RoundedCornerShape(36.dp)
|
||
)
|
||
.align(Alignment.CenterVertically),
|
||
colors = androidx.compose.material3.CheckboxDefaults.colors(
|
||
checkedColor = Color.Transparent, // 隐藏默认背景
|
||
uncheckedColor = Color.Transparent, // 隐藏默认背景
|
||
checkmarkColor = Color.White
|
||
)
|
||
|
||
)
|
||
val annotatedText = buildAnnotatedString {
|
||
append("我已阅读并同意")
|
||
|
||
// 用户协议部分
|
||
pushStringAnnotation(tag = "USER_AGREEMENT", annotation = "user_agreement")
|
||
withStyle(style = SpanStyle(
|
||
color = Color(0xFF767676),
|
||
fontWeight = FontWeight.Bold,
|
||
//textDecoration = TextDecoration.Underline
|
||
)) {
|
||
append("《用户协议》")
|
||
}
|
||
pop()
|
||
|
||
append("和")
|
||
|
||
// 隐私政策部分
|
||
pushStringAnnotation(tag = "PRIVACY_POLICY", annotation = "privacy_policy")
|
||
withStyle(style = SpanStyle(
|
||
color = Color(0xFF767676),
|
||
fontWeight = FontWeight.Bold,
|
||
//textDecoration = TextDecoration.Underline
|
||
)) {
|
||
append("《隐私政策》")
|
||
}
|
||
pop()
|
||
}
|
||
ClickableText(
|
||
text = annotatedText,
|
||
onClick = { offset ->
|
||
annotatedText.getStringAnnotations(offset, offset)
|
||
.firstOrNull()?.let { annotation ->
|
||
when (annotation.tag) {
|
||
"USER_AGREEMENT" -> {
|
||
// 打开用户协议
|
||
openAgreement(context = context, title = "用户协议", url = agreementUrl)
|
||
}
|
||
"PRIVACY_POLICY" -> {
|
||
// 打开隐私政策
|
||
openAgreement(context = context, title = "隐私政策", url = privacyUrl)
|
||
}
|
||
}
|
||
}
|
||
},
|
||
style = androidx.compose.ui.text.TextStyle(
|
||
fontSize = 12.sp,
|
||
color = Color.Gray
|
||
),
|
||
modifier = Modifier
|
||
.padding(start = 4.dp)
|
||
.align(Alignment.CenterVertically)
|
||
)
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 一键登录页
|
||
* 至少包含号码栏(NumberTextview)、品牌露出(SloganTextview)、登录按钮(LoginButton)、隐私确认(PrivacyCheckbox)、隐私标题(PrivacyTextview)
|
||
*/
|
||
/*
|
||
@SuppressLint("UseKtx")
|
||
@Composable
|
||
private fun OneKeyLoginScreen(context: Context, viewModel: LoginViewModel) {
|
||
val preLoginResult = GYManager.getInstance().preLoginResult
|
||
preLoginResult.operator
|
||
preLoginResult.isValid
|
||
Column(
|
||
modifier = Modifier
|
||
.fillMaxWidth()
|
||
.wrapContentHeight()
|
||
.padding(top = 230.dp),
|
||
horizontalAlignment = Alignment.CenterHorizontally,
|
||
) {
|
||
Text(
|
||
text = "18698756851",
|
||
fontWeight = FontWeight.Bold,
|
||
fontSize = 36.sp,
|
||
color = Color(0xFF1A1A1A),
|
||
modifier = Modifier
|
||
.wrapContentWidth()
|
||
.wrapContentHeight(),
|
||
)
|
||
Text(
|
||
text = "天翼账号提供认证服务",
|
||
fontWeight = FontWeight.Normal,
|
||
fontSize = 14.sp,
|
||
color = Color(0xFF767676),
|
||
modifier = Modifier
|
||
.wrapContentWidth()
|
||
.wrapContentHeight(),
|
||
)
|
||
|
||
// 登录按钮
|
||
Box(
|
||
modifier = Modifier
|
||
.fillMaxWidth()
|
||
.wrapContentHeight()
|
||
.padding(start = 30.dp, end = 30.dp, top = 46.dp)
|
||
.background(
|
||
Color(0xFF252525),
|
||
shape = RoundedCornerShape(359.dp),
|
||
)
|
||
.clickable {
|
||
// 点击登录
|
||
if (validateCaptchaLoginEmpty(
|
||
context = context,
|
||
viewModel = viewModel,
|
||
showToast = true
|
||
)
|
||
) {
|
||
//TODO 验证码登录请求
|
||
Toast.makeText(context, "登录成功!", Toast.LENGTH_SHORT).show()
|
||
}
|
||
}
|
||
) {
|
||
Text(
|
||
"本机号码一键绑定",
|
||
color = Color(0xFFC2FF43),
|
||
fontSize = 16.sp,
|
||
fontWeight = FontWeight.Bold,
|
||
modifier = Modifier
|
||
.padding(vertical = 12.dp)
|
||
.align(Alignment.Center)
|
||
)
|
||
}
|
||
Row(
|
||
modifier = Modifier
|
||
.fillMaxWidth()
|
||
.wrapContentHeight()
|
||
.padding(start = 30.dp, end = 30.dp, top = 14.dp)
|
||
) {
|
||
Checkbox(
|
||
checked = viewModel.isPolicyAgreement.value,
|
||
onCheckedChange = { isChecked ->
|
||
viewModel.setIsPolicyAgreement(isChecked)
|
||
},
|
||
modifier = Modifier
|
||
.size(16.dp)
|
||
.scale(0.35f)
|
||
.padding(top = 16.dp, start = 6.dp)
|
||
.background(
|
||
if (viewModel.isPolicyAgreement.value) Color(0xFF252525)
|
||
else Color.Transparent,
|
||
shape = RoundedCornerShape(36.dp)
|
||
)
|
||
.border(
|
||
width = 1.dp,
|
||
color = if (viewModel.isPolicyAgreement.value) Color(0xFF252525)
|
||
else Color(0xFFCCCCCC),
|
||
shape = RoundedCornerShape(36.dp)
|
||
),
|
||
colors = androidx.compose.material3.CheckboxDefaults.colors(
|
||
checkedColor = Color.Transparent, // 隐藏默认背景
|
||
uncheckedColor = Color.Transparent, // 隐藏默认背景
|
||
checkmarkColor = Color.White
|
||
)
|
||
|
||
)
|
||
val annotatedText = buildAnnotatedString {
|
||
append("我已阅读并同意")
|
||
|
||
// 用户协议部分
|
||
pushStringAnnotation(tag = "SERVICE_AGREEMENT", annotation = "service_agreement")
|
||
withStyle(style = SpanStyle(
|
||
color = Color(0xFF767676),
|
||
fontWeight = FontWeight.Bold,
|
||
//textDecoration = TextDecoration.Underline
|
||
)) {
|
||
append("${preLoginResult.privacyName}")
|
||
}
|
||
pop()
|
||
|
||
append("、")
|
||
|
||
// 用户协议部分
|
||
pushStringAnnotation(tag = "USER_AGREEMENT", annotation = "user_agreement")
|
||
withStyle(style = SpanStyle(
|
||
color = Color(0xFF767676),
|
||
fontWeight = FontWeight.Bold,
|
||
//textDecoration = TextDecoration.Underline
|
||
)) {
|
||
append("《用户协议》")
|
||
}
|
||
pop()
|
||
|
||
append("和")
|
||
|
||
// 隐私政策部分
|
||
pushStringAnnotation(tag = "PRIVACY_POLICY", annotation = "privacy_policy")
|
||
withStyle(style = SpanStyle(
|
||
color = Color(0xFF767676),
|
||
fontWeight = FontWeight.Bold,
|
||
//textDecoration = TextDecoration.Underline
|
||
)) {
|
||
append("《隐私政策》")
|
||
}
|
||
pop()
|
||
}
|
||
ClickableText(
|
||
text = annotatedText,
|
||
onClick = { offset ->
|
||
annotatedText.getStringAnnotations(offset, offset)
|
||
.firstOrNull()?.let { annotation ->
|
||
when (annotation.tag) {
|
||
"SERVICE_AGREEMENT" -> {
|
||
// 打开服务协议
|
||
preLoginResult.privacyUrl?.let {
|
||
Intent(Intent.ACTION_VIEW, it.toUri()).apply {
|
||
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||
}.let { intent ->
|
||
context.startActivity(intent)
|
||
}
|
||
}
|
||
}
|
||
"USER_AGREEMENT" -> {
|
||
//TODO 打开用户协议
|
||
Toast.makeText(context, "打开用户协议", Toast.LENGTH_SHORT).show()
|
||
}
|
||
"PRIVACY_POLICY" -> {
|
||
//TODO 打开隐私政策
|
||
Toast.makeText(context, "打开隐私政策", Toast.LENGTH_SHORT).show()
|
||
}
|
||
}
|
||
}
|
||
},
|
||
style = androidx.compose.ui.text.TextStyle(
|
||
fontSize = 12.sp,
|
||
color = Color.Gray
|
||
),
|
||
modifier = Modifier
|
||
.padding(start = 4.dp)
|
||
.align(Alignment.CenterVertically)
|
||
)
|
||
}
|
||
}
|
||
}
|
||
*/
|
||
|
||
@Composable
|
||
private fun OtherLoginBar(viewModel: LoginViewModel) {
|
||
Column(
|
||
modifier = Modifier
|
||
.fillMaxWidth()
|
||
.wrapContentHeight()
|
||
.padding(start = 64.dp, end = 64.dp)
|
||
) {
|
||
Row(
|
||
modifier = Modifier
|
||
.fillMaxWidth()
|
||
.wrapContentHeight()
|
||
.padding(horizontal = 6.dp),
|
||
horizontalArrangement = Arrangement.SpaceBetween
|
||
) {
|
||
Box(
|
||
modifier = Modifier
|
||
.width(60.dp)
|
||
.height(2.dp)
|
||
.align(Alignment.CenterVertically)
|
||
.background(
|
||
brush = Brush.horizontalGradient(
|
||
colors = listOf(Color(0x00D8D8D8), Color(0xFFE5E5E5))
|
||
)
|
||
)
|
||
)
|
||
Text(
|
||
"其他登录方式",
|
||
color = Color(0xFF767676),
|
||
fontSize = 14.sp,
|
||
fontWeight = FontWeight.Normal,
|
||
modifier = Modifier
|
||
.padding(horizontal = 14.dp)
|
||
.align(Alignment.CenterVertically)
|
||
)
|
||
Box(
|
||
modifier = Modifier
|
||
.width(60.dp)
|
||
.height(2.dp)
|
||
.align(Alignment.CenterVertically)
|
||
.background(
|
||
brush = Brush.horizontalGradient(
|
||
colors = listOf(Color(0xFFE5E5E5), Color(0x00D8D8D8))
|
||
)
|
||
)
|
||
)
|
||
}
|
||
Row(
|
||
modifier = Modifier
|
||
.fillMaxWidth()
|
||
.wrapContentHeight()
|
||
.padding(horizontal = 6.dp, vertical = 27.dp),
|
||
horizontalArrangement = Arrangement.SpaceBetween
|
||
) {
|
||
Image(
|
||
painter = painterResource(id = R.mipmap.ic_wechat),
|
||
contentDescription = null,
|
||
modifier = Modifier
|
||
.size(32.dp)
|
||
.weight(1f)
|
||
.align(Alignment.CenterVertically)
|
||
.clickable(
|
||
indication = null,
|
||
interactionSource = remember { MutableInteractionSource() }
|
||
) {
|
||
// 微信登录
|
||
viewModel.loginScreenType.value = LoginScreenType.LOGIN_WX
|
||
}
|
||
)
|
||
Image(
|
||
painter = painterResource(id = R.mipmap.ic_alipay),
|
||
contentDescription = null,
|
||
modifier = Modifier
|
||
.size(32.dp)
|
||
.weight(1f)
|
||
.align(Alignment.CenterVertically)
|
||
.clickable(
|
||
indication = null,
|
||
interactionSource = remember { MutableInteractionSource() }
|
||
) {
|
||
// 支付宝登录
|
||
viewModel.loginScreenType.value = LoginScreenType.LOGIN_ALIPAY
|
||
}
|
||
)
|
||
Image(
|
||
painter = painterResource(id = R.mipmap.ic_phone),
|
||
contentDescription = null,
|
||
modifier = Modifier
|
||
.size(32.dp)
|
||
.weight(1f)
|
||
.align(Alignment.CenterVertically)
|
||
.clickable(
|
||
indication = null,
|
||
interactionSource = remember { MutableInteractionSource() }
|
||
) {
|
||
// 校验码登录
|
||
viewModel.loginScreenType.value = LoginScreenType.LOGIN_CAPTCHA
|
||
}
|
||
)
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 验证手机号是否为空
|
||
*/
|
||
private fun validatePhoneEmpty(context: Context, viewModel: LoginViewModel, showToast: Boolean = false): Boolean {
|
||
if (showToast && viewModel.userName.value.isEmpty()) {
|
||
Toast.makeText(context, "请输入手机号", Toast.LENGTH_SHORT).show()
|
||
}
|
||
return viewModel.userName.value.isNotEmpty()
|
||
}
|
||
|
||
/**
|
||
* 验证验证码登录是否为空
|
||
*/
|
||
private fun validateCaptchaLoginEmpty(context: Context, viewModel: LoginViewModel, showToast: Boolean = false): Boolean {
|
||
if (showToast) {
|
||
if(viewModel.userName.value.isEmpty()){
|
||
Toast.makeText(context, "请输入手机号", Toast.LENGTH_SHORT).show()
|
||
}else if(viewModel.captcha.value.isEmpty()){
|
||
Toast.makeText(context, "请输入验证码", Toast.LENGTH_SHORT).show()
|
||
}else if(!viewModel.isPolicyAgreement.value){
|
||
Toast.makeText(context, "请同意用户协议和隐私政策", Toast.LENGTH_SHORT).show()
|
||
}
|
||
}
|
||
return viewModel.userName.value.isNotEmpty() && viewModel.captcha.value.isNotEmpty() && viewModel.isPolicyAgreement.value
|
||
}
|
||
|
||
private fun oneKeyLogin(
|
||
context: Context,
|
||
numberTv: TextView,
|
||
sloganTv: TextView,
|
||
loginBtn: TextView,
|
||
checkBox: CheckBox,
|
||
privacyTv: TextView,
|
||
viewModel: LoginViewModel,
|
||
) {
|
||
val eloginActivityParam = EloginActivityParam()
|
||
.setActivity(context as Activity)
|
||
.setNumberTextview(numberTv)
|
||
.setSloganTextview(sloganTv)
|
||
.setLoginButton(loginBtn)
|
||
.setPrivacyCheckbox(checkBox)
|
||
.setPrivacyTextview(privacyTv)
|
||
.setUiErrorListener { msg -> //隐私协议未打勾、界面不合规、setLoginOnClickListener抛出异常等情况下的回调
|
||
Log.e("OneKeyLogin", "UIErrorListener.onError:$msg")
|
||
}
|
||
.setLoginOnClickListener {
|
||
if (!checkBox.isChecked) {
|
||
// 抛出异常,避免sdk进行后续登录动作(否则eAccountLogin会回调onFailed错误)
|
||
throw IllegalStateException("请先仔细阅读协议并勾选,然后再点击登录")
|
||
}
|
||
//启动登录时候的转圈圈
|
||
}
|
||
GYManager.getInstance().eAccountLogin(eloginActivityParam, 5000, object : GyCallBack {
|
||
override fun onSuccess(response: GYResponse?) {
|
||
// 登录成功,需要与后端交互
|
||
Log.i("OneKeyLogin", "onSuccess:$response")
|
||
try {
|
||
val jsonObject = JSONObject(response?.msg?:"{}")
|
||
val data = jsonObject.getJSONObject("data")
|
||
val token = data.getString("token")
|
||
viewModel.requestOneKeyLogin(response?.gyuid?:"", token)
|
||
} catch (e: Exception) {
|
||
e.printStackTrace()
|
||
}
|
||
}
|
||
|
||
override fun onFailed(p0: GYResponse?) {
|
||
// 登录失败
|
||
Log.e("OneKeyLogin", "onFailed:$p0")
|
||
}
|
||
})
|
||
}
|
||
|
||
|
||
enum class LoginScreenType {
|
||
LOGIN_NORMAL,
|
||
LOGIN_ONE_KEY,
|
||
LOGIN_CAPTCHA,
|
||
LOGIN_WX,
|
||
LOGIN_ALIPAY,
|
||
}
|
||
|
||
@Preview(showBackground = true)
|
||
@Composable
|
||
private fun PreviewOneKeyLoginScreen() {
|
||
OneKeyLoginScreen(LocalContext.current, viewModel(), viewModel())
|
||
}
|
||
|
||
|
||
@Preview(showBackground = true)
|
||
@Composable
|
||
private fun PreviewWxLoginScreen() {
|
||
WxLoginScreen(LocalContext.current, viewModel(), viewModel())
|
||
}
|
||
|
||
|
||
@Preview(showBackground = true)
|
||
@Composable
|
||
private fun PreviewAliPayLoginScreen() {
|
||
AliPayLoginScreen(LocalContext.current, viewModel())
|
||
}
|
||
|
||
@Preview(showBackground = true)
|
||
@Composable
|
||
private fun PreviewLoginScreen() {
|
||
LoginScreen(navController = rememberNavController(), generalViewModel = viewModel(), loginViewModel = viewModel(), isVisibilityBreak = false)
|
||
}
|