package com.xw.yunwei.ui.user.login import android.annotation.SuppressLint import android.graphics.Color import android.text.InputType import android.text.TextPaint import android.text.method.HideReturnsTransformationMethod import android.text.method.LinkMovementMethod import android.text.method.PasswordTransformationMethod import android.text.style.ClickableSpan import android.view.View import android.webkit.WebSettings import android.webkit.WebView import android.widget.Button import androidx.appcompat.widget.AppCompatEditText import androidx.core.os.bundleOf import androidx.databinding.DataBindingUtil import com.afollestad.materialdialogs.MaterialDialog import com.afollestad.materialdialogs.customview.customView import com.afollestad.materialdialogs.customview.getCustomView import com.blankj.utilcode.util.SpanUtils import com.google.android.material.tabs.TabLayout import com.xw.common.Constants import com.xw.common.R import com.xw.common.base.BaseActivity import com.xw.common.utils.BindUtils.getResColor import com.xw.common.utils.KeyPreferences import com.xw.common.utils.MMKVManager import com.xw.yunwei.BR import com.xw.yunwei.MyApp import com.xw.yunwei.databinding.ActivityLoginBinding import com.xw.yunwei.databinding.DialogProtocolBinding import com.xw.yunwei.ui.MainActivity import com.xw.yunwei.ui.work.car.detail.StandardDescriptionActivity class LoginActivity : BaseActivity() { override fun getBindingVariable() = BR.viewModel override fun init() { super.init() if (Constants.token.isNotEmpty()) { startActivity(MainActivity::class.java) finish() } else { MyApp.myApp.unbindPushAccount() val tab1 = binding.tabLayout.newTab().apply { text = "验证码登录" } val tab2 = binding.tabLayout.newTab().apply { text = "密码登录" } binding.tabLayout.addTab(tab1, true) binding.tabLayout.addTab(tab2, false) val protocol = SpanUtils().append("我已阅读并同意") .setForegroundColor(getResColor(R.color.gray_9)) .append("《小鹏Robotaxi自动驾驶出行运维隐私政策》").setBold() .setForegroundColor(getResColor(R.color.blue_5)) .setClickSpan(object : ClickableSpan() { override fun onClick(widget: View) { // showProtocolDialog(1) startActivity( StandardDescriptionActivity::class.java, bundleOf("type" to 8, "webType" to 1) ) } override fun updateDrawState(ds: TextPaint) {} }) .append("《第三方共享信息清单》").setBold() .setForegroundColor(getResColor(R.color.blue_5)) .setClickSpan(object : ClickableSpan() { override fun onClick(widget: View) { // showProtocolDialog(2) startActivity( StandardDescriptionActivity::class.java, bundleOf("type" to 9, "webType" to 1) ) } override fun updateDrawState(ds: TextPaint) {} }) .append("《个人信息收集清单》").setBold() .setForegroundColor(getResColor(R.color.blue_5)) .setClickSpan(object : ClickableSpan() { override fun onClick(widget: View) { startActivity( StandardDescriptionActivity::class.java, bundleOf("type" to 10, "webType" to 1) ) } override fun updateDrawState(ds: TextPaint) {} }) .append("《权限调用》").setBold() .setForegroundColor(getResColor(R.color.blue_5)) .setClickSpan(object : ClickableSpan() { override fun onClick(widget: View) { startActivity( StandardDescriptionActivity::class.java, bundleOf("type" to 11, "webType" to 1) ) } override fun updateDrawState(ds: TextPaint) {} }) .create() binding.protocol.text = protocol binding.protocol.highlightColor = Color.TRANSPARENT binding.protocol.movementMethod = LinkMovementMethod.getInstance() } } override fun setListener() { super.setListener() binding.tabLayout.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener { override fun onTabSelected(tab: TabLayout.Tab?) { tab?.let { viewModel.tabIndex.value = when (it.text) { "验证码登录" -> 0 "密码登录" -> 1 else -> 0 } } } override fun onTabUnselected(tab: TabLayout.Tab?) {} override fun onTabReselected(tab: TabLayout.Tab?) {} }) } override fun setObservable() { super.setObservable() viewModel.tabIndex.observe(this) { // binding.phone.setText("") binding.code.setText("") when (it) { 0 -> { // binding.phone.hint = "手机号" // binding.phone.inputType = InputType.TYPE_CLASS_PHONE // viewModel.passwordLoginCodeValidateInfo = null } 1 -> { // binding.phone.hint = "登录账户或者邮箱" // binding.phone.inputType = InputType.TYPE_CLASS_TEXT } } } viewModel.protocolStatus.observe(this) { MMKVManager.getInstance().saveBoolean(KeyPreferences.NEED_READ, !it) } viewModel.phone.observe(this) { when (viewModel.tabIndex.value) { 0 -> { viewModel.canGetCode.postValue(it.length == 11) } 1 -> { // viewModel.canGetCode.postValue(it.isNotEmpty()) viewModel.canGetCode.postValue(it.length == 11) } } } viewModel.eyeStatus2.observe(this) { setPasswordVisible(binding.psw, it) } } /** * 设置密码显示/隐藏 * @param visible true=明文, false=密文 */ private fun setPasswordVisible(et: AppCompatEditText, visible: Boolean) { if (visible) { et.transformationMethod = HideReturnsTransformationMethod.getInstance() } else { et.transformationMethod = PasswordTransformationMethod.getInstance() } // 关键:切换后需要将光标移到最后,防止光标跳到开头 et.setSelection(et.text?.length ?: 0) } // 标记两个协议是否都已读到底部 private var userProtocolRead = false private var privacyProtocolRead = false private var currentTab = 1 // 当前选中标签 fun showProtocolDialog(type: Int) { MaterialDialog(this).cornerRadius(15f).cancelable(true).show { customView( com.xw.yunwei.R.layout.dialog_protocol, noVerticalPadding = true, dialogWrapContent = true ) DataBindingUtil.bind(getCustomView())?.let { bind -> // 初始禁用确认按钮 bind.btnRight.isEnabled = false // bind.btnRight.alpha = 0.5f bind.btnRight.setTextColor(getResColor(R.color.gray_7)) val tab1 = bind.protocolLayout.tabLayout.newTab().apply { text = "用户协议" } val tab2 = bind.protocolLayout.tabLayout.newTab().apply { text = "隐私条款" } bind.protocolLayout.tabLayout.addTab(tab1, type == 1) bind.protocolLayout.tabLayout.addTab(tab2, type == 2) bind.btnLeft.setOnClickListener { dismiss() } bind.btnRight.setOnClickListener { viewModel.protocolStatus.value = true dismiss() } initWeb(bind.protocolLayout.web, bind.btnRight) val getProtocol: (Int) -> Unit = { type -> currentTab = type viewModel.getProtocol(type) { setContent(bind.protocolLayout.web, it, bind.btnRight) } } getProtocol(type) bind.protocolLayout.tabLayout.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener { override fun onTabSelected(tab: TabLayout.Tab?) { tab?.let { when (it.text) { "用户协议" -> getProtocol(1) "隐私条款" -> getProtocol(2) else -> {} } } } override fun onTabUnselected(tab: TabLayout.Tab?) {} override fun onTabReselected(tab: TabLayout.Tab?) {} }) } } } @SuppressLint("SetJavaScriptEnabled") private fun initWeb(webView: WebView, confirmBtn: Button) { //声明WebSettings子类 val webSettings = webView.settings webSettings.domStorageEnabled = true //设置适应Html5 //如果访问的页面中要与Javascript交互,则webview必须设置支持Javascript webSettings.javaScriptEnabled = true //允许js调用 webSettings.allowFileAccess = true //在File域下,能够执行任意的JavaScript代码,同源策略跨域访问能够对私有目录文件进行访问等 webSettings.allowContentAccess = true //是否允许在WebView中访问内容URL(Content Url),默认允许 //缩放操作 webSettings.setSupportZoom(true) //支持缩放,默认为true。是下面那个的前提。 webSettings.builtInZoomControls = true //设置内置的缩放控件。若为false,则该WebView不可缩放 webSettings.displayZoomControls = false //隐藏原生的缩放控件 //其他细节操作 webSettings.cacheMode = WebSettings.LOAD_CACHE_ELSE_NETWORK //关闭webview中缓存 webSettings.allowFileAccess = true //设置可以访问文件 webSettings.javaScriptCanOpenWindowsAutomatically = true //支持通过JS打开新窗口 webSettings.loadsImagesAutomatically = true //支持自动加载图片 webSettings.defaultTextEncodingName = "utf-8" //设置编码格式 // 关键:添加滚动监听 webView.setOnScrollChangeListener { _, _, scrollY, _, oldScrollY -> // 只有向下滑动时才检测 if (scrollY > oldScrollY) { checkScrollBottom(webView, confirmBtn) } } } @SuppressLint("SetJavaScriptEnabled") private fun setContent(webView: WebView, content: String?, confirmBtn: Button) { content?.let { webView.loadDataWithBaseURL(null, it, "text/html", "utf-8", null) // confirmBtn.text = if(currentTab == 1) "请阅读协议" else "请阅读条款" // 禁用按钮直到滚动到底 confirmBtn.isEnabled = false // confirmBtn.alpha = 0.5f confirmBtn.setTextColor(getResColor(R.color.gray_7)) // 页面加载完成后延迟检查(确保内容渲染完成) webView.postDelayed({ checkScrollBottom(webView, confirmBtn) }, 500) } } /** * 检测是否滚动到底部 */ private fun checkScrollBottom(webView: WebView, confirmBtn: Button) { webView.evaluateJavascript( """ (function() { var scrollHeight = Math.max( document.body.scrollHeight, document.documentElement.scrollHeight, document.body.offsetHeight, document.documentElement.offsetHeight, document.body.clientHeight, document.documentElement.clientHeight ); var scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0; var clientHeight = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight || 0; // 计算距离底部距离,允许20px误差 var distanceToBottom = scrollHeight - scrollTop - clientHeight; return distanceToBottom <= 20; })(); """.trimIndent() ) { result -> val isBottom = result?.trim() == "true" if (isBottom) { // 标记当前协议已读 when (currentTab) { 1 -> userProtocolRead = true 2 -> privacyProtocolRead = true } updateButtonState(confirmBtn) } } } /** * 更新按钮状态:两个协议都必须阅读完才能点击 */ private fun updateButtonState(confirmBtn: Button) { val allRead = userProtocolRead && privacyProtocolRead if (allRead && !confirmBtn.isEnabled) { confirmBtn.isEnabled = true // confirmBtn.alpha = 1.0f confirmBtn.setTextColor(getResColor(R.color.blue_5)) confirmBtn.text = "同意并继续" // 可选:启用动画 confirmBtn.animate() .scaleX(1.05f) .scaleY(1.05f) .setDuration(150) .withEndAction { confirmBtn.animate() .scaleX(1.0f) .scaleY(1.0f) .setDuration(150) .start() } .start() } else if (!allRead) { confirmBtn.isEnabled = false // confirmBtn.alpha = 0.5f confirmBtn.setTextColor(getResColor(R.color.gray_7)) // 提示还需阅读哪个协议 // val hint = if(currentTab == 1){ // when { // !userProtocolRead -> "请阅读协议" // !privacyProtocolRead -> "请阅读条款" // else -> "请阅读协议" // } // }else{ // when { // !privacyProtocolRead -> "请阅读条款" // !userProtocolRead -> "请阅读协议" // else -> "请阅读协议" // } // } // confirmBtn.text = hint } } }