diff --git a/modules.gradle b/modules.gradle index 1fff4cf8..81510707 100644 --- a/modules.gradle +++ b/modules.gradle @@ -19,6 +19,7 @@ include ':views' include ':recyclerview-adapters' include ':kotlin-extensions' include ':templates' +include ':webview-delegate' project(':utils').projectDir = new File(rootDir, 'utils') project(':logging').projectDir = new File(rootDir, 'logging') @@ -31,3 +32,4 @@ project(':views').projectDir = new File(rootDir, 'views') project(':recyclerview-adapters').projectDir = new File(rootDir, 'recyclerview-adapters') project(':kotlin-extensions').projectDir = new File(rootDir, 'kotlin-extensions') project(':templates').projectDir = new File(rootDir, 'templates') +project(':webview-delegate').projectDir = new File(rootDir, 'webview-delegate') diff --git a/webview-delegate/.gitignore b/webview-delegate/.gitignore new file mode 100644 index 00000000..796b96d1 --- /dev/null +++ b/webview-delegate/.gitignore @@ -0,0 +1 @@ +/build diff --git a/webview-delegate/build.gradle.kts b/webview-delegate/build.gradle.kts new file mode 100644 index 00000000..e0a033c6 --- /dev/null +++ b/webview-delegate/build.gradle.kts @@ -0,0 +1,26 @@ +import org.jetbrains.kotlin.config.KotlinCompilerVersion + +plugins { + id("com.android.library") + kotlin("android") +} + +val versions: Map by rootProject.extra +android { + compileSdkVersion(versions["compileSdk"] as Int) + + defaultConfig { + minSdkVersion(16) + } + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 + } +} + +dependencies { + implementation(kotlin("stdlib", KotlinCompilerVersion.VERSION)) + implementation("androidx.core:core-ktx:${versions["coreKtx"]}") + implementation("androidx.annotation:annotation:${versions["androidx"]}") +} diff --git a/webview-delegate/src/main/AndroidManifest.xml b/webview-delegate/src/main/AndroidManifest.xml new file mode 100644 index 00000000..81b23a40 --- /dev/null +++ b/webview-delegate/src/main/AndroidManifest.xml @@ -0,0 +1 @@ + diff --git a/webview-delegate/src/main/java/ru/touchin/roboswag/webview_delegate/LoadingState.kt b/webview-delegate/src/main/java/ru/touchin/roboswag/webview_delegate/LoadingState.kt new file mode 100644 index 00000000..61d11847 --- /dev/null +++ b/webview-delegate/src/main/java/ru/touchin/roboswag/webview_delegate/LoadingState.kt @@ -0,0 +1,7 @@ +package ru.touchin.roboswag.webview_delegate + +enum class LoadingState { + LOADING, + ERROR, + LOADED +} diff --git a/webview-delegate/src/main/java/ru/touchin/roboswag/webview_delegate/SimpleWebViewClient.kt b/webview-delegate/src/main/java/ru/touchin/roboswag/webview_delegate/SimpleWebViewClient.kt new file mode 100644 index 00000000..36457b96 --- /dev/null +++ b/webview-delegate/src/main/java/ru/touchin/roboswag/webview_delegate/SimpleWebViewClient.kt @@ -0,0 +1,62 @@ +package ru.touchin.roboswag.webview_delegate + +import android.annotation.TargetApi +import android.graphics.Bitmap +import android.net.http.SslError +import android.os.Build +import android.webkit.SslErrorHandler +import android.webkit.WebResourceError +import android.webkit.WebResourceRequest +import android.webkit.WebView +import android.webkit.WebViewClient + +open class SimpleWebViewClient(private val callback: WebViewCallback) : WebViewClient() { + + var isError = false + + override fun onPageStarted(view: WebView, url: String, favicon: Bitmap?) { + super.onPageStarted(view, url, favicon) + isError = false + callback.onStateChanged(LoadingState.LOADING) + } + + override fun onPageFinished(view: WebView, url: String) { + super.onPageFinished(view, url) + pageFinished(view) + } + + override fun shouldOverrideUrlLoading(view: WebView, url: String?): Boolean { + val shouldOverride = callback.onOverrideUrlLoading(url) + if (!shouldOverride) { + view.loadUrl(url) + } + return shouldOverride + } + + override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean { + return shouldOverrideUrlLoading(view, request.url.toString()) + } + + override fun onReceivedSslError(view: WebView, handler: SslErrorHandler, error: SslError) { + handler.proceed() + } + + private fun pageFinished(view: WebView) { + callback.onStateChanged(if (isError) LoadingState.ERROR else LoadingState.LOADED) + callback.clearCacheAndData(view) + } + + @TargetApi(Build.VERSION_CODES.M) + override fun onReceivedError(view: WebView, request: WebResourceRequest, error: WebResourceError) { + onReceivedError(view, error.errorCode, error.description.toString(), request.url.toString()) + } + + override fun onReceivedError(view: WebView, errorCode: Int, description: String?, failingUrl: String) { + super.onReceivedError(view, errorCode, description, failingUrl) + if (!(errorCode == -10 && "about:blank" == failingUrl)) { + isError = true + } + pageFinished(view) + } + +} diff --git a/webview-delegate/src/main/java/ru/touchin/roboswag/webview_delegate/SimpleWebViewDelegate.kt b/webview-delegate/src/main/java/ru/touchin/roboswag/webview_delegate/SimpleWebViewDelegate.kt new file mode 100644 index 00000000..ff5ca0ef --- /dev/null +++ b/webview-delegate/src/main/java/ru/touchin/roboswag/webview_delegate/SimpleWebViewDelegate.kt @@ -0,0 +1,75 @@ +package ru.touchin.roboswag.webview_delegate + +import android.content.pm.ApplicationInfo +import android.view.View +import android.webkit.WebView +import androidx.annotation.CallSuper +import androidx.core.view.isInvisible +import androidx.core.view.isVisible + +open class SimpleWebViewDelegate( + protected val webView: WebView, + protected open val errorView: View, + protected open val loadingView: View +) : WebViewCallback { + + init { + if (0 != webView.context.applicationInfo.flags and ApplicationInfo.FLAG_DEBUGGABLE) { + WebView.setWebContentsDebuggingEnabled(true) + } + webView.webViewClient = getWebViewClient() + + webView.scrollBarStyle = View.SCROLLBARS_INSIDE_OVERLAY + with(webView.settings) { + loadsImagesAutomatically = true + javaScriptEnabled = true + domStorageEnabled = true + useWideViewPort = true + loadWithOverviewMode = true + } + } + + open fun getWebViewClient() = SimpleWebViewClient(this) + + open override fun clearCacheAndData(view: WebView) { + with(view) { + clearMatches() + clearFormData() + clearCache(true) + } + } + + @CallSuper + open override fun onStateChanged(newState: LoadingState) { + when (newState) { + LoadingState.LOADED -> { + webView.isVisible = true + errorView.isVisible = false + loadingView.isVisible = false + } + LoadingState.LOADING -> { + webView.isInvisible = true + errorView.isVisible = false + loadingView.isVisible = true + } + LoadingState.ERROR -> { + webView.isInvisible = true + errorView.isVisible = true + loadingView.isVisible = false + } + } + } + + open fun loadUrl(url: String?) { + webView.loadUrl(url) + } + + open fun onBackPressed(): Boolean { + if (webView.canGoBack()) { + webView.goBack() + return true + } + return false + } + +} diff --git a/webview-delegate/src/main/java/ru/touchin/roboswag/webview_delegate/WebViewCallback.kt b/webview-delegate/src/main/java/ru/touchin/roboswag/webview_delegate/WebViewCallback.kt new file mode 100644 index 00000000..0d461b52 --- /dev/null +++ b/webview-delegate/src/main/java/ru/touchin/roboswag/webview_delegate/WebViewCallback.kt @@ -0,0 +1,17 @@ +package ru.touchin.roboswag.webview_delegate + +import android.webkit.WebView + +interface WebViewCallback { + + fun onOverrideUrlLoading(url: String?): Boolean = false + + fun onInterceptRequest(url: String) {} + + fun onStartPageLoading(url: String) {} + + fun clearCacheAndData(view: WebView) + + fun onStateChanged(newState: LoadingState) + +}