Add linear progress bar and refactor WebViewCallback

This commit is contained in:
Grigorii 2022-12-27 15:44:42 +04:00
parent 4ebe674620
commit 49037036b4
8 changed files with 107 additions and 82 deletions

View File

@ -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 }

View File

@ -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'
}
}
}
}

View File

@ -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)
}
}

View File

@ -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<String, String>?) -> 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<String, String>?) {
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)
}
}
}

View File

@ -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
}

View File

@ -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<String, String>?)
fun onRepeatButtonClicked()
fun actionOnRedirectInsideWebView(webView: WebView, url: String?)
fun onPageCookiesLoaded(cookies: Map<String, String>?) = 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
}

View File

@ -24,6 +24,14 @@
android:layout_height="32dp"
android:layout_gravity="center" />
<ProgressBar
style="@style/Widget.AppCompat.ProgressBar.Horizontal"
android:id="@+id/linear_progress_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_gravity="center" />
<LinearLayout
android:id="@+id/error_layout"
android:layout_width="match_parent"

View File

@ -9,6 +9,8 @@
<attr name="repeatButtonTextAppearance" format="reference"/>
<attr name="errorTextAppearance" format="reference"/>
<attr name="progressBarTintColor" format="color"/>
<attr name="isCircleProgressBar" format="boolean"/>
<attr name="isPullToRefreshEnabled" format="boolean"/>
</declare-styleable>
</resources>