diff --git a/kotlin-extensions/src/main/java/ru/touchin/extensions/TypedArray.kt b/kotlin-extensions/src/main/java/ru/touchin/extensions/TypedArray.kt index de03034..752368a 100644 --- a/kotlin-extensions/src/main/java/ru/touchin/extensions/TypedArray.kt +++ b/kotlin-extensions/src/main/java/ru/touchin/extensions/TypedArray.kt @@ -2,6 +2,11 @@ package ru.touchin.extensions import android.content.res.TypedArray import androidx.annotation.StyleableRes -import androidx.core.content.res.getResourceIdOrThrow -fun TypedArray.getResourceIdOrNull(@StyleableRes index: Int) = runCatching { getResourceIdOrThrow(index) }.getOrNull() +private const val DEFAULT_VALUE = -1 + +fun TypedArray.getResourceIdOrNull(@StyleableRes index: Int) = getResourceId(index, DEFAULT_VALUE) + .takeIf { it != DEFAULT_VALUE } + +fun TypedArray.getColorOrNull(@StyleableRes index: Int) = getColor(index, DEFAULT_VALUE) + .takeIf { it != DEFAULT_VALUE } diff --git a/webview/build.gradle b/webview/build.gradle index 5b4bd46..35487b8 100644 --- a/webview/build.gradle +++ b/webview/build.gradle @@ -14,6 +14,7 @@ dependencies { implementation "com.google.android.material:material" implementation "androidx.constraintlayout:constraintlayout" implementation "androidx.core:core-ktx" + implementation "androidx.swiperefreshlayout:swiperefreshlayout" constraints { implementation("com.google.android.material:material") { @@ -36,6 +37,11 @@ dependencies { require '1.3.0' } } + implementation("androidx.swiperefreshlayout:swiperefreshlayout") { + version { + require '1.1.0' + } + } } } diff --git a/webview/src/main/java/ru/touchin/roboswag/webview/web_view/BaseChromeWebViewClient.kt b/webview/src/main/java/ru/touchin/roboswag/webview/web_view/BaseChromeWebViewClient.kt index 13754f9..40a221c 100644 --- a/webview/src/main/java/ru/touchin/roboswag/webview/web_view/BaseChromeWebViewClient.kt +++ b/webview/src/main/java/ru/touchin/roboswag/webview/web_view/BaseChromeWebViewClient.kt @@ -7,35 +7,37 @@ import android.webkit.WebChromeClient import android.webkit.WebView open class BaseChromeWebViewClient( - private val onJsConfirm: (() -> Unit)? = null, - private val onJsAlert: (() -> Unit)? = null, - private val onJsPrompt: ((String?) -> Unit)? = null, - private val onJsError: ((error: ConsoleMessage) -> Unit)? = null + private val callback: WebViewCallback ) : WebChromeClient() { override fun onJsConfirm(view: WebView?, url: String?, message: String?, result: JsResult?): Boolean { - onJsConfirm?.invoke() + callback.onJsConfirm(message) result?.confirm() return true } override fun onJsAlert(view: WebView?, url: String?, message: String?, result: JsResult?): Boolean { - onJsAlert?.invoke() + callback.onJsAlert(message) result?.confirm() return true } override fun onConsoleMessage(consoleMessage: ConsoleMessage?): Boolean { if (consoleMessage?.messageLevel() == ConsoleMessage.MessageLevel.ERROR) { - onJsError?.invoke(consoleMessage) + callback.onJsError(consoleMessage) } return super.onConsoleMessage(consoleMessage) } override fun onJsPrompt(view: WebView?, url: String?, message: String?, defaultValue: String?, result: JsPromptResult?): Boolean { - onJsPrompt?.invoke(defaultValue) + callback.onJsPrompt(defaultValue) result?.confirm() return true } + override fun onProgressChanged(view: WebView?, newProgress: Int) { + super.onProgressChanged(view, newProgress) + callback.onProgressChanged(newProgress) + } + } diff --git a/webview/src/main/java/ru/touchin/roboswag/webview/web_view/BaseWebView.kt b/webview/src/main/java/ru/touchin/roboswag/webview/web_view/BaseWebView.kt index 31d7300..08c2708 100644 --- a/webview/src/main/java/ru/touchin/roboswag/webview/web_view/BaseWebView.kt +++ b/webview/src/main/java/ru/touchin/roboswag/webview/web_view/BaseWebView.kt @@ -3,15 +3,14 @@ package ru.touchin.roboswag.webview.web_view import android.annotation.SuppressLint import android.content.Context import android.content.res.ColorStateList -import android.graphics.Color import android.util.AttributeSet import android.view.LayoutInflater import android.view.View -import android.webkit.ConsoleMessage import android.webkit.CookieManager -import android.webkit.WebView import androidx.core.content.withStyledAttributes import androidx.core.widget.TextViewCompat +import ru.touchin.extensions.getColorOrNull +import ru.touchin.extensions.getResourceIdOrNull import ru.touchin.extensions.setOnRippleClickListener import ru.touchin.roboswag.views.widget.Switcher import ru.touchin.roboswag.webview.R @@ -26,17 +25,9 @@ open class BaseWebView @JvmOverloads constructor( private val binding = BaseWebViewBinding.inflate(LayoutInflater.from(context), this) - var onWebViewLoaded: (() -> Unit)? = null - var onWebViewRepeatButtonClicked: (() -> Unit)? = null - var onWebViewScrolled: ((WebView, Int, Int) -> Unit)? = null - var onCookieLoaded: ((cookies: Map?) -> Unit)? = null + private var isCircleProgressBar = true - var onJsConfirm: (() -> Unit)? = null - var onJsAlert: (() -> Unit)? = null - var onJsPrompt: ((defaultValue: String?) -> Unit)? = null - var onJsError: ((error: ConsoleMessage) -> Unit)? = null - - var isPullToRefreshEnable = false + private var isPullToRefreshEnabled = false set(value) { binding.pullToRefresh.isEnabled = value binding.pullToRefresh.isRefreshing = false @@ -45,45 +36,19 @@ open class BaseWebView @JvmOverloads constructor( var redirectionController = RedirectionController() - /** - * If you need to do some action on url click inside WebView, just assign this parameter and disable isRedirectEnable - **/ - var actionOnRedirect: ((String?, WebView) -> Unit)? = null - init { - binding.pullToRefresh.isEnabled = isPullToRefreshEnable + initAttributes(attrs, defStyleAttr) + binding.pullToRefresh.isEnabled = isPullToRefreshEnabled + binding.apply { - context.withStyledAttributes(attrs, R.styleable.BaseWebView, defStyleAttr, 0) { - if (hasValue(R.styleable.BaseWebView_errorTextAppearance)) { - TextViewCompat.setTextAppearance(errorText, getResourceId(R.styleable.BaseWebView_errorTextAppearance, 0)) - } - if (hasValue(R.styleable.BaseWebView_repeatButtonTextAppearance)) { - TextViewCompat.setTextAppearance(errorRepeatButton, getResourceId(R.styleable.BaseWebView_repeatButtonTextAppearance, 0)) - } - if (hasValue(R.styleable.BaseWebView_progressBarTintColor)) { - progressBar.indeterminateTintList = ColorStateList.valueOf(getColor(R.styleable.BaseWebView_progressBarTintColor, Color.BLACK)) - } - if (hasValue(R.styleable.BaseWebView_repeatButtonBackground)) { - errorRepeatButton.setBackgroundResource(getResourceId(R.styleable.BaseWebView_repeatButtonBackground, 0)) - } - if (hasValue(R.styleable.BaseWebView_screenBackground)) { - setBackgroundResource(getResourceId(R.styleable.BaseWebView_screenBackground, 0)) - } - if (hasValue(R.styleable.BaseWebView_errorText)) { - errorText.text = getString(R.styleable.BaseWebView_errorText) - } - if (hasValue(R.styleable.BaseWebView_repeatButtonText)) { - errorRepeatButton.text = getString(R.styleable.BaseWebView_repeatButtonText) - } - } pullToRefresh.setOnRefreshListener { webView.reload() } errorRepeatButton.setOnRippleClickListener { - onWebViewRepeatButtonClicked?.invoke() + onRepeatButtonClicked() } webView.onScrollChanged = { scrollX, scrollY, _, _ -> - onWebViewScrolled?.invoke(binding.webView, scrollX, scrollY) + onWebViewScrolled(scrollX, scrollY) } setWebViewPreferences() } @@ -92,13 +57,11 @@ open class BaseWebView @JvmOverloads constructor( override fun onStateChanged(newState: WebViewLoadingState) { when { newState == WebViewLoadingState.LOADED -> { - onWebViewLoaded?.invoke() binding.pullToRefresh.isRefreshing = false showChild(R.id.pull_to_refresh) } - newState == WebViewLoadingState.LOADING - && !binding.pullToRefresh.isRefreshing -> { - showChild(R.id.progress_bar) + newState == WebViewLoadingState.LOADING && !binding.pullToRefresh.isRefreshing -> { + showChild(if (isCircleProgressBar) R.id.progress_bar else R.id.linear_progress_bar) } newState == WebViewLoadingState.ERROR -> { showChild(R.id.error_layout) @@ -109,17 +72,21 @@ open class BaseWebView @JvmOverloads constructor( override fun onOverrideUrlLoading(url: String?): Boolean = redirectionController.shouldRedirectToUrl(url) - override fun onPageCookiesLoaded(cookies: Map?) { - onCookieLoaded?.invoke(cookies) + override fun onRepeatButtonClicked() { + loadUrl(getWebView().url) } - override fun actionOnRedirectInsideWebView(webView: WebView, url: String?) { - actionOnRedirect?.invoke(url, webView) + override fun onProgressChanged(progress: Int) { + binding.linearProgressBar.progress = progress } - fun setBaseWebViewClient(isSSlPinningEnable: Boolean = true) { - binding.webView.webViewClient = BaseWebViewClient(this, isSSlPinningEnable) - binding.webView.webChromeClient = BaseChromeWebViewClient(onJsConfirm, onJsAlert, onJsPrompt, onJsError) + fun setBaseWebViewClient(callback: WebViewCallback = this) { + binding.webView.webViewClient = BaseWebViewClient(callback) + binding.webView.webChromeClient = BaseChromeWebViewClient(callback) + } + + fun handleBackPressed(closeScreenAction: () -> Unit) { + with(getWebView()) { if (canGoBack()) goBack() else closeScreenAction.invoke() } } fun getWebView() = binding.webView @@ -168,14 +135,6 @@ open class BaseWebView @JvmOverloads constructor( ) } - fun setState(newState: WebViewLoadingState) { - onStateChanged(newState) - } - - fun setOnWebViewDisplayedContentAction(action: () -> Unit) { - binding.webView.onWebViewDisplayedContent = action - } - /** * loadWithOverviewMode loads the WebView completely zoomed out * useWideViewPort sets page size to fit screen @@ -200,4 +159,33 @@ open class BaseWebView @JvmOverloads constructor( } } + private fun initAttributes(attrs: AttributeSet?, defStyleAttr: Int) = with(binding) { + context.withStyledAttributes(attrs, R.styleable.BaseWebView, defStyleAttr, 0) { + getResourceIdOrNull(R.styleable.BaseWebView_errorTextAppearance)?.let { + TextViewCompat.setTextAppearance(errorText, it) + } + getResourceIdOrNull(R.styleable.BaseWebView_repeatButtonTextAppearance)?.let { + TextViewCompat.setTextAppearance(errorRepeatButton, it) + } + getResourceIdOrNull(R.styleable.BaseWebView_repeatButtonBackground)?.let { + errorRepeatButton.setBackgroundResource(it) + } + getColorOrNull(R.styleable.BaseWebView_progressBarTintColor)?.let { + progressBar.indeterminateTintList = ColorStateList.valueOf(it) + linearProgressBar.indeterminateTintList = ColorStateList.valueOf(it) + } + getResourceIdOrNull(R.styleable.BaseWebView_repeatButtonBackground)?.let { + setBackgroundResource(getResourceId(R.styleable.BaseWebView_screenBackground, 0)) + } + + getString(R.styleable.BaseWebView_errorText)?.let { errorText.text = it } + getString(R.styleable.BaseWebView_repeatButtonText)?.let { errorRepeatButton.text = it } + + isCircleProgressBar = getBoolean(R.styleable.BaseWebView_isCircleProgressBar, true) + isPullToRefreshEnabled = getBoolean(R.styleable.BaseWebView_isPullToRefreshEnabled, false) + + onStateChanged(WebViewLoadingState.LOADING) + } + } + } diff --git a/webview/src/main/java/ru/touchin/roboswag/webview/web_view/BaseWebViewClient.kt b/webview/src/main/java/ru/touchin/roboswag/webview/web_view/BaseWebViewClient.kt index 6b1c6d8..a8b8da5 100644 --- a/webview/src/main/java/ru/touchin/roboswag/webview/web_view/BaseWebViewClient.kt +++ b/webview/src/main/java/ru/touchin/roboswag/webview/web_view/BaseWebViewClient.kt @@ -62,7 +62,7 @@ open class BaseWebViewClient( override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean { val url = request.url.toString() return if (!callback.onOverrideUrlLoading(url) && view.originalUrl != null) { - callback.actionOnRedirectInsideWebView(webView = view, url = url) + callback.onRedirectInsideWebView(webView = view, url = url) true } else { false @@ -102,9 +102,3 @@ open class BaseWebViewClient( } } - -enum class WebViewLoadingState { - LOADING, - ERROR, - LOADED -} diff --git a/webview/src/main/java/ru/touchin/roboswag/webview/web_view/WebViewCallback.kt b/webview/src/main/java/ru/touchin/roboswag/webview/web_view/WebViewCallback.kt index d3d62d9..9f5df58 100644 --- a/webview/src/main/java/ru/touchin/roboswag/webview/web_view/WebViewCallback.kt +++ b/webview/src/main/java/ru/touchin/roboswag/webview/web_view/WebViewCallback.kt @@ -1,5 +1,6 @@ package ru.touchin.roboswag.webview.web_view +import android.webkit.ConsoleMessage import android.webkit.WebView interface WebViewCallback { @@ -8,8 +9,27 @@ interface WebViewCallback { fun onOverrideUrlLoading(url: String?): Boolean - fun onPageCookiesLoaded(cookies: Map?) + fun onRepeatButtonClicked() - fun actionOnRedirectInsideWebView(webView: WebView, url: String?) + fun onPageCookiesLoaded(cookies: Map?) = Unit + fun onRedirectInsideWebView(webView: WebView, url: String?) = Unit + + fun onWebViewScrolled(scrollX: Int, scrollY: Int) = Unit + + fun onJsConfirm(message: String?) = Unit + + fun onJsAlert(message: String?) = Unit + + fun onJsPrompt(defaultValue: String?) = Unit + + fun onJsError(error: ConsoleMessage) = Unit + + fun onProgressChanged(progress: Int) = Unit +} + +enum class WebViewLoadingState { + LOADING, + ERROR, + LOADED } diff --git a/webview/src/main/res/layout/base_web_view.xml b/webview/src/main/res/layout/base_web_view.xml index a167e46..37abe44 100644 --- a/webview/src/main/res/layout/base_web_view.xml +++ b/webview/src/main/res/layout/base_web_view.xml @@ -24,6 +24,14 @@ android:layout_height="32dp" android:layout_gravity="center" /> + + + +