|
|
|
@ -30,8 +30,6 @@ import androidx.navigation.NavController
|
|
|
|
|
import androidx.navigation.fragment.findNavController
|
|
|
|
|
import androidx.preference.PreferenceManager
|
|
|
|
|
import com.google.android.material.snackbar.Snackbar
|
|
|
|
|
import kotlinx.android.synthetic.main.fragment_browser.*
|
|
|
|
|
import kotlinx.android.synthetic.main.fragment_browser.view.*
|
|
|
|
|
import kotlinx.coroutines.Dispatchers.IO
|
|
|
|
|
import kotlinx.coroutines.Dispatchers.Main
|
|
|
|
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
|
|
|
@ -134,6 +132,7 @@ import mozilla.components.support.ktx.android.view.enterToImmersiveMode
|
|
|
|
|
import mozilla.components.support.ktx.kotlin.getOrigin
|
|
|
|
|
import org.mozilla.fenix.components.toolbar.interactor.BrowserToolbarInteractor
|
|
|
|
|
import org.mozilla.fenix.components.toolbar.interactor.DefaultBrowserToolbarInteractor
|
|
|
|
|
import org.mozilla.fenix.databinding.FragmentBrowserBinding
|
|
|
|
|
import org.mozilla.fenix.ext.secure
|
|
|
|
|
import org.mozilla.fenix.settings.biometric.BiometricPromptFeature
|
|
|
|
|
import mozilla.components.feature.session.behavior.ToolbarPosition as MozacToolbarPosition
|
|
|
|
@ -152,6 +151,9 @@ abstract class BaseBrowserFragment :
|
|
|
|
|
OnBackLongPressedListener,
|
|
|
|
|
AccessibilityManager.AccessibilityStateChangeListener {
|
|
|
|
|
|
|
|
|
|
private var _binding: FragmentBrowserBinding? = null
|
|
|
|
|
protected val binding get() = _binding!!
|
|
|
|
|
|
|
|
|
|
private lateinit var browserFragmentStore: BrowserFragmentStore
|
|
|
|
|
private lateinit var browserAnimator: BrowserAnimator
|
|
|
|
|
|
|
|
|
@ -221,7 +223,7 @@ abstract class BaseBrowserFragment :
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
val view = inflater.inflate(R.layout.fragment_browser, container, false)
|
|
|
|
|
_binding = FragmentBrowserBinding.inflate(inflater, container, false)
|
|
|
|
|
|
|
|
|
|
val activity = activity as HomeActivity
|
|
|
|
|
activity.themeManager.applyStatusBarTheme(activity)
|
|
|
|
@ -232,7 +234,7 @@ abstract class BaseBrowserFragment :
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return view
|
|
|
|
|
return binding.root
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
final override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
|
|
|
@ -277,8 +279,8 @@ abstract class BaseBrowserFragment :
|
|
|
|
|
|
|
|
|
|
browserAnimator = BrowserAnimator(
|
|
|
|
|
fragment = WeakReference(this),
|
|
|
|
|
engineView = WeakReference(engineView),
|
|
|
|
|
swipeRefresh = WeakReference(swipeRefresh),
|
|
|
|
|
engineView = WeakReference(binding.engineView),
|
|
|
|
|
swipeRefresh = WeakReference(binding.swipeRefresh),
|
|
|
|
|
viewLifecycleScope = WeakReference(viewLifecycleOwner.lifecycleScope)
|
|
|
|
|
).apply {
|
|
|
|
|
beginAnimateInIfNecessary()
|
|
|
|
@ -291,7 +293,7 @@ abstract class BaseBrowserFragment :
|
|
|
|
|
|
|
|
|
|
val readerMenuController = DefaultReaderModeController(
|
|
|
|
|
readerViewFeature,
|
|
|
|
|
view.readerViewControlsBar,
|
|
|
|
|
binding.readerViewControlsBar,
|
|
|
|
|
isPrivate = activity.browsingModeManager.mode.isPrivate,
|
|
|
|
|
onReaderModeChanged = { activity.finishActionMode() }
|
|
|
|
|
)
|
|
|
|
@ -302,7 +304,7 @@ abstract class BaseBrowserFragment :
|
|
|
|
|
navController = findNavController(),
|
|
|
|
|
metrics = requireComponents.analytics.metrics,
|
|
|
|
|
readerModeController = readerMenuController,
|
|
|
|
|
engineView = engineView,
|
|
|
|
|
engineView = binding.engineView,
|
|
|
|
|
homeViewModel = homeViewModel,
|
|
|
|
|
customTabSessionId = customTabSessionId,
|
|
|
|
|
onTabCounterClicked = {
|
|
|
|
@ -322,7 +324,7 @@ abstract class BaseBrowserFragment :
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
viewLifecycleOwner.lifecycleScope.allowUndo(
|
|
|
|
|
requireView().browserLayout,
|
|
|
|
|
binding.browserLayout,
|
|
|
|
|
snackbarMessage,
|
|
|
|
|
requireContext().getString(R.string.snackbar_deleted_undo),
|
|
|
|
|
{
|
|
|
|
@ -342,7 +344,7 @@ abstract class BaseBrowserFragment :
|
|
|
|
|
readerModeController = readerMenuController,
|
|
|
|
|
sessionFeature = sessionFeature,
|
|
|
|
|
findInPageLauncher = { findInPageIntegration.withFeature { it.launch() } },
|
|
|
|
|
swipeRefresh = swipeRefresh,
|
|
|
|
|
swipeRefresh = binding.swipeRefresh,
|
|
|
|
|
browserAnimator = browserAnimator,
|
|
|
|
|
customTabSessionId = customTabSessionId,
|
|
|
|
|
openInFenixIntent = openInFenixIntent,
|
|
|
|
@ -363,7 +365,7 @@ abstract class BaseBrowserFragment :
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
_browserToolbarView = BrowserToolbarView(
|
|
|
|
|
container = view.browserLayout,
|
|
|
|
|
container = binding.browserLayout,
|
|
|
|
|
toolbarPosition = context.settings().toolbarPosition,
|
|
|
|
|
interactor = browserToolbarInteractor,
|
|
|
|
|
customTabSession = customTabSessionId?.let { store.state.findCustomTab(it) },
|
|
|
|
@ -380,8 +382,8 @@ abstract class BaseBrowserFragment :
|
|
|
|
|
feature = FindInPageIntegration(
|
|
|
|
|
store = store,
|
|
|
|
|
sessionId = customTabSessionId,
|
|
|
|
|
stub = view.stubFindInPage,
|
|
|
|
|
engineView = engineView,
|
|
|
|
|
stub = binding.stubFindInPage,
|
|
|
|
|
engineView = binding.engineView,
|
|
|
|
|
toolbarInfo = FindInPageIntegration.ToolbarInfo(
|
|
|
|
|
browserToolbarView.view,
|
|
|
|
|
!context.settings().shouldUseFixedTopToolbar && context.settings().isDynamicToolbarEnabled,
|
|
|
|
@ -400,8 +402,8 @@ abstract class BaseBrowserFragment :
|
|
|
|
|
feature = ContextMenuFeature(
|
|
|
|
|
fragmentManager = parentFragmentManager,
|
|
|
|
|
store = store,
|
|
|
|
|
candidates = getContextMenuCandidates(context, view.browserLayout),
|
|
|
|
|
engineView = view.engineView,
|
|
|
|
|
candidates = getContextMenuCandidates(context, binding.browserLayout),
|
|
|
|
|
engineView = binding.engineView,
|
|
|
|
|
useCases = context.components.useCases.contextMenuUseCases,
|
|
|
|
|
tabId = customTabSessionId
|
|
|
|
|
),
|
|
|
|
@ -483,15 +485,15 @@ abstract class BaseBrowserFragment :
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
val dynamicDownloadDialog = DynamicDownloadDialog(
|
|
|
|
|
container = view.browserLayout,
|
|
|
|
|
container = binding.browserLayout,
|
|
|
|
|
downloadState = downloadState,
|
|
|
|
|
metrics = requireComponents.analytics.metrics,
|
|
|
|
|
didFail = downloadJobStatus == DownloadState.Status.FAILED,
|
|
|
|
|
tryAgain = downloadFeature::tryAgain,
|
|
|
|
|
onCannotOpenFile = {
|
|
|
|
|
showCannotOpenFileError(view.browserLayout, context, it)
|
|
|
|
|
showCannotOpenFileError(binding.browserLayout, context, it)
|
|
|
|
|
},
|
|
|
|
|
view = view.viewDynamicDownloadDialog,
|
|
|
|
|
view = binding.viewDynamicDownloadDialog.root,
|
|
|
|
|
toolbarHeight = toolbarHeight,
|
|
|
|
|
onDismiss = { sharedViewModel.downloadDialogState.remove(downloadState.sessionId) }
|
|
|
|
|
)
|
|
|
|
@ -503,7 +505,7 @@ abstract class BaseBrowserFragment :
|
|
|
|
|
|
|
|
|
|
resumeDownloadDialogState(
|
|
|
|
|
getCurrentTab()?.id,
|
|
|
|
|
store, view, context, toolbarHeight
|
|
|
|
|
store, context, toolbarHeight
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
shareDownloadsFeature.set(
|
|
|
|
@ -587,7 +589,7 @@ abstract class BaseBrowserFragment :
|
|
|
|
|
onNeedToRequestPermissions = { permissions ->
|
|
|
|
|
requestPermissions(permissions, REQUEST_CODE_PROMPT_PERMISSIONS)
|
|
|
|
|
},
|
|
|
|
|
loginPickerView = loginSelectBar,
|
|
|
|
|
loginPickerView = binding.loginSelectBar,
|
|
|
|
|
onManageLogins = {
|
|
|
|
|
browserAnimator.captureEngineViewAndDrawStatically {
|
|
|
|
|
val directions =
|
|
|
|
@ -595,7 +597,7 @@ abstract class BaseBrowserFragment :
|
|
|
|
|
findNavController().navigate(directions)
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
creditCardPickerView = creditCardSelectBar,
|
|
|
|
|
creditCardPickerView = binding.creditCardSelectBar,
|
|
|
|
|
onManageCreditCards = {
|
|
|
|
|
val directions =
|
|
|
|
|
NavGraphDirections.actionGlobalCreditCardsSettingFragment()
|
|
|
|
@ -613,7 +615,7 @@ abstract class BaseBrowserFragment :
|
|
|
|
|
feature = SessionFeature(
|
|
|
|
|
requireComponents.core.store,
|
|
|
|
|
requireComponents.useCases.sessionUseCases.goBack,
|
|
|
|
|
view.engineView,
|
|
|
|
|
binding.engineView,
|
|
|
|
|
customTabSessionId
|
|
|
|
|
),
|
|
|
|
|
owner = this,
|
|
|
|
@ -719,17 +721,17 @@ abstract class BaseBrowserFragment :
|
|
|
|
|
.collect { tab -> pipModeChanged(tab) }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
view.swipeRefresh.isEnabled = shouldPullToRefreshBeEnabled(false)
|
|
|
|
|
binding.swipeRefresh.isEnabled = shouldPullToRefreshBeEnabled(false)
|
|
|
|
|
|
|
|
|
|
if (view.swipeRefresh.isEnabled) {
|
|
|
|
|
if (binding.swipeRefresh.isEnabled) {
|
|
|
|
|
val primaryTextColor =
|
|
|
|
|
ThemeManager.resolveAttribute(R.attr.primaryText, context)
|
|
|
|
|
view.swipeRefresh.setColorSchemeColors(primaryTextColor)
|
|
|
|
|
binding.swipeRefresh.setColorSchemeColors(primaryTextColor)
|
|
|
|
|
swipeRefreshFeature.set(
|
|
|
|
|
feature = SwipeRefreshFeature(
|
|
|
|
|
requireComponents.core.store,
|
|
|
|
|
context.components.useCases.sessionUseCases.reload,
|
|
|
|
|
view.swipeRefresh,
|
|
|
|
|
binding.swipeRefresh,
|
|
|
|
|
customTabSessionId
|
|
|
|
|
),
|
|
|
|
|
owner = this,
|
|
|
|
@ -859,7 +861,6 @@ abstract class BaseBrowserFragment :
|
|
|
|
|
internal fun resumeDownloadDialogState(
|
|
|
|
|
sessionId: String?,
|
|
|
|
|
store: BrowserStore,
|
|
|
|
|
view: View,
|
|
|
|
|
context: Context,
|
|
|
|
|
toolbarHeight: Int
|
|
|
|
|
) {
|
|
|
|
@ -867,7 +868,7 @@ abstract class BaseBrowserFragment :
|
|
|
|
|
sharedViewModel.downloadDialogState[sessionId]
|
|
|
|
|
|
|
|
|
|
if (savedDownloadState == null || sessionId == null) {
|
|
|
|
|
view.viewDynamicDownloadDialog.visibility = View.GONE
|
|
|
|
|
binding.viewDynamicDownloadDialog.root.visibility = View.GONE
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -885,15 +886,15 @@ abstract class BaseBrowserFragment :
|
|
|
|
|
{ sharedViewModel.downloadDialogState.remove(sessionId) }
|
|
|
|
|
|
|
|
|
|
DynamicDownloadDialog(
|
|
|
|
|
container = view.browserLayout,
|
|
|
|
|
container = binding.browserLayout,
|
|
|
|
|
downloadState = savedDownloadState.first,
|
|
|
|
|
metrics = requireComponents.analytics.metrics,
|
|
|
|
|
didFail = savedDownloadState.second,
|
|
|
|
|
tryAgain = onTryAgain,
|
|
|
|
|
onCannotOpenFile = {
|
|
|
|
|
showCannotOpenFileError(view.browserLayout, context, it)
|
|
|
|
|
showCannotOpenFileError(binding.browserLayout, context, it)
|
|
|
|
|
},
|
|
|
|
|
view = view.viewDynamicDownloadDialog,
|
|
|
|
|
view = binding.viewDynamicDownloadDialog.root,
|
|
|
|
|
toolbarHeight = toolbarHeight,
|
|
|
|
|
onDismiss = onDismiss
|
|
|
|
|
).show()
|
|
|
|
@ -1012,13 +1013,13 @@ abstract class BaseBrowserFragment :
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (browserInitialized) {
|
|
|
|
|
view?.let { view ->
|
|
|
|
|
view?.let {
|
|
|
|
|
fullScreenChanged(false)
|
|
|
|
|
browserToolbarView.expand()
|
|
|
|
|
|
|
|
|
|
val toolbarHeight = resources.getDimensionPixelSize(R.dimen.browser_toolbar_height)
|
|
|
|
|
val context = requireContext()
|
|
|
|
|
resumeDownloadDialogState(selectedTab.id, context.components.core.store, view, context, toolbarHeight)
|
|
|
|
|
resumeDownloadDialogState(selectedTab.id, context.components.core.store, context, toolbarHeight)
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
view?.let { view -> initializeUI(view) }
|
|
|
|
@ -1158,7 +1159,7 @@ abstract class BaseBrowserFragment :
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Returns the layout [android.view.Gravity] for the quick settings and ETP dialog.
|
|
|
|
|
* Returns the layout [android.binding.Gravity] for the quick settings and ETP dialog.
|
|
|
|
|
*/
|
|
|
|
|
protected fun getAppropriateLayoutGravity(): Int =
|
|
|
|
|
requireComponents.settings.toolbarPosition.androidGravity
|
|
|
|
@ -1230,9 +1231,9 @@ abstract class BaseBrowserFragment :
|
|
|
|
|
withContext(Main) {
|
|
|
|
|
requireComponents.analytics.metrics.track(Event.AddBookmark)
|
|
|
|
|
|
|
|
|
|
view?.let { view ->
|
|
|
|
|
view?.let {
|
|
|
|
|
FenixSnackbar.make(
|
|
|
|
|
view = view.browserLayout,
|
|
|
|
|
view = binding.browserLayout,
|
|
|
|
|
duration = FenixSnackbar.LENGTH_LONG,
|
|
|
|
|
isDisplayedWithBrowserToolbar = true
|
|
|
|
|
)
|
|
|
|
@ -1283,7 +1284,7 @@ abstract class BaseBrowserFragment :
|
|
|
|
|
// Close find in page bar if opened
|
|
|
|
|
findInPageIntegration.onBackPressed()
|
|
|
|
|
FenixSnackbar.make(
|
|
|
|
|
view = requireView().browserLayout,
|
|
|
|
|
view = binding.browserLayout,
|
|
|
|
|
duration = Snackbar.LENGTH_SHORT,
|
|
|
|
|
isDisplayedWithBrowserToolbar = false
|
|
|
|
|
)
|
|
|
|
@ -1292,14 +1293,14 @@ abstract class BaseBrowserFragment :
|
|
|
|
|
activity?.enterToImmersiveMode()
|
|
|
|
|
browserToolbarView.collapse()
|
|
|
|
|
browserToolbarView.view.isVisible = false
|
|
|
|
|
val browserEngine = swipeRefresh.layoutParams as CoordinatorLayout.LayoutParams
|
|
|
|
|
val browserEngine = binding.swipeRefresh.layoutParams as CoordinatorLayout.LayoutParams
|
|
|
|
|
browserEngine.bottomMargin = 0
|
|
|
|
|
browserEngine.topMargin = 0
|
|
|
|
|
swipeRefresh.translationY = 0f
|
|
|
|
|
binding.swipeRefresh.translationY = 0f
|
|
|
|
|
|
|
|
|
|
engineView.setDynamicToolbarMaxHeight(0)
|
|
|
|
|
binding.engineView.setDynamicToolbarMaxHeight(0)
|
|
|
|
|
// Without this, fullscreen has a margin at the top.
|
|
|
|
|
engineView.setVerticalClipping(0)
|
|
|
|
|
binding.engineView.setVerticalClipping(0)
|
|
|
|
|
|
|
|
|
|
requireComponents.analytics.metrics.track(Event.MediaFullscreenState)
|
|
|
|
|
} else {
|
|
|
|
@ -1315,7 +1316,7 @@ abstract class BaseBrowserFragment :
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
activity?.swipeRefresh?.isEnabled = shouldPullToRefreshBeEnabled(inFullScreen)
|
|
|
|
|
binding.swipeRefresh.isEnabled = shouldPullToRefreshBeEnabled(inFullScreen)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
@ -1333,6 +1334,7 @@ abstract class BaseBrowserFragment :
|
|
|
|
|
requireContext().accessibilityManager.removeAccessibilityStateChangeListener(this)
|
|
|
|
|
_browserToolbarView = null
|
|
|
|
|
_browserToolbarInteractor = null
|
|
|
|
|
_binding = null
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
override fun onAttach(context: Context) {
|
|
|
|
@ -1409,13 +1411,13 @@ abstract class BaseBrowserFragment :
|
|
|
|
|
* Convenience method for replacing EngineView (id/engineView) in unit tests.
|
|
|
|
|
*/
|
|
|
|
|
@VisibleForTesting
|
|
|
|
|
internal fun getEngineView() = engineView
|
|
|
|
|
internal fun getEngineView() = binding.engineView
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Convenience method for replacing SwipeRefreshLayout (id/swipeRefresh) in unit tests.
|
|
|
|
|
*/
|
|
|
|
|
@VisibleForTesting
|
|
|
|
|
internal fun getSwipeRefreshLayout() = swipeRefresh
|
|
|
|
|
internal fun getSwipeRefreshLayout() = binding.swipeRefresh
|
|
|
|
|
|
|
|
|
|
@VisibleForTesting
|
|
|
|
|
internal fun shouldShowCompletedDownloadDialog(
|
|
|
|
|