@@ -203,6 +203,11 @@ class BrowserTabFragment : Fragment(), FindListener, CoroutineScope {
203203
204204 private var webView: WebView ? = null
205205
206+ private val errorSnackbar: Snackbar by lazy {
207+ Snackbar .make(browserLayout, R .string.crashedWebViewErrorMessage, Snackbar .LENGTH_INDEFINITE )
208+ .setBehavior(NonDismissibleBehavior ())
209+ }
210+
206211 private val findInPageTextWatcher = object : TextChangedWatcher () {
207212 override fun afterTextChanged (editable : Editable ) {
208213 viewModel.userFindingInPage(findInPageInput.text.toString())
@@ -309,7 +314,7 @@ class BrowserTabFragment : Fragment(), FindListener, CoroutineScope {
309314 popupMenu.apply {
310315 onMenuItemClicked(view.forwardPopupMenuItem) { viewModel.onUserPressedForward() }
311316 onMenuItemClicked(view.backPopupMenuItem) { activity?.onBackPressed() }
312- onMenuItemClicked(view.refreshPopupMenuItem) { refresh () }
317+ onMenuItemClicked(view.refreshPopupMenuItem) { viewModel.onRefreshRequested () }
313318 onMenuItemClicked(view.newTabPopupMenuItem) { viewModel.userRequestedOpeningNewTab() }
314319 onMenuItemClicked(view.bookmarksPopupMenuItem) { browserActivity?.launchBookmarks() }
315320 onMenuItemClicked(view.addBookmarksPopupMenuItem) { launch { viewModel.onBookmarkAddRequested() } }
@@ -374,6 +379,8 @@ class BrowserTabFragment : Fragment(), FindListener, CoroutineScope {
374379 }
375380
376381 private fun showHome () {
382+ errorSnackbar.dismiss()
383+ newTabLayout.show()
377384 showKeyboardImmediately()
378385 appBarLayout.setExpanded(true )
379386 webView?.onPause()
@@ -383,6 +390,7 @@ class BrowserTabFragment : Fragment(), FindListener, CoroutineScope {
383390 }
384391
385392 private fun showBrowser () {
393+ newTabLayout.gone()
386394 webView?.show()
387395 webView?.onResume()
388396 omnibarScrolling.enableOmnibarScrolling(toolbarContainer)
@@ -398,13 +406,17 @@ class BrowserTabFragment : Fragment(), FindListener, CoroutineScope {
398406 webView?.loadUrl(url)
399407 }
400408
409+ fun onRefreshRequested () {
410+ viewModel.onRefreshRequested()
411+ }
412+
401413 fun refresh () {
402414 webView?.reload()
403415 }
404416
405417 private fun processCommand (it : Command ? ) {
406418 when (it) {
407- Command .Refresh -> refresh()
419+ is Command .Refresh -> refresh()
408420 is Command .OpenInNewTab -> {
409421 browserActivity?.openInNewTab(it.query)
410422 }
@@ -419,10 +431,10 @@ class BrowserTabFragment : Fragment(), FindListener, CoroutineScope {
419431 is Command .NavigateBack -> {
420432 webView?.goBackOrForward(- it.steps)
421433 }
422- Command .NavigateForward -> {
434+ is Command .NavigateForward -> {
423435 webView?.goForward()
424436 }
425- Command .ResetHistory -> {
437+ is Command .ResetHistory -> {
426438 resetWebView()
427439 }
428440 is Command .DialNumber -> {
@@ -439,10 +451,10 @@ class BrowserTabFragment : Fragment(), FindListener, CoroutineScope {
439451 val intent = Intent (Intent .ACTION_SENDTO , Uri .parse(" smsto:${it.telephoneNumber} " ))
440452 openExternalDialog(intent)
441453 }
442- Command .ShowKeyboard -> {
454+ is Command .ShowKeyboard -> {
443455 showKeyboard()
444456 }
445- Command .HideKeyboard -> {
457+ is Command .HideKeyboard -> {
446458 hideKeyboard()
447459 }
448460 is Command .BrokenSiteFeedback -> {
@@ -458,7 +470,7 @@ class BrowserTabFragment : Fragment(), FindListener, CoroutineScope {
458470 }
459471 is Command .DownloadImage -> requestImageDownload(it.url)
460472 is Command .FindInPageCommand -> webView?.findAllAsync(it.searchTerm)
461- Command .DismissFindInPage -> webView?.findAllAsync(null )
473+ is Command .DismissFindInPage -> webView?.findAllAsync(null )
462474 is Command .ShareLink -> launchSharePageChooser(it.url)
463475 is Command .CopyLink -> {
464476 clipboardManager.primaryClip = ClipData .newPlainText(null , it.url)
@@ -481,6 +493,14 @@ class BrowserTabFragment : Fragment(), FindListener, CoroutineScope {
481493 is Command .SaveCredentials -> saveBasicAuthCredentials(it.request, it.credentials)
482494 is Command .GenerateWebViewPreviewImage -> generateWebViewPreviewImage()
483495 is Command .LaunchTabSwitcher -> launchTabSwitcher()
496+ is Command .ShowErrorWithAction -> showErrorSnackbar(it)
497+ }
498+ }
499+
500+ private fun showErrorSnackbar (command : Command .ShowErrorWithAction ) {
501+ // Snackbar is global and it should appear only the foreground fragment
502+ if (! errorSnackbar.view.isAttachedToWindow && isVisible) {
503+ errorSnackbar.setAction(R .string.crashedWebViewErrorAction) { command.action() }.show()
484504 }
485505 }
486506
@@ -1124,13 +1144,23 @@ class BrowserTabFragment : Fragment(), FindListener, CoroutineScope {
11241144 }
11251145
11261146 fun renderGlobalViewState (viewState : GlobalLayoutViewState ) {
1147+ if (lastSeenGlobalViewState is GlobalLayoutViewState .Invalidated &&
1148+ viewState is GlobalLayoutViewState .Browser ) {
1149+ throw IllegalStateException (" Invalid state transition" )
1150+ }
1151+
11271152 renderIfChanged(viewState, lastSeenGlobalViewState) {
11281153 lastSeenGlobalViewState = viewState
11291154
1130- if (viewState.isNewTabState) {
1131- browserLayout.hide()
1132- } else {
1133- browserLayout.show()
1155+ when (viewState) {
1156+ is GlobalLayoutViewState .Browser -> {
1157+ if (viewState.isNewTabState) {
1158+ browserLayout.hide()
1159+ } else {
1160+ browserLayout.show()
1161+ }
1162+ }
1163+ is GlobalLayoutViewState .Invalidated -> destroyWebView()
11341164 }
11351165 }
11361166 }
@@ -1174,6 +1204,8 @@ class BrowserTabFragment : Fragment(), FindListener, CoroutineScope {
11741204 newTabPopupMenuItem.isEnabled = browserShowing
11751205 addBookmarksPopupMenuItem?.isEnabled = viewState.canAddBookmarks
11761206 sharePageMenuItem?.isEnabled = viewState.canSharePage
1207+ brokenSitePopupMenuItem?.isEnabled = viewState.canReportSite
1208+ requestDesktopSiteCheckMenuItem?.isEnabled = viewState.canChangeBrowsingMode
11771209
11781210 addToHome?.let {
11791211 it.visibility = if (viewState.addToHomeVisible) VISIBLE else GONE
0 commit comments