mirror of
				https://github.com/mihonapp/mihon.git
				synced 2025-10-31 14:27:57 +01:00 
			
		
		
		
	Migrate WebViewActivity to Compose
This commit is contained in:
		
							
								
								
									
										103
									
								
								app/src/main/java/eu/kanade/presentation/components/AppBar.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										103
									
								
								app/src/main/java/eu/kanade/presentation/components/AppBar.kt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,103 @@ | ||||
| package eu.kanade.presentation.components | ||||
|  | ||||
| import androidx.compose.foundation.layout.Column | ||||
| import androidx.compose.material.icons.Icons | ||||
| import androidx.compose.material.icons.filled.MoreVert | ||||
| import androidx.compose.material3.DropdownMenu | ||||
| import androidx.compose.material3.DropdownMenuItem | ||||
| import androidx.compose.material3.Icon | ||||
| import androidx.compose.material3.IconButton | ||||
| import androidx.compose.material3.MaterialTheme | ||||
| import androidx.compose.material3.Text | ||||
| import androidx.compose.runtime.Composable | ||||
| import androidx.compose.runtime.getValue | ||||
| import androidx.compose.runtime.mutableStateOf | ||||
| import androidx.compose.runtime.remember | ||||
| import androidx.compose.runtime.setValue | ||||
| import androidx.compose.ui.graphics.vector.ImageVector | ||||
| import androidx.compose.ui.res.stringResource | ||||
| import androidx.compose.ui.text.style.TextOverflow | ||||
| import eu.kanade.tachiyomi.R | ||||
|  | ||||
| @Composable | ||||
| fun AppBarTitle( | ||||
|     title: String?, | ||||
|     subtitle: String? = null, | ||||
| ) { | ||||
|     val subtitleTextStyle = MaterialTheme.typography.bodyMedium | ||||
|  | ||||
|     Column { | ||||
|         title?.let { | ||||
|             Text( | ||||
|                 text = it, | ||||
|                 maxLines = 1, | ||||
|                 overflow = TextOverflow.Ellipsis, | ||||
|             ) | ||||
|         } | ||||
|         subtitle?.let { | ||||
|             Text( | ||||
|                 text = it, | ||||
|                 style = subtitleTextStyle, | ||||
|                 maxLines = 1, | ||||
|                 overflow = TextOverflow.Ellipsis, | ||||
|             ) | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| @Composable | ||||
| fun AppBarActions( | ||||
|     actions: List<AppBar.AppBarAction>, | ||||
| ) { | ||||
|     var showMenu by remember { mutableStateOf(false) } | ||||
|  | ||||
|     actions.filterIsInstance<AppBar.Action>().map { | ||||
|         IconButton( | ||||
|             onClick = it.onClick, | ||||
|             enabled = it.isEnabled, | ||||
|         ) { | ||||
|             Icon( | ||||
|                 imageVector = it.icon, | ||||
|                 contentDescription = it.title, | ||||
|             ) | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     val overflowActions = actions.filterIsInstance<AppBar.OverflowAction>() | ||||
|     if (overflowActions.isNotEmpty()) { | ||||
|         IconButton(onClick = { showMenu = !showMenu }) { | ||||
|             Icon(Icons.Default.MoreVert, contentDescription = stringResource(R.string.label_more)) | ||||
|         } | ||||
|  | ||||
|         DropdownMenu( | ||||
|             expanded = showMenu, | ||||
|             onDismissRequest = { showMenu = false } | ||||
|         ) { | ||||
|             overflowActions.map { | ||||
|                 DropdownMenuItem( | ||||
|                     onClick = { | ||||
|                         it.onClick() | ||||
|                         showMenu = false | ||||
|                     }, | ||||
|                     text = { Text(it.title) }, | ||||
|                 ) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| object AppBar { | ||||
|     interface AppBarAction | ||||
|  | ||||
|     data class Action( | ||||
|         val title: String, | ||||
|         val icon: ImageVector, | ||||
|         val onClick: () -> Unit, | ||||
|         val isEnabled: Boolean = true, | ||||
|     ) : AppBarAction | ||||
|  | ||||
|     data class OverflowAction( | ||||
|         val title: String, | ||||
|         val onClick: () -> Unit, | ||||
|     ) : AppBarAction | ||||
| } | ||||
| @@ -0,0 +1,152 @@ | ||||
| package eu.kanade.presentation.webview | ||||
|  | ||||
| import android.content.pm.ApplicationInfo | ||||
| import android.webkit.WebResourceRequest | ||||
| import android.webkit.WebView | ||||
| import androidx.compose.foundation.layout.Box | ||||
| import androidx.compose.foundation.layout.Column | ||||
| import androidx.compose.foundation.layout.fillMaxSize | ||||
| import androidx.compose.foundation.layout.fillMaxWidth | ||||
| import androidx.compose.material.icons.Icons | ||||
| import androidx.compose.material.icons.filled.ArrowBack | ||||
| import androidx.compose.material.icons.filled.ArrowForward | ||||
| import androidx.compose.material.icons.filled.Close | ||||
| import androidx.compose.material3.Icon | ||||
| import androidx.compose.material3.IconButton | ||||
| import androidx.compose.material3.LinearProgressIndicator | ||||
| import androidx.compose.material3.SmallTopAppBar | ||||
| import androidx.compose.runtime.Composable | ||||
| import androidx.compose.runtime.remember | ||||
| import androidx.compose.ui.Modifier | ||||
| import androidx.compose.ui.platform.LocalContext | ||||
| import androidx.compose.ui.res.stringResource | ||||
| import com.google.accompanist.web.AccompanistWebViewClient | ||||
| import com.google.accompanist.web.LoadingState | ||||
| import com.google.accompanist.web.WebView | ||||
| import com.google.accompanist.web.rememberWebViewNavigator | ||||
| import com.google.accompanist.web.rememberWebViewState | ||||
| import eu.kanade.presentation.components.AppBar | ||||
| import eu.kanade.presentation.components.AppBarActions | ||||
| import eu.kanade.presentation.components.AppBarTitle | ||||
| import eu.kanade.tachiyomi.BuildConfig | ||||
| import eu.kanade.tachiyomi.R | ||||
| import eu.kanade.tachiyomi.util.system.setDefaultSettings | ||||
|  | ||||
| @Composable | ||||
| fun WebViewScreen( | ||||
|     onUp: () -> Unit, | ||||
|     initialTitle: String?, | ||||
|     url: String, | ||||
|     headers: Map<String, String> = emptyMap(), | ||||
|     onShare: (String) -> Unit, | ||||
|     onOpenInBrowser: (String) -> Unit, | ||||
|     onClearCookies: (String) -> Unit, | ||||
| ) { | ||||
|     val context = LocalContext.current | ||||
|     val state = rememberWebViewState(url = url) | ||||
|     val navigator = rememberWebViewNavigator() | ||||
|  | ||||
|     Column { | ||||
|         SmallTopAppBar( | ||||
|             title = { | ||||
|                 AppBarTitle( | ||||
|                     title = state.pageTitle ?: initialTitle, | ||||
|                     subtitle = state.content.getCurrentUrl(), | ||||
|                 ) | ||||
|             }, | ||||
|             navigationIcon = { | ||||
|                 IconButton(onClick = onUp) { | ||||
|                     Icon( | ||||
|                         imageVector = Icons.Default.Close, | ||||
|                         contentDescription = stringResource(R.string.action_close), | ||||
|                     ) | ||||
|                 } | ||||
|             }, | ||||
|             actions = { | ||||
|                 AppBarActions( | ||||
|                     listOf( | ||||
|                         AppBar.Action( | ||||
|                             title = stringResource(R.string.action_webview_back), | ||||
|                             icon = Icons.Default.ArrowBack, | ||||
|                             onClick = { | ||||
|                                 if (navigator.canGoBack) { | ||||
|                                     navigator.navigateBack() | ||||
|                                 } | ||||
|                             }, | ||||
|                             isEnabled = navigator.canGoBack, | ||||
|                         ), | ||||
|                         AppBar.Action( | ||||
|                             title = stringResource(R.string.action_webview_forward), | ||||
|                             icon = Icons.Default.ArrowForward, | ||||
|                             onClick = { | ||||
|                                 if (navigator.canGoForward) { | ||||
|                                     navigator.navigateForward() | ||||
|                                 } | ||||
|                             }, | ||||
|                             isEnabled = navigator.canGoForward, | ||||
|                         ), | ||||
|                         AppBar.OverflowAction( | ||||
|                             title = stringResource(R.string.action_webview_refresh), | ||||
|                             onClick = { navigator.reload() }, | ||||
|                         ), | ||||
|                         AppBar.OverflowAction( | ||||
|                             title = stringResource(R.string.action_share), | ||||
|                             onClick = { onShare(state.content.getCurrentUrl()!!) }, | ||||
|                         ), | ||||
|                         AppBar.OverflowAction( | ||||
|                             title = stringResource(R.string.action_open_in_browser), | ||||
|                             onClick = { onOpenInBrowser(state.content.getCurrentUrl()!!) }, | ||||
|                         ), | ||||
|                         AppBar.OverflowAction( | ||||
|                             title = stringResource(R.string.pref_clear_cookies), | ||||
|                             onClick = { onClearCookies(state.content.getCurrentUrl()!!) }, | ||||
|                         ), | ||||
|                     ), | ||||
|                 ) | ||||
|             }, | ||||
|         ) | ||||
|  | ||||
|         Box(modifier = Modifier.weight(1f)) { | ||||
|             val loadingState = state.loadingState | ||||
|             if (loadingState is LoadingState.Loading) { | ||||
|                 LinearProgressIndicator( | ||||
|                     progress = loadingState.progress, | ||||
|                     modifier = Modifier.fillMaxWidth(), | ||||
|                 ) | ||||
|             } | ||||
|  | ||||
|             val webClient = remember { | ||||
|                 object : AccompanistWebViewClient() { | ||||
|                     override fun shouldOverrideUrlLoading( | ||||
|                         view: WebView?, | ||||
|                         request: WebResourceRequest?, | ||||
|                     ): Boolean { | ||||
|                         request?.let { | ||||
|                             view?.loadUrl(it.url.toString(), headers) | ||||
|                         } | ||||
|                         return super.shouldOverrideUrlLoading(view, request) | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             WebView( | ||||
|                 state = state, | ||||
|                 modifier = Modifier.fillMaxSize(), | ||||
|                 navigator = navigator, | ||||
|                 onCreated = { webView -> | ||||
|                     webView.setDefaultSettings() | ||||
|  | ||||
|                     // Debug mode (chrome://inspect/#devices) | ||||
|                     if (BuildConfig.DEBUG && 0 != context.applicationInfo.flags and ApplicationInfo.FLAG_DEBUGGABLE) { | ||||
|                         WebView.setWebContentsDebuggingEnabled(true) | ||||
|                     } | ||||
|  | ||||
|                     headers["User-Agent"]?.let { | ||||
|                         webView.settings.userAgentString = it | ||||
|                     } | ||||
|                 }, | ||||
|                 client = webClient, | ||||
|             ) | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -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" } | ||||
|     } | ||||
|   | ||||
| @@ -11,7 +11,7 @@ import logcat.LogPriority | ||||
| object WebViewUtil { | ||||
|     const val SPOOF_PACKAGE_NAME = "org.chromium.chrome" | ||||
|  | ||||
|     const val MINIMUM_WEBVIEW_VERSION = 95 | ||||
|     const val MINIMUM_WEBVIEW_VERSION = 98 | ||||
|  | ||||
|     fun supportsWebView(context: Context): Boolean { | ||||
|         try { | ||||
|   | ||||
| @@ -1,9 +0,0 @@ | ||||
| <vector xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     android:width="24dp" | ||||
|     android:height="24dp" | ||||
|     android:viewportWidth="24" | ||||
|     android:viewportHeight="24"> | ||||
|     <path | ||||
|         android:fillColor="@android:color/black" | ||||
|         android:pathData="M20,11H7.83l5.59,-5.59L12,4l-8,8 8,8 1.41,-1.41L7.83,13H20v-2z" /> | ||||
| </vector> | ||||
| @@ -1,40 +0,0 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     xmlns:app="http://schemas.android.com/apk/res-auto" | ||||
|     android:layout_width="match_parent" | ||||
|     android:layout_height="match_parent" | ||||
|     android:fitsSystemWindows="true" | ||||
|     android:orientation="vertical"> | ||||
|  | ||||
|     <com.google.android.material.appbar.AppBarLayout | ||||
|         android:layout_width="match_parent" | ||||
|         android:layout_height="wrap_content"> | ||||
|  | ||||
|         <com.google.android.material.appbar.MaterialToolbar | ||||
|             android:id="@+id/toolbar" | ||||
|             android:layout_width="match_parent" | ||||
|             android:layout_height="?attr/actionBarSize" | ||||
|             app:navigationIcon="@drawable/ic_close_24dp" /> | ||||
|  | ||||
|     </com.google.android.material.appbar.AppBarLayout> | ||||
|  | ||||
|     <eu.kanade.tachiyomi.widget.ThemedSwipeRefreshLayout | ||||
|         android:id="@id/swipe_refresh" | ||||
|         android:layout_width="match_parent" | ||||
|         android:layout_height="match_parent"> | ||||
|  | ||||
|         <WebView | ||||
|             android:id="@+id/webview" | ||||
|             android:layout_width="match_parent" | ||||
|             android:layout_height="match_parent"> | ||||
|  | ||||
|             <com.google.android.material.progressindicator.LinearProgressIndicator | ||||
|                 android:id="@+id/progress_bar" | ||||
|                 android:layout_width="match_parent" | ||||
|                 android:layout_height="wrap_content" /> | ||||
|  | ||||
|         </WebView> | ||||
|  | ||||
|     </eu.kanade.tachiyomi.widget.ThemedSwipeRefreshLayout> | ||||
|  | ||||
| </LinearLayout> | ||||
| @@ -1,39 +0,0 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <menu xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     xmlns:app="http://schemas.android.com/apk/res-auto"> | ||||
|  | ||||
|     <item | ||||
|         android:id="@+id/action_web_back" | ||||
|         android:icon="@drawable/ic_arrow_back_24dp" | ||||
|         android:title="@string/action_webview_back" | ||||
|         app:iconTint="?attr/colorOnSurface" | ||||
|         app:showAsAction="ifRoom" /> | ||||
|  | ||||
|     <item | ||||
|         android:id="@+id/action_web_forward" | ||||
|         android:icon="@drawable/ic_arrow_forward_24dp" | ||||
|         android:title="@string/action_webview_forward" | ||||
|         app:iconTint="?attr/colorOnSurface" | ||||
|         app:showAsAction="ifRoom" /> | ||||
|  | ||||
|     <item | ||||
|         android:id="@+id/action_web_refresh" | ||||
|         android:title="@string/action_webview_refresh" | ||||
|         app:showAsAction="never" /> | ||||
|  | ||||
|     <item | ||||
|         android:id="@+id/action_web_share" | ||||
|         android:title="@string/action_share" | ||||
|         app:showAsAction="never" /> | ||||
|  | ||||
|     <item | ||||
|         android:id="@+id/action_web_browser" | ||||
|         android:title="@string/action_open_in_browser" | ||||
|         app:showAsAction="never" /> | ||||
|  | ||||
|     <item | ||||
|         android:id="@+id/action_clear_cookies" | ||||
|         android:title="@string/pref_clear_cookies" | ||||
|         app:showAsAction="never" /> | ||||
|  | ||||
| </menu> | ||||
| @@ -121,6 +121,7 @@ | ||||
|     <string name="action_save">Save</string> | ||||
|     <string name="action_reset">Reset</string> | ||||
|     <string name="action_undo">Undo</string> | ||||
|     <string name="action_close">Close</string> | ||||
|     <string name="action_open_log">Open log</string> | ||||
|     <string name="action_show_errors">Tap to see details</string> | ||||
|     <string name="action_create">Create</string> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user