forked from github/wulkanowy-mirror
Make some improvements in captcha dialog (#2393)
* Add improvements retrying after captcha solved * Add showAuthDialog from BaseActivity instead of displaying this dialog manually * Add getCookieStore() with removeAll impl in WebkitCookieManagerProxy * Add debounce to captcha dialog showing logic * Add refresh button to captcha dialog * Destroy webview along with captcha dialog * Add clear webkit cookies button to debug menu * Add captcha error message * Update captcha verified message
This commit is contained in:
parent
a98e8398fd
commit
096fe359e7
@ -65,8 +65,6 @@ class TimetableNotificationSchedulerHelper @Inject constructor(
|
||||
range = lesson.start..lesson.end,
|
||||
requestCode = getRequestCode(lesson.start, studentId)
|
||||
)
|
||||
|
||||
Timber.d("TimetableNotification canceled: type 1 & 2, subject: ${lesson.subject}, start: ${lesson.start}, student: $studentId")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,6 @@ import android.widget.Toast
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import androidx.viewbinding.ViewBinding
|
||||
import com.google.android.material.elevation.SurfaceColors
|
||||
import io.github.wulkanowy.ui.modules.auth.AuthDialog
|
||||
import io.github.wulkanowy.utils.AnalyticsHelper
|
||||
import io.github.wulkanowy.utils.lifecycleAwareVariable
|
||||
import javax.inject.Inject
|
||||
@ -49,7 +48,7 @@ abstract class BaseDialogFragment<VB : ViewBinding> : DialogFragment(), BaseView
|
||||
}
|
||||
|
||||
override fun showAuthDialog() {
|
||||
AuthDialog.newInstance().show(childFragmentManager, "auth_dialog")
|
||||
(activity as? BaseActivity<*, *>)?.showAuthDialog()
|
||||
}
|
||||
|
||||
override fun showErrorDetailsDialog(error: Throwable) {
|
||||
|
@ -7,7 +7,6 @@ import androidx.viewbinding.ViewBinding
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
import com.google.android.material.snackbar.Snackbar.LENGTH_LONG
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.ui.modules.auth.AuthDialog
|
||||
import io.github.wulkanowy.utils.lifecycleAwareVariable
|
||||
|
||||
abstract class BaseFragment<VB : ViewBinding>(@LayoutRes layoutId: Int) : Fragment(layoutId),
|
||||
@ -52,7 +51,7 @@ abstract class BaseFragment<VB : ViewBinding>(@LayoutRes layoutId: Int) : Fragme
|
||||
}
|
||||
|
||||
override fun showAuthDialog() {
|
||||
AuthDialog.newInstance().show(childFragmentManager, "auth_dialog")
|
||||
(activity as? BaseActivity<*, *>)?.showAuthDialog()
|
||||
}
|
||||
|
||||
override fun openClearLoginView() {
|
||||
|
@ -5,12 +5,11 @@ import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.webkit.WebResourceError
|
||||
import android.webkit.WebResourceRequest
|
||||
import android.webkit.WebView
|
||||
import android.webkit.WebViewClient
|
||||
import androidx.core.os.bundleOf
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.databinding.DialogCaptchaBinding
|
||||
import io.github.wulkanowy.sdk.Sdk
|
||||
import io.github.wulkanowy.ui.base.BaseDialogFragment
|
||||
@ -23,8 +22,13 @@ class CaptchaDialog : BaseDialogFragment<DialogCaptchaBinding>() {
|
||||
@Inject
|
||||
lateinit var sdk: Sdk
|
||||
|
||||
private var webView: WebView? = null
|
||||
|
||||
companion object {
|
||||
const val CAPTCHA_SUCCESS = "captcha_success"
|
||||
private const val CAPTCHA_URL = "captcha_url"
|
||||
private const val CAPTCHA_CHECK_JS = "document.getElementById('challenge-running') == null"
|
||||
|
||||
fun newInstance(url: String?): CaptchaDialog {
|
||||
return CaptchaDialog().apply {
|
||||
arguments = bundleOf(CAPTCHA_URL to url)
|
||||
@ -41,8 +45,14 @@ class CaptchaDialog : BaseDialogFragment<DialogCaptchaBinding>() {
|
||||
@SuppressLint("SetJavaScriptEnabled")
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
isCancelable = false
|
||||
binding.captchaRefresh.setOnClickListener {
|
||||
binding.captchaWebview.loadUrl(arguments?.getString(CAPTCHA_URL).orEmpty())
|
||||
}
|
||||
binding.captchaClose.setOnClickListener { dismiss() }
|
||||
|
||||
with(binding.captchaWebview) {
|
||||
webView = this
|
||||
with(settings) {
|
||||
javaScriptEnabled = true
|
||||
userAgentString = sdk.userAgent
|
||||
@ -50,23 +60,27 @@ class CaptchaDialog : BaseDialogFragment<DialogCaptchaBinding>() {
|
||||
|
||||
webViewClient = object : WebViewClient() {
|
||||
override fun onPageFinished(view: WebView?, url: String?) {
|
||||
view?.evaluateJavascript("document.getElementById('challenge-running') == undefined") {
|
||||
view?.evaluateJavascript(CAPTCHA_CHECK_JS) {
|
||||
if (it == "true") {
|
||||
dismiss()
|
||||
} else Timber.e("JS result: $it")
|
||||
onChallengeAccepted()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onReceivedError(
|
||||
view: WebView?,
|
||||
request: WebResourceRequest?,
|
||||
error: WebResourceError?
|
||||
) {
|
||||
super.onReceivedError(view, request, error)
|
||||
}
|
||||
}
|
||||
|
||||
loadUrl(arguments?.getString(CAPTCHA_URL).orEmpty())
|
||||
}
|
||||
}
|
||||
|
||||
private fun onChallengeAccepted() {
|
||||
runCatching { parentFragmentManager.setFragmentResult(CAPTCHA_SUCCESS, bundleOf()) }
|
||||
.onFailure { Timber.e(it) }
|
||||
showMessage(getString(R.string.captcha_verified_message))
|
||||
dismiss()
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
webView?.destroy()
|
||||
super.onDestroy()
|
||||
}
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ import io.github.wulkanowy.databinding.FragmentDashboardBinding
|
||||
import io.github.wulkanowy.ui.base.BaseFragment
|
||||
import io.github.wulkanowy.ui.modules.account.accountdetails.AccountDetailsFragment
|
||||
import io.github.wulkanowy.ui.modules.attendance.summary.AttendanceSummaryFragment
|
||||
import io.github.wulkanowy.ui.modules.captcha.CaptchaDialog.Companion.CAPTCHA_SUCCESS
|
||||
import io.github.wulkanowy.ui.modules.conference.ConferenceFragment
|
||||
import io.github.wulkanowy.ui.modules.dashboard.adapters.DashboardAdapter
|
||||
import io.github.wulkanowy.ui.modules.exam.ExamFragment
|
||||
@ -36,6 +37,7 @@ import io.github.wulkanowy.utils.getErrorString
|
||||
import io.github.wulkanowy.utils.getThemeAttrColor
|
||||
import io.github.wulkanowy.utils.openInternetBrowser
|
||||
import io.github.wulkanowy.utils.toFormattedString
|
||||
import timber.log.Timber
|
||||
import java.time.LocalDate
|
||||
import javax.inject.Inject
|
||||
|
||||
@ -62,6 +64,9 @@ class DashboardFragment : BaseFragment<FragmentDashboardBinding>(R.layout.fragme
|
||||
return ((recyclerWidth - margin) / resources.displayMetrics.density).toInt()
|
||||
}
|
||||
|
||||
override val isViewEmpty
|
||||
get() = dashboardAdapter.itemCount == 0
|
||||
|
||||
companion object {
|
||||
|
||||
fun newInstance() = DashboardFragment()
|
||||
@ -77,6 +82,13 @@ class DashboardFragment : BaseFragment<FragmentDashboardBinding>(R.layout.fragme
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
binding = FragmentDashboardBinding.bind(view)
|
||||
presenter.onAttachView(this)
|
||||
initializeCaptchaResultObserver()
|
||||
}
|
||||
|
||||
private fun initializeCaptchaResultObserver() {
|
||||
childFragmentManager.setFragmentResultListener(CAPTCHA_SUCCESS, this) { _, _ ->
|
||||
presenter.onRetryAfterCaptcha()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||
|
@ -239,6 +239,14 @@ class DashboardPresenter @Inject constructor(
|
||||
loadData(selectedDashboardTiles, forceRefresh = true)
|
||||
}
|
||||
|
||||
fun onRetryAfterCaptcha() {
|
||||
view?.run {
|
||||
showErrorView(false)
|
||||
showProgress(true)
|
||||
}
|
||||
loadData(selectedDashboardTiles, forceRefresh = true)
|
||||
}
|
||||
|
||||
fun onViewReselected() {
|
||||
Timber.i("Dashboard view is reselected")
|
||||
view?.run {
|
||||
|
@ -6,6 +6,8 @@ interface DashboardView : BaseView {
|
||||
|
||||
val tileWidth: Int
|
||||
|
||||
val isViewEmpty: Boolean
|
||||
|
||||
fun initView()
|
||||
|
||||
fun updateData(data: List<DashboardItem>)
|
||||
@ -27,6 +29,5 @@ interface DashboardView : BaseView {
|
||||
fun popViewToRoot()
|
||||
|
||||
fun openNotificationsCenterView()
|
||||
|
||||
fun openInternetBrowser(url: String)
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package io.github.wulkanowy.ui.modules.debug
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.webkit.CookieManager
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import io.github.wulkanowy.R
|
||||
@ -58,6 +59,10 @@ class DebugFragment : BaseFragment<FragmentDebugBinding>(R.layout.fragment_debug
|
||||
(activity as? MainActivity)?.pushView(NotificationDebugFragment.newInstance())
|
||||
}
|
||||
|
||||
override fun clearWebkitCookies() {
|
||||
CookieManager.getInstance().removeAllCookies(null)
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
presenter.onDetachView()
|
||||
super.onDestroyView()
|
||||
|
@ -15,6 +15,7 @@ class DebugPresenter @Inject constructor(
|
||||
val items = listOf(
|
||||
DebugItem(R.string.logviewer_title),
|
||||
DebugItem(R.string.notification_debug_title),
|
||||
DebugItem(R.string.debug_cookies_clear),
|
||||
)
|
||||
|
||||
override fun onAttachView(view: DebugView) {
|
||||
@ -31,6 +32,7 @@ class DebugPresenter @Inject constructor(
|
||||
when (item.title) {
|
||||
R.string.logviewer_title -> view?.openLogViewer()
|
||||
R.string.notification_debug_title -> view?.openNotificationsDebug()
|
||||
R.string.debug_cookies_clear -> view?.clearWebkitCookies()
|
||||
else -> Timber.d("Unknown debug item: $item")
|
||||
}
|
||||
}
|
||||
|
@ -11,4 +11,6 @@ interface DebugView : BaseView {
|
||||
fun openLogViewer()
|
||||
|
||||
fun openNotificationsDebug()
|
||||
|
||||
fun clearWebkitCookies()
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ import android.view.View.GONE
|
||||
import android.view.View.VISIBLE
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.core.widget.doOnTextChanged
|
||||
import androidx.fragment.app.setFragmentResultListener
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.data.db.entities.AdminMessage
|
||||
@ -14,6 +15,7 @@ import io.github.wulkanowy.data.pojos.RegisterUser
|
||||
import io.github.wulkanowy.data.repositories.PreferencesRepository
|
||||
import io.github.wulkanowy.databinding.FragmentLoginFormBinding
|
||||
import io.github.wulkanowy.ui.base.BaseFragment
|
||||
import io.github.wulkanowy.ui.modules.captcha.CaptchaDialog
|
||||
import io.github.wulkanowy.ui.modules.dashboard.viewholders.AdminMessageViewHolder
|
||||
import io.github.wulkanowy.ui.modules.login.LoginActivity
|
||||
import io.github.wulkanowy.ui.modules.login.LoginData
|
||||
@ -72,6 +74,13 @@ class LoginFormFragment : BaseFragment<FragmentLoginFormBinding>(R.layout.fragme
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
binding = FragmentLoginFormBinding.bind(view)
|
||||
presenter.onAttachView(this)
|
||||
initializeCaptchaResultObserver()
|
||||
}
|
||||
|
||||
private fun initializeCaptchaResultObserver() {
|
||||
setFragmentResultListener(CaptchaDialog.CAPTCHA_SUCCESS) { _, _ ->
|
||||
presenter.onRetryAfterCaptcha()
|
||||
}
|
||||
}
|
||||
|
||||
override fun initView() {
|
||||
|
@ -152,6 +152,10 @@ class LoginFormPresenter @Inject constructor(
|
||||
)
|
||||
}
|
||||
|
||||
fun onRetryAfterCaptcha() {
|
||||
onSignInClick()
|
||||
}
|
||||
|
||||
fun onSignInClick() {
|
||||
val loginData = getLoginData()
|
||||
|
||||
|
@ -16,6 +16,7 @@ import androidx.core.view.isVisible
|
||||
import androidx.core.view.updateLayoutParams
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.preference.Preference
|
||||
import androidx.preference.PreferenceFragmentCompat
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
@ -30,6 +31,8 @@ import io.github.wulkanowy.databinding.ActivityMainBinding
|
||||
import io.github.wulkanowy.ui.base.BaseActivity
|
||||
import io.github.wulkanowy.ui.modules.Destination
|
||||
import io.github.wulkanowy.ui.modules.account.accountquick.AccountQuickDialog
|
||||
import io.github.wulkanowy.ui.modules.auth.AuthDialog
|
||||
import io.github.wulkanowy.ui.modules.captcha.CaptchaDialog
|
||||
import io.github.wulkanowy.ui.modules.settings.appearance.menuorder.AppMenuItem
|
||||
import io.github.wulkanowy.utils.AnalyticsHelper
|
||||
import io.github.wulkanowy.utils.AppInfo
|
||||
@ -40,10 +43,17 @@ import io.github.wulkanowy.utils.dpToPx
|
||||
import io.github.wulkanowy.utils.nickOrName
|
||||
import io.github.wulkanowy.utils.safelyPopFragments
|
||||
import io.github.wulkanowy.utils.setOnViewChangeListener
|
||||
import kotlinx.coroutines.FlowPreview
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.flow.debounce
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
|
||||
@AndroidEntryPoint
|
||||
class MainActivity : BaseActivity<MainPresenter, ActivityMainBinding>(), MainView,
|
||||
@ -73,6 +83,8 @@ class MainActivity : BaseActivity<MainPresenter, ActivityMainBinding>(), MainVie
|
||||
private val navController =
|
||||
FragNavController(supportFragmentManager, R.id.main_fragment_container)
|
||||
|
||||
private val captchaVerificationEvent = MutableSharedFlow<String?>()
|
||||
|
||||
companion object {
|
||||
|
||||
private const val EXTRA_START_DESTINATION = "start_destination_json"
|
||||
@ -144,6 +156,7 @@ class MainActivity : BaseActivity<MainPresenter, ActivityMainBinding>(), MainVie
|
||||
initializeToolbar()
|
||||
initializeBottomNavigation(startMenuIndex, rootAppMenuItems)
|
||||
initializeNavController(startMenuIndex, rootUpdatedDestinations)
|
||||
initializeCaptchaVerificationEvent()
|
||||
}
|
||||
|
||||
private fun initializeNavController(
|
||||
@ -323,6 +336,27 @@ class MainActivity : BaseActivity<MainPresenter, ActivityMainBinding>(), MainVie
|
||||
.show()
|
||||
}
|
||||
|
||||
@OptIn(FlowPreview::class)
|
||||
private fun initializeCaptchaVerificationEvent() {
|
||||
captchaVerificationEvent
|
||||
.debounce(1.seconds)
|
||||
.onEach { url ->
|
||||
Timber.d("Showing captcha dialog for: $url")
|
||||
showDialogFragment(CaptchaDialog.newInstance(url))
|
||||
}
|
||||
.launchIn(lifecycleScope)
|
||||
}
|
||||
|
||||
override fun onCaptchaVerificationRequired(url: String?) {
|
||||
lifecycleScope.launch {
|
||||
captchaVerificationEvent.emit(url)
|
||||
}
|
||||
}
|
||||
|
||||
override fun showAuthDialog() {
|
||||
showDialogFragment(AuthDialog.newInstance())
|
||||
}
|
||||
|
||||
override fun onSaveInstanceState(outState: Bundle) {
|
||||
super.onSaveInstanceState(outState)
|
||||
navController.onSaveInstanceState(outState)
|
||||
|
@ -8,7 +8,6 @@ import dagger.hilt.android.AndroidEntryPoint
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.ui.base.BaseActivity
|
||||
import io.github.wulkanowy.ui.base.ErrorDialog
|
||||
import io.github.wulkanowy.ui.modules.auth.AuthDialog
|
||||
import io.github.wulkanowy.ui.modules.main.MainView
|
||||
import io.github.wulkanowy.utils.AppInfo
|
||||
import javax.inject.Inject
|
||||
@ -72,7 +71,7 @@ class AdvancedFragment : PreferenceFragmentCompat(),
|
||||
}
|
||||
|
||||
override fun showAuthDialog() {
|
||||
AuthDialog.newInstance().show(childFragmentManager, "auth_dialog")
|
||||
(activity as? BaseActivity<*, *>)?.showAuthDialog()
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
|
@ -9,7 +9,6 @@ import dagger.hilt.android.AndroidEntryPoint
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.ui.base.BaseActivity
|
||||
import io.github.wulkanowy.ui.base.ErrorDialog
|
||||
import io.github.wulkanowy.ui.modules.auth.AuthDialog
|
||||
import io.github.wulkanowy.ui.modules.main.MainView
|
||||
import io.github.wulkanowy.utils.AppInfo
|
||||
import javax.inject.Inject
|
||||
@ -88,7 +87,7 @@ class AppearanceFragment : PreferenceFragmentCompat(),
|
||||
}
|
||||
|
||||
override fun showAuthDialog() {
|
||||
AuthDialog.newInstance().show(childFragmentManager, "auth_dialog")
|
||||
(activity as? BaseActivity<*, *>)?.showAuthDialog()
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
|
@ -21,7 +21,6 @@ import dagger.hilt.android.AndroidEntryPoint
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.ui.base.BaseActivity
|
||||
import io.github.wulkanowy.ui.base.ErrorDialog
|
||||
import io.github.wulkanowy.ui.modules.auth.AuthDialog
|
||||
import io.github.wulkanowy.ui.modules.main.MainView
|
||||
import io.github.wulkanowy.utils.AppInfo
|
||||
import io.github.wulkanowy.utils.openInternetBrowser
|
||||
@ -158,7 +157,7 @@ class NotificationsFragment : PreferenceFragmentCompat(),
|
||||
}
|
||||
|
||||
override fun showAuthDialog() {
|
||||
AuthDialog.newInstance().show(childFragmentManager, "auth_dialog")
|
||||
(activity as? BaseActivity<*, *>)?.showAuthDialog()
|
||||
}
|
||||
|
||||
override fun showFixSyncDialog() {
|
||||
|
@ -10,7 +10,6 @@ import dagger.hilt.android.AndroidEntryPoint
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.ui.base.BaseActivity
|
||||
import io.github.wulkanowy.ui.base.ErrorDialog
|
||||
import io.github.wulkanowy.ui.modules.auth.AuthDialog
|
||||
import io.github.wulkanowy.ui.modules.main.MainView
|
||||
import javax.inject.Inject
|
||||
|
||||
@ -109,7 +108,7 @@ class SyncFragment : PreferenceFragmentCompat(),
|
||||
}
|
||||
|
||||
override fun showAuthDialog() {
|
||||
AuthDialog.newInstance().show(childFragmentManager, "auth_dialog")
|
||||
(activity as? BaseActivity<*, *>)?.showAuthDialog()
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
|
@ -3,6 +3,7 @@ package io.github.wulkanowy.utils
|
||||
import android.content.res.Resources
|
||||
import io.github.wulkanowy.R
|
||||
import io.github.wulkanowy.sdk.exception.FeatureNotAvailableException
|
||||
import io.github.wulkanowy.sdk.scrapper.exception.CloudflareVerificationException
|
||||
import io.github.wulkanowy.sdk.scrapper.exception.FeatureDisabledException
|
||||
import io.github.wulkanowy.sdk.scrapper.exception.ScrapperException
|
||||
import io.github.wulkanowy.sdk.scrapper.exception.ServiceUnavailableException
|
||||
@ -34,6 +35,7 @@ fun Resources.getErrorString(error: Throwable): String = when (error) {
|
||||
is FeatureNotAvailableException -> R.string.error_feature_not_available
|
||||
is VulcanException -> R.string.error_unknown_uonet
|
||||
is ScrapperException -> R.string.error_unknown_app
|
||||
is CloudflareVerificationException -> R.string.error_cloudflare_captcha
|
||||
is SSLHandshakeException -> when {
|
||||
error.isCausedByCertificateNotValidNow() -> R.string.error_invalid_device_datetime
|
||||
else -> R.string.error_timeout
|
||||
|
@ -1,6 +1,8 @@
|
||||
package io.github.wulkanowy.utils
|
||||
|
||||
import java.net.CookiePolicy
|
||||
import java.net.CookieStore
|
||||
import java.net.HttpCookie
|
||||
import java.net.URI
|
||||
import android.webkit.CookieManager as WebkitCookieManager
|
||||
import java.net.CookieManager as JavaCookieManager
|
||||
@ -36,4 +38,21 @@ class WebkitCookieManagerProxy : JavaCookieManager(null, CookiePolicy.ACCEPT_ALL
|
||||
if (cookie != null) res["Cookie"] = listOf(cookie)
|
||||
return res
|
||||
}
|
||||
|
||||
override fun getCookieStore(): CookieStore {
|
||||
val cookies = super.getCookieStore()
|
||||
return object : CookieStore {
|
||||
override fun add(uri: URI?, cookie: HttpCookie?) = cookies.add(uri, cookie)
|
||||
override fun get(uri: URI?): List<HttpCookie> = cookies.get(uri)
|
||||
override fun getCookies(): List<HttpCookie> = cookies.cookies
|
||||
override fun getURIs(): List<URI> = cookies.urIs
|
||||
override fun remove(uri: URI?, cookie: HttpCookie?): Boolean =
|
||||
cookies.remove(uri, cookie)
|
||||
|
||||
override fun removeAll(): Boolean {
|
||||
webkitCookieManager.removeAllCookies(null)
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,51 @@
|
||||
<androidx.constraintlayout.widget.ConstraintLayout 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:minWidth="350dp"
|
||||
tools:context=".ui.modules.captcha.CaptchaDialog">
|
||||
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="20dp"
|
||||
android:gravity="center_vertical"
|
||||
android:text="@string/captcha_dialog_title"
|
||||
app:layout_constraintBottom_toBottomOf="@id/captcha_close"
|
||||
app:layout_constraintEnd_toStartOf="@id/captcha_refresh"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/captcha_refresh"
|
||||
style="@style/Widget.Material3.Button.IconButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="end"
|
||||
android:contentDescription="@string/logviewer_refresh"
|
||||
app:icon="@drawable/ic_refresh"
|
||||
app:iconTint="?colorOnSurface"
|
||||
app:layout_constraintEnd_toStartOf="@id/captcha_close"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/captcha_close"
|
||||
style="@style/Widget.Material3.Button.IconButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="end"
|
||||
android:contentDescription="@string/all_close"
|
||||
app:icon="@drawable/ic_all_close_circle"
|
||||
app:iconTint="?colorOnSurface"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<WebView
|
||||
android:id="@+id/captcha_webview"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
android:layout_height="match_parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/captcha_close" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
@ -14,6 +14,7 @@
|
||||
<string name="logviewer_title">Log viewer</string>
|
||||
<string name="debug_title">Debug</string>
|
||||
<string name="notification_debug_title">Notification debug</string>
|
||||
<string name="debug_cookies_clear">Clear webview cookies</string>
|
||||
<string name="contributors_title">Contributors</string>
|
||||
<string name="license_title">Licenses</string>
|
||||
<string name="message_title">Messages</string>
|
||||
@ -833,6 +834,11 @@
|
||||
<string name="auth_button_skip">Skip for now</string>
|
||||
|
||||
|
||||
<!--Captcha-->
|
||||
<string name="captcha_dialog_title">Verification is in progress. Wait…</string>
|
||||
<string name="captcha_verified_message">Verified successfully</string>
|
||||
|
||||
|
||||
<!--Errors-->
|
||||
<string name="error_no_internet">No internet connection</string>
|
||||
<string name="error_invalid_device_datetime">An error occurred. Check your device clock</string>
|
||||
@ -842,6 +848,7 @@
|
||||
<string name="error_service_unavailable">Maintenance underway UONET + register. Try again later</string>
|
||||
<string name="error_unknown_uonet">Unknown UONET + register error. Try again later</string>
|
||||
<string name="error_unknown_app">Unknown application error. Please try again later</string>
|
||||
<string name="error_cloudflare_captcha">Captcha verification required</string>
|
||||
<string name="error_unknown">An unexpected error occurred</string>
|
||||
<string name="error_feature_disabled">Feature disabled by your school</string>
|
||||
<string name="error_feature_not_available">Feature not available. Login in a mode other than Mobile API</string>
|
||||
|
Loading…
x
Reference in New Issue
Block a user