Migrate WebViewActivity to Compose

This commit is contained in:
arkon
2022-04-24 10:22:22 -04:00
parent 6e95fde4ec
commit 558b18899c
10 changed files with 291 additions and 258 deletions

View File

@@ -2,50 +2,28 @@ package eu.kanade.tachiyomi.ui.webview
import android.content.Context
import android.content.Intent
import android.content.pm.ApplicationInfo
import android.graphics.Bitmap
import android.os.Bundle
import android.view.Menu
import android.view.MenuItem
import android.webkit.WebChromeClient
import android.webkit.WebView
import android.widget.Toast
import androidx.core.graphics.ColorUtils
import androidx.core.view.isInvisible
import androidx.core.view.isVisible
import androidx.lifecycle.lifecycleScope
import eu.kanade.tachiyomi.BuildConfig
import androidx.activity.compose.setContent
import eu.kanade.presentation.theme.TachiyomiTheme
import eu.kanade.presentation.webview.WebViewScreen
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.databinding.WebviewActivityBinding
import eu.kanade.tachiyomi.network.NetworkHelper
import eu.kanade.tachiyomi.source.SourceManager
import eu.kanade.tachiyomi.source.online.HttpSource
import eu.kanade.tachiyomi.ui.base.activity.BaseActivity
import eu.kanade.tachiyomi.util.system.WebViewClientCompat
import eu.kanade.tachiyomi.util.system.WebViewUtil
import eu.kanade.tachiyomi.util.system.getResourceColor
import eu.kanade.tachiyomi.util.system.logcat
import eu.kanade.tachiyomi.util.system.openInBrowser
import eu.kanade.tachiyomi.util.system.setDefaultSettings
import eu.kanade.tachiyomi.util.system.toast
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import okhttp3.HttpUrl.Companion.toHttpUrl
import reactivecircus.flowbinding.appcompat.navigationClicks
import reactivecircus.flowbinding.swiperefreshlayout.refreshes
import uy.kohesive.injekt.injectLazy
class WebViewActivity : BaseActivity() {
private lateinit var binding: WebviewActivityBinding
private val sourceManager: SourceManager by injectLazy()
private val network: NetworkHelper by injectLazy()
private var bundle: Bundle? = null
private var isRefreshing: Boolean = false
init {
registerSecureActivity(this)
}
@@ -59,152 +37,33 @@ class WebViewActivity : BaseActivity() {
return
}
try {
binding = WebviewActivityBinding.inflate(layoutInflater)
setContentView(binding.root)
} catch (e: Throwable) {
// Potentially throws errors like "Error inflating class android.webkit.WebView"
toast(R.string.information_webview_required, Toast.LENGTH_LONG)
finish()
return
val url = intent.extras!!.getString(URL_KEY) ?: return
var headers = mutableMapOf<String, String>()
val source = sourceManager.get(intent.extras!!.getLong(SOURCE_KEY)) as? HttpSource
if (source != null) {
headers = source.headers.toMultimap().mapValues { it.value.getOrNull(0) ?: "" }.toMutableMap()
}
title = intent.extras?.getString(TITLE_KEY)
setSupportActionBar(binding.toolbar)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
binding.toolbar.navigationClicks()
.onEach { super.onBackPressed() }
.launchIn(lifecycleScope)
binding.swipeRefresh.isEnabled = false
binding.swipeRefresh.refreshes()
.onEach { refreshPage() }
.launchIn(lifecycleScope)
if (bundle == null) {
binding.webview.setDefaultSettings()
// Debug mode (chrome://inspect/#devices)
if (BuildConfig.DEBUG && 0 != applicationInfo.flags and ApplicationInfo.FLAG_DEBUGGABLE) {
WebView.setWebContentsDebuggingEnabled(true)
setContent {
TachiyomiTheme {
WebViewScreen(
onUp = { finish() },
initialTitle = intent.extras?.getString(TITLE_KEY),
url = url,
headers = headers,
onShare = this::shareWebpage,
onOpenInBrowser = this::openInBrowser,
onClearCookies = this::clearCookies,
)
}
binding.webview.webChromeClient = object : WebChromeClient() {
override fun onProgressChanged(view: WebView?, newProgress: Int) {
binding.progressBar.isVisible = true
binding.progressBar.progress = newProgress
if (newProgress == 100) {
binding.progressBar.isInvisible = true
}
super.onProgressChanged(view, newProgress)
}
}
} else {
binding.webview.restoreState(bundle!!)
}
if (bundle == null) {
val url = intent.extras!!.getString(URL_KEY) ?: return
var headers = mutableMapOf<String, String>()
val source = sourceManager.get(intent.extras!!.getLong(SOURCE_KEY)) as? HttpSource
if (source != null) {
headers = source.headers.toMultimap().mapValues { it.value.getOrNull(0) ?: "" }.toMutableMap()
binding.webview.settings.userAgentString = source.headers["User-Agent"]
}
supportActionBar?.subtitle = url
binding.webview.webViewClient = object : WebViewClientCompat() {
override fun shouldOverrideUrlCompat(view: WebView, url: String): Boolean {
view.loadUrl(url, headers)
return true
}
override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) {
super.onPageStarted(view, url, favicon)
invalidateOptionsMenu()
}
override fun onPageFinished(view: WebView?, url: String?) {
super.onPageFinished(view, url)
invalidateOptionsMenu()
title = view?.title
supportActionBar?.subtitle = url
binding.swipeRefresh.isEnabled = true
binding.swipeRefresh.isRefreshing = false
// Reset to top when page refreshes
if (isRefreshing) {
view?.scrollTo(0, 0)
isRefreshing = false
}
}
}
binding.webview.loadUrl(url, headers)
}
}
@Suppress("UNNECESSARY_SAFE_CALL")
override fun onDestroy() {
super.onDestroy()
// Binding sometimes isn't actually instantiated yet somehow
binding?.webview?.destroy()
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.webview, menu)
return true
}
override fun onPrepareOptionsMenu(menu: Menu): Boolean {
val iconTintColor = getResourceColor(R.attr.colorOnSurface)
val translucentIconTintColor = ColorUtils.setAlphaComponent(iconTintColor, 127)
menu.findItem(R.id.action_web_back).apply {
isEnabled = binding.webview.canGoBack()
icon.setTint(if (binding.webview.canGoBack()) iconTintColor else translucentIconTintColor)
}
menu.findItem(R.id.action_web_forward).apply {
isEnabled = binding.webview.canGoForward()
icon.setTint(if (binding.webview.canGoForward()) iconTintColor else translucentIconTintColor)
}
return super.onPrepareOptionsMenu(menu)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.action_web_back -> binding.webview.goBack()
R.id.action_web_forward -> binding.webview.goForward()
R.id.action_web_refresh -> refreshPage()
R.id.action_web_share -> shareWebpage()
R.id.action_web_browser -> openInBrowser()
R.id.action_clear_cookies -> clearCookies()
}
return super.onOptionsItemSelected(item)
}
override fun onBackPressed() {
if (binding.webview.canGoBack()) binding.webview.goBack()
else super.onBackPressed()
}
private fun refreshPage() {
binding.swipeRefresh.isRefreshing = true
binding.webview.reload()
isRefreshing = true
}
private fun shareWebpage() {
private fun shareWebpage(url: String) {
try {
val intent = Intent(Intent.ACTION_SEND).apply {
type = "text/plain"
putExtra(Intent.EXTRA_TEXT, binding.webview.url)
putExtra(Intent.EXTRA_TEXT, url)
}
startActivity(Intent.createChooser(intent, getString(R.string.action_share)))
} catch (e: Exception) {
@@ -212,12 +71,11 @@ class WebViewActivity : BaseActivity() {
}
}
private fun openInBrowser() {
openInBrowser(binding.webview.url!!, forceDefaultBrowser = true)
private fun openInBrowser(url: String) {
openInBrowser(url, forceDefaultBrowser = true)
}
private fun clearCookies() {
val url = binding.webview.url!!
private fun clearCookies(url: String) {
val cleared = network.cookieManager.remove(url.toHttpUrl())
logcat { "Cleared $cleared cookies for: $url" }
}