From 096fe359e72abb67dc3cd7608428c5f91d29f334 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Pich?= Date: Sun, 14 Jan 2024 14:09:04 +0100 Subject: [PATCH] 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 --- .../TimetableNotificationSchedulerHelper.kt | 2 - .../wulkanowy/ui/base/BaseDialogFragment.kt | 3 +- .../github/wulkanowy/ui/base/BaseFragment.kt | 3 +- .../ui/modules/captcha/CaptchaDialog.kt | 40 ++++++++++++------ .../ui/modules/dashboard/DashboardFragment.kt | 12 ++++++ .../modules/dashboard/DashboardPresenter.kt | 8 ++++ .../ui/modules/dashboard/DashboardView.kt | 3 +- .../ui/modules/debug/DebugFragment.kt | 5 +++ .../ui/modules/debug/DebugPresenter.kt | 2 + .../wulkanowy/ui/modules/debug/DebugView.kt | 2 + .../modules/login/form/LoginFormFragment.kt | 9 ++++ .../modules/login/form/LoginFormPresenter.kt | 4 ++ .../wulkanowy/ui/modules/main/MainActivity.kt | 34 +++++++++++++++ .../settings/advanced/AdvancedFragment.kt | 3 +- .../settings/appearance/AppearanceFragment.kt | 3 +- .../notifications/NotificationsFragment.kt | 3 +- .../ui/modules/settings/sync/SyncFragment.kt | 3 +- .../wulkanowy/utils/ExceptionExtension.kt | 2 + .../utils/WebkitCookieManagerProxy.kt | 19 +++++++++ app/src/main/res/layout/dialog_captcha.xml | 41 ++++++++++++++++++- app/src/main/res/values/strings.xml | 7 ++++ 21 files changed, 179 insertions(+), 29 deletions(-) diff --git a/app/src/main/java/io/github/wulkanowy/services/alarm/TimetableNotificationSchedulerHelper.kt b/app/src/main/java/io/github/wulkanowy/services/alarm/TimetableNotificationSchedulerHelper.kt index 42078d03f..aae7882f1 100644 --- a/app/src/main/java/io/github/wulkanowy/services/alarm/TimetableNotificationSchedulerHelper.kt +++ b/app/src/main/java/io/github/wulkanowy/services/alarm/TimetableNotificationSchedulerHelper.kt @@ -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") } } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/base/BaseDialogFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/base/BaseDialogFragment.kt index cb85fd8aa..e63887b8f 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/base/BaseDialogFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/base/BaseDialogFragment.kt @@ -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 : DialogFragment(), BaseView } override fun showAuthDialog() { - AuthDialog.newInstance().show(childFragmentManager, "auth_dialog") + (activity as? BaseActivity<*, *>)?.showAuthDialog() } override fun showErrorDetailsDialog(error: Throwable) { diff --git a/app/src/main/java/io/github/wulkanowy/ui/base/BaseFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/base/BaseFragment.kt index 4f919f456..ba346131c 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/base/BaseFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/base/BaseFragment.kt @@ -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(@LayoutRes layoutId: Int) : Fragment(layoutId), @@ -52,7 +51,7 @@ abstract class BaseFragment(@LayoutRes layoutId: Int) : Fragme } override fun showAuthDialog() { - AuthDialog.newInstance().show(childFragmentManager, "auth_dialog") + (activity as? BaseActivity<*, *>)?.showAuthDialog() } override fun openClearLoginView() { diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/captcha/CaptchaDialog.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/captcha/CaptchaDialog.kt index 6c4d6420f..098d08ed9 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/captcha/CaptchaDialog.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/captcha/CaptchaDialog.kt @@ -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() { @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() { @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() { 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() + } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/DashboardFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/DashboardFragment.kt index 301262a04..bedbce231 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/DashboardFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/DashboardFragment.kt @@ -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(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(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) { diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/DashboardPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/DashboardPresenter.kt index c93dd9e78..d7add2c05 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/DashboardPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/DashboardPresenter.kt @@ -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 { diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/DashboardView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/DashboardView.kt index 767885434..fe011c929 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/DashboardView.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/dashboard/DashboardView.kt @@ -6,6 +6,8 @@ interface DashboardView : BaseView { val tileWidth: Int + val isViewEmpty: Boolean + fun initView() fun updateData(data: List) @@ -27,6 +29,5 @@ interface DashboardView : BaseView { fun popViewToRoot() fun openNotificationsCenterView() - fun openInternetBrowser(url: String) } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/debug/DebugFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/debug/DebugFragment.kt index 000916b17..9db01a307 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/debug/DebugFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/debug/DebugFragment.kt @@ -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(R.layout.fragment_debug (activity as? MainActivity)?.pushView(NotificationDebugFragment.newInstance()) } + override fun clearWebkitCookies() { + CookieManager.getInstance().removeAllCookies(null) + } + override fun onDestroyView() { presenter.onDetachView() super.onDestroyView() diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/debug/DebugPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/debug/DebugPresenter.kt index 67ac88861..816b59858 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/debug/DebugPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/debug/DebugPresenter.kt @@ -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") } } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/debug/DebugView.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/debug/DebugView.kt index 9396ec6ac..792d63d9e 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/debug/DebugView.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/debug/DebugView.kt @@ -11,4 +11,6 @@ interface DebugView : BaseView { fun openLogViewer() fun openNotificationsDebug() + + fun clearWebkitCookies() } diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormFragment.kt index 8e9b86fa3..975cad185 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormFragment.kt @@ -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(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() { diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormPresenter.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormPresenter.kt index ad535c382..c9ae4f27f 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormPresenter.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/login/form/LoginFormPresenter.kt @@ -152,6 +152,10 @@ class LoginFormPresenter @Inject constructor( ) } + fun onRetryAfterCaptcha() { + onSignInClick() + } + fun onSignInClick() { val loginData = getLoginData() diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/main/MainActivity.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/main/MainActivity.kt index ba0ef4050..62c16257e 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/main/MainActivity.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/main/MainActivity.kt @@ -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(), MainView, @@ -73,6 +83,8 @@ class MainActivity : BaseActivity(), MainVie private val navController = FragNavController(supportFragmentManager, R.id.main_fragment_container) + private val captchaVerificationEvent = MutableSharedFlow() + companion object { private const val EXTRA_START_DESTINATION = "start_destination_json" @@ -144,6 +156,7 @@ class MainActivity : BaseActivity(), MainVie initializeToolbar() initializeBottomNavigation(startMenuIndex, rootAppMenuItems) initializeNavController(startMenuIndex, rootUpdatedDestinations) + initializeCaptchaVerificationEvent() } private fun initializeNavController( @@ -323,6 +336,27 @@ class MainActivity : BaseActivity(), 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) diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/settings/advanced/AdvancedFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/settings/advanced/AdvancedFragment.kt index a1d00227f..3ef1a80a3 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/settings/advanced/AdvancedFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/settings/advanced/AdvancedFragment.kt @@ -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() { diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/settings/appearance/AppearanceFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/settings/appearance/AppearanceFragment.kt index b9b35019a..3d0c8052b 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/settings/appearance/AppearanceFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/settings/appearance/AppearanceFragment.kt @@ -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() { diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/settings/notifications/NotificationsFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/settings/notifications/NotificationsFragment.kt index fdc4a24d9..0bf9ddadd 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/settings/notifications/NotificationsFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/settings/notifications/NotificationsFragment.kt @@ -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() { diff --git a/app/src/main/java/io/github/wulkanowy/ui/modules/settings/sync/SyncFragment.kt b/app/src/main/java/io/github/wulkanowy/ui/modules/settings/sync/SyncFragment.kt index 1e81e58ac..d57144832 100644 --- a/app/src/main/java/io/github/wulkanowy/ui/modules/settings/sync/SyncFragment.kt +++ b/app/src/main/java/io/github/wulkanowy/ui/modules/settings/sync/SyncFragment.kt @@ -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() { diff --git a/app/src/main/java/io/github/wulkanowy/utils/ExceptionExtension.kt b/app/src/main/java/io/github/wulkanowy/utils/ExceptionExtension.kt index a4c2537ac..18fc10bba 100644 --- a/app/src/main/java/io/github/wulkanowy/utils/ExceptionExtension.kt +++ b/app/src/main/java/io/github/wulkanowy/utils/ExceptionExtension.kt @@ -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 diff --git a/app/src/main/java/io/github/wulkanowy/utils/WebkitCookieManagerProxy.kt b/app/src/main/java/io/github/wulkanowy/utils/WebkitCookieManagerProxy.kt index 509f39f58..a54978717 100644 --- a/app/src/main/java/io/github/wulkanowy/utils/WebkitCookieManagerProxy.kt +++ b/app/src/main/java/io/github/wulkanowy/utils/WebkitCookieManagerProxy.kt @@ -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 = cookies.get(uri) + override fun getCookies(): List = cookies.cookies + override fun getURIs(): List = cookies.urIs + override fun remove(uri: URI?, cookie: HttpCookie?): Boolean = + cookies.remove(uri, cookie) + + override fun removeAll(): Boolean { + webkitCookieManager.removeAllCookies(null) + return true + } + } + } } diff --git a/app/src/main/res/layout/dialog_captcha.xml b/app/src/main/res/layout/dialog_captcha.xml index 2df18066d..539aa0cc9 100644 --- a/app/src/main/res/layout/dialog_captcha.xml +++ b/app/src/main/res/layout/dialog_captcha.xml @@ -1,12 +1,51 @@ + + + + + + + android:layout_height="match_parent" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintTop_toBottomOf="@id/captcha_close" /> diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 72910b85c..60d85606d 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -14,6 +14,7 @@ Log viewer Debug Notification debug + Clear webview cookies Contributors Licenses Messages @@ -833,6 +834,11 @@ Skip for now + + Verification is in progress. Wait… + Verified successfully + + No internet connection An error occurred. Check your device clock @@ -842,6 +848,7 @@ Maintenance underway UONET + register. Try again later Unknown UONET + register error. Try again later Unknown application error. Please try again later + Captcha verification required An unexpected error occurred Feature disabled by your school Feature not available. Login in a mode other than Mobile API