mirror of
https://github.com/fork-maintainers/iceraven-browser
synced 2024-11-03 23:15:31 +00:00
[fenix] Refactor ExternalAppBrowserActivity and ExternalAppBrowserFragment to not use Session(Manager).
This commit is contained in:
parent
a1246d05f8
commit
086174a280
@ -184,6 +184,7 @@ abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler,
|
|||||||
protected var webAppToolbarShouldBeVisible = true
|
protected var webAppToolbarShouldBeVisible = true
|
||||||
|
|
||||||
private val sharedViewModel: SharedViewModel by activityViewModels()
|
private val sharedViewModel: SharedViewModel by activityViewModels()
|
||||||
|
private val homeViewModel: HomeScreenViewModel by activityViewModels()
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
internal val onboarding by lazy { FenixOnboarding(requireContext()) }
|
internal val onboarding by lazy { FenixOnboarding(requireContext()) }
|
||||||
@ -220,7 +221,7 @@ abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler,
|
|||||||
}
|
}
|
||||||
|
|
||||||
final override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
final override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
browserInitialized = initializeUI(view) != null
|
initializeUI(view)
|
||||||
|
|
||||||
if (customTabSessionId == null) {
|
if (customTabSessionId == null) {
|
||||||
// We currently only need this observer to navigate to home
|
// We currently only need this observer to navigate to home
|
||||||
@ -238,12 +239,19 @@ abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler,
|
|||||||
requireContext().accessibilityManager.addAccessibilityStateChangeListener(this)
|
requireContext().accessibilityManager.addAccessibilityStateChangeListener(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
private val homeViewModel: HomeScreenViewModel by activityViewModels()
|
private fun initializeUI(view: View) {
|
||||||
|
val tab = getCurrentTab()
|
||||||
|
browserInitialized = if (tab != null) {
|
||||||
|
initializeUI(view, tab)
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Suppress("ComplexMethod", "LongMethod")
|
@Suppress("ComplexMethod", "LongMethod")
|
||||||
@CallSuper
|
@CallSuper
|
||||||
@VisibleForTesting
|
internal open fun initializeUI(view: View, tab: SessionState) {
|
||||||
internal open fun initializeUI(view: View): Session? {
|
|
||||||
val context = requireContext()
|
val context = requireContext()
|
||||||
val sessionManager = context.components.core.sessionManager
|
val sessionManager = context.components.core.sessionManager
|
||||||
val store = context.components.core.store
|
val store = context.components.core.store
|
||||||
@ -260,456 +268,454 @@ abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler,
|
|||||||
beginAnimateInIfNecessary()
|
beginAnimateInIfNecessary()
|
||||||
}
|
}
|
||||||
|
|
||||||
return getSessionById()?.also { _ ->
|
val openInFenixIntent = Intent(context, IntentReceiverActivity::class.java).apply {
|
||||||
val openInFenixIntent = Intent(context, IntentReceiverActivity::class.java).apply {
|
action = Intent.ACTION_VIEW
|
||||||
action = Intent.ACTION_VIEW
|
putExtra(HomeActivity.OPEN_TO_BROWSER, true)
|
||||||
putExtra(HomeActivity.OPEN_TO_BROWSER, true)
|
}
|
||||||
}
|
|
||||||
|
|
||||||
val readerMenuController = DefaultReaderModeController(
|
val readerMenuController = DefaultReaderModeController(
|
||||||
readerViewFeature,
|
readerViewFeature,
|
||||||
view.readerViewControlsBar,
|
view.readerViewControlsBar,
|
||||||
isPrivate = activity.browsingModeManager.mode.isPrivate
|
isPrivate = activity.browsingModeManager.mode.isPrivate
|
||||||
)
|
)
|
||||||
val browserToolbarController = DefaultBrowserToolbarController(
|
val browserToolbarController = DefaultBrowserToolbarController(
|
||||||
store = store,
|
store = store,
|
||||||
activity = activity,
|
activity = activity,
|
||||||
navController = findNavController(),
|
navController = findNavController(),
|
||||||
metrics = requireComponents.analytics.metrics,
|
metrics = requireComponents.analytics.metrics,
|
||||||
readerModeController = readerMenuController,
|
readerModeController = readerMenuController,
|
||||||
sessionManager = requireComponents.core.sessionManager,
|
sessionManager = requireComponents.core.sessionManager,
|
||||||
engineView = engineView,
|
engineView = engineView,
|
||||||
homeViewModel = homeViewModel,
|
homeViewModel = homeViewModel,
|
||||||
customTabSession = customTabSessionId?.let { sessionManager.findSessionById(it) },
|
customTabSession = customTabSessionId?.let { sessionManager.findSessionById(it) },
|
||||||
onTabCounterClicked = {
|
onTabCounterClicked = {
|
||||||
thumbnailsFeature.get()?.requestScreenshot()
|
thumbnailsFeature.get()?.requestScreenshot()
|
||||||
findNavController().nav(
|
findNavController().nav(
|
||||||
R.id.browserFragment,
|
R.id.browserFragment,
|
||||||
BrowserFragmentDirections.actionGlobalTabTrayDialogFragment()
|
BrowserFragmentDirections.actionGlobalTabTrayDialogFragment()
|
||||||
)
|
|
||||||
},
|
|
||||||
onCloseTab = { closedSession ->
|
|
||||||
val tab = store.state.findTab(closedSession.id) ?: return@DefaultBrowserToolbarController
|
|
||||||
|
|
||||||
val snackbarMessage = if (tab.content.private) {
|
|
||||||
requireContext().getString(R.string.snackbar_private_tab_closed)
|
|
||||||
} else {
|
|
||||||
requireContext().getString(R.string.snackbar_tab_closed)
|
|
||||||
}
|
|
||||||
|
|
||||||
viewLifecycleOwner.lifecycleScope.allowUndo(
|
|
||||||
requireView().browserLayout,
|
|
||||||
snackbarMessage,
|
|
||||||
requireContext().getString(R.string.snackbar_deleted_undo),
|
|
||||||
{
|
|
||||||
requireComponents.useCases.tabsUseCases.undo.invoke()
|
|
||||||
},
|
|
||||||
paddedForBottomToolbar = true,
|
|
||||||
operation = { }
|
|
||||||
)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
val browserToolbarMenuController = DefaultBrowserToolbarMenuController(
|
|
||||||
activity = activity,
|
|
||||||
navController = findNavController(),
|
|
||||||
metrics = requireComponents.analytics.metrics,
|
|
||||||
settings = context.settings(),
|
|
||||||
readerModeController = readerMenuController,
|
|
||||||
sessionManager = requireComponents.core.sessionManager,
|
|
||||||
sessionFeature = sessionFeature,
|
|
||||||
findInPageLauncher = { findInPageIntegration.withFeature { it.launch() } },
|
|
||||||
swipeRefresh = swipeRefresh,
|
|
||||||
browserAnimator = browserAnimator,
|
|
||||||
customTabSession = customTabSessionId?.let { sessionManager.findSessionById(it) },
|
|
||||||
openInFenixIntent = openInFenixIntent,
|
|
||||||
bookmarkTapped = { url: String, title: String ->
|
|
||||||
viewLifecycleOwner.lifecycleScope.launch {
|
|
||||||
bookmarkTapped(url, title)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
scope = viewLifecycleOwner.lifecycleScope,
|
|
||||||
tabCollectionStorage = requireComponents.core.tabCollectionStorage,
|
|
||||||
topSitesStorage = requireComponents.core.topSitesStorage,
|
|
||||||
browserStore = store
|
|
||||||
)
|
|
||||||
|
|
||||||
_browserInteractor = BrowserInteractor(
|
|
||||||
browserToolbarController,
|
|
||||||
browserToolbarMenuController
|
|
||||||
)
|
|
||||||
|
|
||||||
_browserToolbarView = BrowserToolbarView(
|
|
||||||
container = view.browserLayout,
|
|
||||||
toolbarPosition = context.settings().toolbarPosition,
|
|
||||||
interactor = browserInteractor,
|
|
||||||
customTabSession = customTabSessionId?.let { sessionManager.findSessionById(it) },
|
|
||||||
lifecycleOwner = viewLifecycleOwner
|
|
||||||
)
|
|
||||||
|
|
||||||
toolbarIntegration.set(
|
|
||||||
feature = browserToolbarView.toolbarIntegration,
|
|
||||||
owner = this,
|
|
||||||
view = view
|
|
||||||
)
|
|
||||||
|
|
||||||
findInPageIntegration.set(
|
|
||||||
feature = FindInPageIntegration(
|
|
||||||
store = store,
|
|
||||||
sessionId = customTabSessionId,
|
|
||||||
stub = view.stubFindInPage,
|
|
||||||
engineView = view.engineView,
|
|
||||||
toolbar = browserToolbarView.view
|
|
||||||
),
|
|
||||||
owner = this,
|
|
||||||
view = view
|
|
||||||
)
|
|
||||||
|
|
||||||
browserToolbarView.view.display.setOnSiteSecurityClickedListener {
|
|
||||||
showQuickSettingsDialog()
|
|
||||||
}
|
|
||||||
|
|
||||||
browserToolbarView.view.display.setOnTrackingProtectionClickedListener {
|
|
||||||
context.metrics.track(Event.TrackingProtectionIconPressed)
|
|
||||||
showTrackingProtectionPanel()
|
|
||||||
}
|
|
||||||
|
|
||||||
contextMenuFeature.set(
|
|
||||||
feature = ContextMenuFeature(
|
|
||||||
fragmentManager = parentFragmentManager,
|
|
||||||
store = store,
|
|
||||||
candidates = getContextMenuCandidates(context, view.browserLayout),
|
|
||||||
engineView = view.engineView,
|
|
||||||
useCases = context.components.useCases.contextMenuUseCases,
|
|
||||||
tabId = customTabSessionId
|
|
||||||
),
|
|
||||||
owner = this,
|
|
||||||
view = view
|
|
||||||
)
|
|
||||||
|
|
||||||
val allowScreenshotsInPrivateMode = context.settings().allowScreenshotsInPrivateMode
|
|
||||||
secureWindowFeature.set(
|
|
||||||
feature = SecureWindowFeature(
|
|
||||||
window = requireActivity().window,
|
|
||||||
store = store,
|
|
||||||
customTabId = customTabSessionId,
|
|
||||||
isSecure = { !allowScreenshotsInPrivateMode && it.content.private }
|
|
||||||
),
|
|
||||||
owner = this,
|
|
||||||
view = view
|
|
||||||
)
|
|
||||||
|
|
||||||
if (newMediaSessionApi) {
|
|
||||||
fullScreenMediaSessionFeature.set(
|
|
||||||
feature = MediaSessionFullscreenFeature(
|
|
||||||
requireActivity(),
|
|
||||||
context.components.core.store
|
|
||||||
),
|
|
||||||
owner = this,
|
|
||||||
view = view
|
|
||||||
)
|
)
|
||||||
} else {
|
},
|
||||||
fullScreenMediaFeature.set(
|
onCloseTab = { closedSession ->
|
||||||
feature = MediaFullscreenOrientationFeature(
|
val closedTab = store.state.findTab(closedSession.id) ?: return@DefaultBrowserToolbarController
|
||||||
requireActivity(),
|
|
||||||
context.components.core.store
|
val snackbarMessage = if (closedTab.content.private) {
|
||||||
),
|
requireContext().getString(R.string.snackbar_private_tab_closed)
|
||||||
owner = this,
|
} else {
|
||||||
view = view
|
requireContext().getString(R.string.snackbar_tab_closed)
|
||||||
|
}
|
||||||
|
|
||||||
|
viewLifecycleOwner.lifecycleScope.allowUndo(
|
||||||
|
requireView().browserLayout,
|
||||||
|
snackbarMessage,
|
||||||
|
requireContext().getString(R.string.snackbar_deleted_undo),
|
||||||
|
{
|
||||||
|
requireComponents.useCases.tabsUseCases.undo.invoke()
|
||||||
|
},
|
||||||
|
paddedForBottomToolbar = true,
|
||||||
|
operation = { }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
)
|
||||||
val downloadFeature = DownloadsFeature(
|
val browserToolbarMenuController = DefaultBrowserToolbarMenuController(
|
||||||
context.applicationContext,
|
activity = activity,
|
||||||
store = store,
|
navController = findNavController(),
|
||||||
useCases = context.components.useCases.downloadUseCases,
|
metrics = requireComponents.analytics.metrics,
|
||||||
fragmentManager = childFragmentManager,
|
settings = context.settings(),
|
||||||
tabId = customTabSessionId,
|
readerModeController = readerMenuController,
|
||||||
downloadManager = FetchDownloadManager(
|
sessionManager = requireComponents.core.sessionManager,
|
||||||
context.applicationContext,
|
sessionFeature = sessionFeature,
|
||||||
store,
|
findInPageLauncher = { findInPageIntegration.withFeature { it.launch() } },
|
||||||
DownloadService::class
|
swipeRefresh = swipeRefresh,
|
||||||
),
|
browserAnimator = browserAnimator,
|
||||||
shouldForwardToThirdParties = {
|
customTabSession = customTabSessionId?.let { sessionManager.findSessionById(it) },
|
||||||
PreferenceManager.getDefaultSharedPreferences(context).getBoolean(
|
openInFenixIntent = openInFenixIntent,
|
||||||
context.getPreferenceKey(R.string.pref_key_external_download_manager), false
|
bookmarkTapped = { url: String, title: String ->
|
||||||
)
|
viewLifecycleOwner.lifecycleScope.launch {
|
||||||
},
|
bookmarkTapped(url, title)
|
||||||
promptsStyling = DownloadsFeature.PromptsStyling(
|
|
||||||
gravity = Gravity.BOTTOM,
|
|
||||||
shouldWidthMatchParent = true,
|
|
||||||
positiveButtonBackgroundColor = ThemeManager.resolveAttribute(
|
|
||||||
R.attr.accent,
|
|
||||||
context
|
|
||||||
),
|
|
||||||
positiveButtonTextColor = ThemeManager.resolveAttribute(
|
|
||||||
R.attr.contrastText,
|
|
||||||
context
|
|
||||||
),
|
|
||||||
positiveButtonRadius = (resources.getDimensionPixelSize(R.dimen.tab_corner_radius)).toFloat()
|
|
||||||
),
|
|
||||||
onNeedToRequestPermissions = { permissions ->
|
|
||||||
requestPermissions(permissions, REQUEST_CODE_DOWNLOAD_PERMISSIONS)
|
|
||||||
}
|
}
|
||||||
)
|
},
|
||||||
|
scope = viewLifecycleOwner.lifecycleScope,
|
||||||
|
tabCollectionStorage = requireComponents.core.tabCollectionStorage,
|
||||||
|
topSitesStorage = requireComponents.core.topSitesStorage,
|
||||||
|
browserStore = store
|
||||||
|
)
|
||||||
|
|
||||||
downloadFeature.onDownloadStopped = { downloadState, _, downloadJobStatus ->
|
_browserInteractor = BrowserInteractor(
|
||||||
// If the download is just paused, don't show any in-app notification
|
browserToolbarController,
|
||||||
if (downloadJobStatus == DownloadState.Status.COMPLETED ||
|
browserToolbarMenuController
|
||||||
downloadJobStatus == DownloadState.Status.FAILED
|
)
|
||||||
) {
|
|
||||||
|
|
||||||
saveDownloadDialogState(
|
_browserToolbarView = BrowserToolbarView(
|
||||||
downloadState.sessionId,
|
container = view.browserLayout,
|
||||||
downloadState,
|
toolbarPosition = context.settings().toolbarPosition,
|
||||||
downloadJobStatus
|
interactor = browserInteractor,
|
||||||
)
|
customTabSession = customTabSessionId?.let { sessionManager.findSessionById(it) },
|
||||||
|
lifecycleOwner = viewLifecycleOwner
|
||||||
|
)
|
||||||
|
|
||||||
val dynamicDownloadDialog = DynamicDownloadDialog(
|
toolbarIntegration.set(
|
||||||
container = view.browserLayout,
|
feature = browserToolbarView.toolbarIntegration,
|
||||||
downloadState = downloadState,
|
owner = this,
|
||||||
metrics = requireComponents.analytics.metrics,
|
view = view
|
||||||
didFail = downloadJobStatus == DownloadState.Status.FAILED,
|
)
|
||||||
tryAgain = downloadFeature::tryAgain,
|
|
||||||
onCannotOpenFile = {
|
|
||||||
FenixSnackbar.make(
|
|
||||||
view = view.browserLayout,
|
|
||||||
duration = Snackbar.LENGTH_SHORT,
|
|
||||||
isDisplayedWithBrowserToolbar = true
|
|
||||||
)
|
|
||||||
.setText(context.getString(R.string.mozac_feature_downloads_could_not_open_file))
|
|
||||||
.show()
|
|
||||||
},
|
|
||||||
view = view.viewDynamicDownloadDialog,
|
|
||||||
toolbarHeight = toolbarHeight,
|
|
||||||
onDismiss = { sharedViewModel.downloadDialogState.remove(downloadState.sessionId) }
|
|
||||||
)
|
|
||||||
|
|
||||||
// Don't show the dialog if we aren't in the tab that started the download
|
findInPageIntegration.set(
|
||||||
if (downloadState.sessionId == sessionManager.selectedSession?.id) {
|
feature = FindInPageIntegration(
|
||||||
dynamicDownloadDialog.show()
|
|
||||||
browserToolbarView.expand()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
resumeDownloadDialogState(
|
|
||||||
sessionManager.selectedSession?.id,
|
|
||||||
store, view, context, toolbarHeight
|
|
||||||
)
|
|
||||||
|
|
||||||
downloadsFeature.set(
|
|
||||||
downloadFeature,
|
|
||||||
owner = this,
|
|
||||||
view = view
|
|
||||||
)
|
|
||||||
|
|
||||||
pipFeature = PictureInPictureFeature(
|
|
||||||
store = store,
|
store = store,
|
||||||
activity = requireActivity(),
|
sessionId = customTabSessionId,
|
||||||
crashReporting = context.components.analytics.crashReporter,
|
stub = view.stubFindInPage,
|
||||||
|
engineView = view.engineView,
|
||||||
|
toolbar = browserToolbarView.view
|
||||||
|
),
|
||||||
|
owner = this,
|
||||||
|
view = view
|
||||||
|
)
|
||||||
|
|
||||||
|
browserToolbarView.view.display.setOnSiteSecurityClickedListener {
|
||||||
|
showQuickSettingsDialog()
|
||||||
|
}
|
||||||
|
|
||||||
|
browserToolbarView.view.display.setOnTrackingProtectionClickedListener {
|
||||||
|
context.metrics.track(Event.TrackingProtectionIconPressed)
|
||||||
|
showTrackingProtectionPanel()
|
||||||
|
}
|
||||||
|
|
||||||
|
contextMenuFeature.set(
|
||||||
|
feature = ContextMenuFeature(
|
||||||
|
fragmentManager = parentFragmentManager,
|
||||||
|
store = store,
|
||||||
|
candidates = getContextMenuCandidates(context, view.browserLayout),
|
||||||
|
engineView = view.engineView,
|
||||||
|
useCases = context.components.useCases.contextMenuUseCases,
|
||||||
tabId = customTabSessionId
|
tabId = customTabSessionId
|
||||||
)
|
),
|
||||||
|
owner = this,
|
||||||
|
view = view
|
||||||
|
)
|
||||||
|
|
||||||
appLinksFeature.set(
|
val allowScreenshotsInPrivateMode = context.settings().allowScreenshotsInPrivateMode
|
||||||
feature = AppLinksFeature(
|
secureWindowFeature.set(
|
||||||
context,
|
feature = SecureWindowFeature(
|
||||||
store = store,
|
window = requireActivity().window,
|
||||||
sessionId = customTabSessionId,
|
store = store,
|
||||||
fragmentManager = parentFragmentManager,
|
customTabId = customTabSessionId,
|
||||||
launchInApp = { context.settings().openLinksInExternalApp },
|
isSecure = { !allowScreenshotsInPrivateMode && it.content.private }
|
||||||
loadUrlUseCase = context.components.useCases.sessionUseCases.loadUrl
|
),
|
||||||
|
owner = this,
|
||||||
|
view = view
|
||||||
|
)
|
||||||
|
|
||||||
|
if (newMediaSessionApi) {
|
||||||
|
fullScreenMediaSessionFeature.set(
|
||||||
|
feature = MediaSessionFullscreenFeature(
|
||||||
|
requireActivity(),
|
||||||
|
context.components.core.store
|
||||||
),
|
),
|
||||||
owner = this,
|
owner = this,
|
||||||
view = view
|
view = view
|
||||||
)
|
)
|
||||||
|
} else {
|
||||||
|
fullScreenMediaFeature.set(
|
||||||
|
feature = MediaFullscreenOrientationFeature(
|
||||||
|
requireActivity(),
|
||||||
|
context.components.core.store
|
||||||
|
),
|
||||||
|
owner = this,
|
||||||
|
view = view
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
promptsFeature.set(
|
val downloadFeature = DownloadsFeature(
|
||||||
feature = PromptFeature(
|
context.applicationContext,
|
||||||
fragment = this,
|
store = store,
|
||||||
store = store,
|
useCases = context.components.useCases.downloadUseCases,
|
||||||
customTabId = customTabSessionId,
|
fragmentManager = childFragmentManager,
|
||||||
fragmentManager = parentFragmentManager,
|
tabId = customTabSessionId,
|
||||||
loginValidationDelegate = DefaultLoginValidationDelegate(
|
downloadManager = FetchDownloadManager(
|
||||||
context.components.core.lazyPasswordsStorage
|
context.applicationContext,
|
||||||
),
|
store,
|
||||||
isSaveLoginEnabled = {
|
DownloadService::class
|
||||||
context.settings().shouldPromptToSaveLogins
|
),
|
||||||
|
shouldForwardToThirdParties = {
|
||||||
|
PreferenceManager.getDefaultSharedPreferences(context).getBoolean(
|
||||||
|
context.getPreferenceKey(R.string.pref_key_external_download_manager), false
|
||||||
|
)
|
||||||
|
},
|
||||||
|
promptsStyling = DownloadsFeature.PromptsStyling(
|
||||||
|
gravity = Gravity.BOTTOM,
|
||||||
|
shouldWidthMatchParent = true,
|
||||||
|
positiveButtonBackgroundColor = ThemeManager.resolveAttribute(
|
||||||
|
R.attr.accent,
|
||||||
|
context
|
||||||
|
),
|
||||||
|
positiveButtonTextColor = ThemeManager.resolveAttribute(
|
||||||
|
R.attr.contrastText,
|
||||||
|
context
|
||||||
|
),
|
||||||
|
positiveButtonRadius = (resources.getDimensionPixelSize(R.dimen.tab_corner_radius)).toFloat()
|
||||||
|
),
|
||||||
|
onNeedToRequestPermissions = { permissions ->
|
||||||
|
requestPermissions(permissions, REQUEST_CODE_DOWNLOAD_PERMISSIONS)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
downloadFeature.onDownloadStopped = { downloadState, _, downloadJobStatus ->
|
||||||
|
// If the download is just paused, don't show any in-app notification
|
||||||
|
if (downloadJobStatus == DownloadState.Status.COMPLETED ||
|
||||||
|
downloadJobStatus == DownloadState.Status.FAILED
|
||||||
|
) {
|
||||||
|
|
||||||
|
saveDownloadDialogState(
|
||||||
|
downloadState.sessionId,
|
||||||
|
downloadState,
|
||||||
|
downloadJobStatus
|
||||||
|
)
|
||||||
|
|
||||||
|
val dynamicDownloadDialog = DynamicDownloadDialog(
|
||||||
|
container = view.browserLayout,
|
||||||
|
downloadState = downloadState,
|
||||||
|
metrics = requireComponents.analytics.metrics,
|
||||||
|
didFail = downloadJobStatus == DownloadState.Status.FAILED,
|
||||||
|
tryAgain = downloadFeature::tryAgain,
|
||||||
|
onCannotOpenFile = {
|
||||||
|
FenixSnackbar.make(
|
||||||
|
view = view.browserLayout,
|
||||||
|
duration = Snackbar.LENGTH_SHORT,
|
||||||
|
isDisplayedWithBrowserToolbar = true
|
||||||
|
)
|
||||||
|
.setText(context.getString(R.string.mozac_feature_downloads_could_not_open_file))
|
||||||
|
.show()
|
||||||
},
|
},
|
||||||
loginExceptionStorage = context.components.core.loginExceptionStorage,
|
view = view.viewDynamicDownloadDialog,
|
||||||
shareDelegate = object : ShareDelegate {
|
toolbarHeight = toolbarHeight,
|
||||||
override fun showShareSheet(
|
onDismiss = { sharedViewModel.downloadDialogState.remove(downloadState.sessionId) }
|
||||||
context: Context,
|
)
|
||||||
shareData: ShareData,
|
|
||||||
onDismiss: () -> Unit,
|
// Don't show the dialog if we aren't in the tab that started the download
|
||||||
onSuccess: () -> Unit
|
if (downloadState.sessionId == sessionManager.selectedSession?.id) {
|
||||||
) {
|
dynamicDownloadDialog.show()
|
||||||
val directions = NavGraphDirections.actionGlobalShareFragment(
|
browserToolbarView.expand()
|
||||||
data = arrayOf(shareData),
|
}
|
||||||
showPage = true,
|
}
|
||||||
sessionId = getSessionById()?.id
|
}
|
||||||
)
|
|
||||||
findNavController().navigate(directions)
|
resumeDownloadDialogState(
|
||||||
}
|
sessionManager.selectedSession?.id,
|
||||||
},
|
store, view, context, toolbarHeight
|
||||||
onNeedToRequestPermissions = { permissions ->
|
)
|
||||||
requestPermissions(permissions, REQUEST_CODE_PROMPT_PERMISSIONS)
|
|
||||||
},
|
downloadsFeature.set(
|
||||||
loginPickerView = loginSelectBar,
|
downloadFeature,
|
||||||
onManageLogins = {
|
owner = this,
|
||||||
browserAnimator.captureEngineViewAndDrawStatically {
|
view = view
|
||||||
val directions =
|
)
|
||||||
NavGraphDirections.actionGlobalSavedLoginsAuthFragment()
|
|
||||||
findNavController().navigate(directions)
|
pipFeature = PictureInPictureFeature(
|
||||||
}
|
store = store,
|
||||||
|
activity = requireActivity(),
|
||||||
|
crashReporting = context.components.analytics.crashReporter,
|
||||||
|
tabId = customTabSessionId
|
||||||
|
)
|
||||||
|
|
||||||
|
appLinksFeature.set(
|
||||||
|
feature = AppLinksFeature(
|
||||||
|
context,
|
||||||
|
store = store,
|
||||||
|
sessionId = customTabSessionId,
|
||||||
|
fragmentManager = parentFragmentManager,
|
||||||
|
launchInApp = { context.settings().openLinksInExternalApp },
|
||||||
|
loadUrlUseCase = context.components.useCases.sessionUseCases.loadUrl
|
||||||
|
),
|
||||||
|
owner = this,
|
||||||
|
view = view
|
||||||
|
)
|
||||||
|
|
||||||
|
promptsFeature.set(
|
||||||
|
feature = PromptFeature(
|
||||||
|
fragment = this,
|
||||||
|
store = store,
|
||||||
|
customTabId = customTabSessionId,
|
||||||
|
fragmentManager = parentFragmentManager,
|
||||||
|
loginValidationDelegate = DefaultLoginValidationDelegate(
|
||||||
|
context.components.core.lazyPasswordsStorage
|
||||||
|
),
|
||||||
|
isSaveLoginEnabled = {
|
||||||
|
context.settings().shouldPromptToSaveLogins
|
||||||
|
},
|
||||||
|
loginExceptionStorage = context.components.core.loginExceptionStorage,
|
||||||
|
shareDelegate = object : ShareDelegate {
|
||||||
|
override fun showShareSheet(
|
||||||
|
context: Context,
|
||||||
|
shareData: ShareData,
|
||||||
|
onDismiss: () -> Unit,
|
||||||
|
onSuccess: () -> Unit
|
||||||
|
) {
|
||||||
|
val directions = NavGraphDirections.actionGlobalShareFragment(
|
||||||
|
data = arrayOf(shareData),
|
||||||
|
showPage = true,
|
||||||
|
sessionId = getSessionById()?.id
|
||||||
|
)
|
||||||
|
findNavController().navigate(directions)
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
onNeedToRequestPermissions = { permissions ->
|
||||||
|
requestPermissions(permissions, REQUEST_CODE_PROMPT_PERMISSIONS)
|
||||||
|
},
|
||||||
|
loginPickerView = loginSelectBar,
|
||||||
|
onManageLogins = {
|
||||||
|
browserAnimator.captureEngineViewAndDrawStatically {
|
||||||
|
val directions =
|
||||||
|
NavGraphDirections.actionGlobalSavedLoginsAuthFragment()
|
||||||
|
findNavController().navigate(directions)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
),
|
||||||
|
owner = this,
|
||||||
|
view = view
|
||||||
|
)
|
||||||
|
|
||||||
|
sessionFeature.set(
|
||||||
|
feature = SessionFeature(
|
||||||
|
requireComponents.core.store,
|
||||||
|
requireComponents.useCases.sessionUseCases.goBack,
|
||||||
|
view.engineView,
|
||||||
|
customTabSessionId
|
||||||
|
),
|
||||||
|
owner = this,
|
||||||
|
view = view
|
||||||
|
)
|
||||||
|
|
||||||
|
searchFeature.set(
|
||||||
|
feature = SearchFeature(store, customTabSessionId) { request, tabId ->
|
||||||
|
val parentSession = sessionManager.findSessionById(tabId)
|
||||||
|
val useCase = if (request.isPrivate) {
|
||||||
|
requireComponents.useCases.searchUseCases.newPrivateTabSearch
|
||||||
|
} else {
|
||||||
|
requireComponents.useCases.searchUseCases.newTabSearch
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parentSession?.isCustomTabSession() == true) {
|
||||||
|
useCase.invoke(request.query)
|
||||||
|
requireActivity().startActivity(openInFenixIntent)
|
||||||
|
} else {
|
||||||
|
useCase.invoke(request.query, parentSessionId = parentSession?.id)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
owner = this,
|
||||||
|
view = view
|
||||||
|
)
|
||||||
|
|
||||||
|
val accentHighContrastColor =
|
||||||
|
ThemeManager.resolveAttribute(R.attr.accentHighContrast, context)
|
||||||
|
|
||||||
|
sitePermissionsFeature.set(
|
||||||
|
feature = SitePermissionsFeature(
|
||||||
|
context = context,
|
||||||
|
storage = context.components.core.permissionStorage.permissionsStorage,
|
||||||
|
fragmentManager = parentFragmentManager,
|
||||||
|
promptsStyling = SitePermissionsFeature.PromptsStyling(
|
||||||
|
gravity = getAppropriateLayoutGravity(),
|
||||||
|
shouldWidthMatchParent = true,
|
||||||
|
positiveButtonBackgroundColor = accentHighContrastColor,
|
||||||
|
positiveButtonTextColor = R.color.photonWhite
|
||||||
|
),
|
||||||
|
sessionId = customTabSessionId,
|
||||||
|
onNeedToRequestPermissions = { permissions ->
|
||||||
|
requestPermissions(permissions, REQUEST_CODE_APP_PERMISSIONS)
|
||||||
|
},
|
||||||
|
onShouldShowRequestPermissionRationale = {
|
||||||
|
shouldShowRequestPermissionRationale(
|
||||||
|
it
|
||||||
|
)
|
||||||
|
},
|
||||||
|
store = store
|
||||||
|
),
|
||||||
|
owner = this,
|
||||||
|
view = view
|
||||||
|
)
|
||||||
|
|
||||||
|
sitePermissionWifiIntegration.set(
|
||||||
|
feature = SitePermissionsWifiIntegration(
|
||||||
|
settings = context.settings(),
|
||||||
|
wifiConnectionMonitor = context.components.wifiConnectionMonitor
|
||||||
|
),
|
||||||
|
owner = this,
|
||||||
|
view = view
|
||||||
|
)
|
||||||
|
|
||||||
|
if (FeatureFlags.webAuthFeature) {
|
||||||
|
webAuthnFeature.set(
|
||||||
|
feature = WebAuthnFeature(
|
||||||
|
engine = requireComponents.core.engine,
|
||||||
|
activity = requireActivity()
|
||||||
),
|
),
|
||||||
owner = this,
|
owner = this,
|
||||||
view = view
|
view = view
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
sessionFeature.set(
|
context.settings().setSitePermissionSettingListener(viewLifecycleOwner) {
|
||||||
feature = SessionFeature(
|
// If the user connects to WIFI while on the BrowserFragment, this will update the
|
||||||
|
// SitePermissionsRules (specifically autoplay) accordingly
|
||||||
|
runIfFragmentIsAttached {
|
||||||
|
assignSitePermissionsRules()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assignSitePermissionsRules()
|
||||||
|
|
||||||
|
fullScreenFeature.set(
|
||||||
|
feature = FullScreenFeature(
|
||||||
|
requireComponents.core.store,
|
||||||
|
requireComponents.useCases.sessionUseCases,
|
||||||
|
customTabSessionId,
|
||||||
|
::viewportFitChange,
|
||||||
|
::fullScreenChanged
|
||||||
|
),
|
||||||
|
owner = this,
|
||||||
|
view = view
|
||||||
|
)
|
||||||
|
|
||||||
|
expandToolbarOnNavigation(store)
|
||||||
|
|
||||||
|
store.flowScoped(viewLifecycleOwner) { flow ->
|
||||||
|
flow.mapNotNull { state -> state.findTabOrCustomTabOrSelectedTab(customTabSessionId) }
|
||||||
|
.ifChanged { tab -> tab.content.pictureInPictureEnabled }
|
||||||
|
.collect { tab -> pipModeChanged(tab) }
|
||||||
|
}
|
||||||
|
|
||||||
|
view.swipeRefresh.isEnabled = shouldPullToRefreshBeEnabled(false)
|
||||||
|
|
||||||
|
if (view.swipeRefresh.isEnabled) {
|
||||||
|
val primaryTextColor =
|
||||||
|
ThemeManager.resolveAttribute(R.attr.primaryText, context)
|
||||||
|
view.swipeRefresh.setColorSchemeColors(primaryTextColor)
|
||||||
|
swipeRefreshFeature.set(
|
||||||
|
feature = SwipeRefreshFeature(
|
||||||
requireComponents.core.store,
|
requireComponents.core.store,
|
||||||
requireComponents.useCases.sessionUseCases.goBack,
|
context.components.useCases.sessionUseCases.reload,
|
||||||
view.engineView,
|
view.swipeRefresh,
|
||||||
customTabSessionId
|
customTabSessionId
|
||||||
),
|
),
|
||||||
owner = this,
|
owner = this,
|
||||||
view = view
|
view = view
|
||||||
)
|
)
|
||||||
|
|
||||||
searchFeature.set(
|
|
||||||
feature = SearchFeature(store, customTabSessionId) { request, tabId ->
|
|
||||||
val parentSession = sessionManager.findSessionById(tabId)
|
|
||||||
val useCase = if (request.isPrivate) {
|
|
||||||
requireComponents.useCases.searchUseCases.newPrivateTabSearch
|
|
||||||
} else {
|
|
||||||
requireComponents.useCases.searchUseCases.newTabSearch
|
|
||||||
}
|
|
||||||
|
|
||||||
if (parentSession?.isCustomTabSession() == true) {
|
|
||||||
useCase.invoke(request.query)
|
|
||||||
requireActivity().startActivity(openInFenixIntent)
|
|
||||||
} else {
|
|
||||||
useCase.invoke(request.query, parentSessionId = parentSession?.id)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
owner = this,
|
|
||||||
view = view
|
|
||||||
)
|
|
||||||
|
|
||||||
val accentHighContrastColor =
|
|
||||||
ThemeManager.resolveAttribute(R.attr.accentHighContrast, context)
|
|
||||||
|
|
||||||
sitePermissionsFeature.set(
|
|
||||||
feature = SitePermissionsFeature(
|
|
||||||
context = context,
|
|
||||||
storage = context.components.core.permissionStorage.permissionsStorage,
|
|
||||||
fragmentManager = parentFragmentManager,
|
|
||||||
promptsStyling = SitePermissionsFeature.PromptsStyling(
|
|
||||||
gravity = getAppropriateLayoutGravity(),
|
|
||||||
shouldWidthMatchParent = true,
|
|
||||||
positiveButtonBackgroundColor = accentHighContrastColor,
|
|
||||||
positiveButtonTextColor = R.color.photonWhite
|
|
||||||
),
|
|
||||||
sessionId = customTabSessionId,
|
|
||||||
onNeedToRequestPermissions = { permissions ->
|
|
||||||
requestPermissions(permissions, REQUEST_CODE_APP_PERMISSIONS)
|
|
||||||
},
|
|
||||||
onShouldShowRequestPermissionRationale = {
|
|
||||||
shouldShowRequestPermissionRationale(
|
|
||||||
it
|
|
||||||
)
|
|
||||||
},
|
|
||||||
store = store
|
|
||||||
),
|
|
||||||
owner = this,
|
|
||||||
view = view
|
|
||||||
)
|
|
||||||
|
|
||||||
sitePermissionWifiIntegration.set(
|
|
||||||
feature = SitePermissionsWifiIntegration(
|
|
||||||
settings = context.settings(),
|
|
||||||
wifiConnectionMonitor = context.components.wifiConnectionMonitor
|
|
||||||
),
|
|
||||||
owner = this,
|
|
||||||
view = view
|
|
||||||
)
|
|
||||||
|
|
||||||
if (FeatureFlags.webAuthFeature) {
|
|
||||||
webAuthnFeature.set(
|
|
||||||
feature = WebAuthnFeature(
|
|
||||||
engine = requireComponents.core.engine,
|
|
||||||
activity = requireActivity()
|
|
||||||
),
|
|
||||||
owner = this,
|
|
||||||
view = view
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
context.settings().setSitePermissionSettingListener(viewLifecycleOwner) {
|
|
||||||
// If the user connects to WIFI while on the BrowserFragment, this will update the
|
|
||||||
// SitePermissionsRules (specifically autoplay) accordingly
|
|
||||||
runIfFragmentIsAttached {
|
|
||||||
assignSitePermissionsRules()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
assignSitePermissionsRules()
|
|
||||||
|
|
||||||
fullScreenFeature.set(
|
|
||||||
feature = FullScreenFeature(
|
|
||||||
requireComponents.core.store,
|
|
||||||
requireComponents.useCases.sessionUseCases,
|
|
||||||
customTabSessionId,
|
|
||||||
::viewportFitChange,
|
|
||||||
::fullScreenChanged
|
|
||||||
),
|
|
||||||
owner = this,
|
|
||||||
view = view
|
|
||||||
)
|
|
||||||
|
|
||||||
expandToolbarOnNavigation(store)
|
|
||||||
|
|
||||||
store.flowScoped(viewLifecycleOwner) { flow ->
|
|
||||||
flow.mapNotNull { state -> state.findTabOrCustomTabOrSelectedTab(customTabSessionId) }
|
|
||||||
.ifChanged { tab -> tab.content.pictureInPictureEnabled }
|
|
||||||
.collect { tab -> pipModeChanged(tab) }
|
|
||||||
}
|
|
||||||
|
|
||||||
view.swipeRefresh.isEnabled = shouldPullToRefreshBeEnabled(false)
|
|
||||||
|
|
||||||
if (view.swipeRefresh.isEnabled) {
|
|
||||||
val primaryTextColor =
|
|
||||||
ThemeManager.resolveAttribute(R.attr.primaryText, context)
|
|
||||||
view.swipeRefresh.setColorSchemeColors(primaryTextColor)
|
|
||||||
swipeRefreshFeature.set(
|
|
||||||
feature = SwipeRefreshFeature(
|
|
||||||
requireComponents.core.store,
|
|
||||||
context.components.useCases.sessionUseCases.reload,
|
|
||||||
view.swipeRefresh,
|
|
||||||
customTabSessionId
|
|
||||||
),
|
|
||||||
owner = this,
|
|
||||||
view = view
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
webchannelIntegration.set(
|
|
||||||
feature = FxaWebChannelFeature(
|
|
||||||
requireContext(),
|
|
||||||
customTabSessionId,
|
|
||||||
requireComponents.core.engine,
|
|
||||||
requireComponents.core.store,
|
|
||||||
requireComponents.backgroundServices.accountManager,
|
|
||||||
requireComponents.backgroundServices.serverConfig,
|
|
||||||
setOf(FxaCapability.CHOOSE_WHAT_TO_SYNC)
|
|
||||||
),
|
|
||||||
owner = this,
|
|
||||||
view = view
|
|
||||||
)
|
|
||||||
|
|
||||||
initializeEngineView(toolbarHeight)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
webchannelIntegration.set(
|
||||||
|
feature = FxaWebChannelFeature(
|
||||||
|
requireContext(),
|
||||||
|
customTabSessionId,
|
||||||
|
requireComponents.core.engine,
|
||||||
|
requireComponents.core.store,
|
||||||
|
requireComponents.backgroundServices.accountManager,
|
||||||
|
requireComponents.backgroundServices.serverConfig,
|
||||||
|
setOf(FxaCapability.CHOOSE_WHAT_TO_SYNC)
|
||||||
|
),
|
||||||
|
owner = this,
|
||||||
|
view = view
|
||||||
|
)
|
||||||
|
|
||||||
|
initializeEngineView(toolbarHeight)
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
@ -928,9 +934,7 @@ abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler,
|
|||||||
resumeDownloadDialogState(selectedTab.id, context.components.core.store, view, context, toolbarHeight)
|
resumeDownloadDialogState(selectedTab.id, context.components.core.store, view, context, toolbarHeight)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
view?.let { view ->
|
view?.let { view -> initializeUI(view) }
|
||||||
browserInitialized = initializeUI(view) != null
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1070,7 +1074,7 @@ abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler,
|
|||||||
sitePermissions: SitePermissions?
|
sitePermissions: SitePermissions?
|
||||||
)
|
)
|
||||||
|
|
||||||
protected abstract fun navToTrackingProtectionPanel(session: Session)
|
protected abstract fun navToTrackingProtectionPanel(tab: SessionState)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the layout [android.view.Gravity] for the quick settings and ETP dialog.
|
* Returns the layout [android.view.Gravity] for the quick settings and ETP dialog.
|
||||||
@ -1108,9 +1112,9 @@ abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler,
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun showTrackingProtectionPanel() {
|
private fun showTrackingProtectionPanel() {
|
||||||
val session = getSessionById() ?: return
|
val tab = getCurrentTab() ?: return
|
||||||
view?.let {
|
view?.let {
|
||||||
navToTrackingProtectionPanel(session)
|
navToTrackingProtectionPanel(tab)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,7 +15,6 @@ import com.google.android.material.snackbar.Snackbar
|
|||||||
import kotlinx.android.synthetic.main.fragment_browser.*
|
import kotlinx.android.synthetic.main.fragment_browser.*
|
||||||
import kotlinx.android.synthetic.main.fragment_browser.view.*
|
import kotlinx.android.synthetic.main.fragment_browser.view.*
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
import mozilla.components.browser.session.Session
|
|
||||||
import mozilla.components.browser.state.selector.findTab
|
import mozilla.components.browser.state.selector.findTab
|
||||||
import mozilla.components.browser.state.state.TabSessionState
|
import mozilla.components.browser.state.state.TabSessionState
|
||||||
import mozilla.components.browser.state.state.SessionState
|
import mozilla.components.browser.state.state.SessionState
|
||||||
@ -56,107 +55,107 @@ class BrowserFragment : BaseBrowserFragment(), UserInteractionHandler {
|
|||||||
private var pwaOnboardingObserver: PwaOnboardingObserver? = null
|
private var pwaOnboardingObserver: PwaOnboardingObserver? = null
|
||||||
|
|
||||||
@Suppress("LongMethod")
|
@Suppress("LongMethod")
|
||||||
override fun initializeUI(view: View): Session? {
|
override fun initializeUI(view: View, tab: SessionState) {
|
||||||
|
super.initializeUI(view, tab)
|
||||||
|
|
||||||
val context = requireContext()
|
val context = requireContext()
|
||||||
val components = context.components
|
val components = context.components
|
||||||
|
|
||||||
return super.initializeUI(view)?.also {
|
if (context.settings().isSwipeToolbarToSwitchTabsEnabled) {
|
||||||
if (context.settings().isSwipeToolbarToSwitchTabsEnabled) {
|
gestureLayout.addGestureListener(
|
||||||
gestureLayout.addGestureListener(
|
ToolbarGestureHandler(
|
||||||
ToolbarGestureHandler(
|
activity = requireActivity(),
|
||||||
activity = requireActivity(),
|
contentLayout = browserLayout,
|
||||||
contentLayout = browserLayout,
|
tabPreview = tabPreview,
|
||||||
tabPreview = tabPreview,
|
toolbarLayout = browserToolbarView.view,
|
||||||
toolbarLayout = browserToolbarView.view,
|
|
||||||
store = components.core.store,
|
|
||||||
sessionManager = components.core.sessionManager
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
val readerModeAction =
|
|
||||||
BrowserToolbar.ToggleButton(
|
|
||||||
image = AppCompatResources.getDrawable(requireContext(), R.drawable.ic_readermode)!!,
|
|
||||||
imageSelected =
|
|
||||||
AppCompatResources.getDrawable(requireContext(), R.drawable.ic_readermode_selected)!!,
|
|
||||||
contentDescription = requireContext().getString(R.string.browser_menu_read),
|
|
||||||
contentDescriptionSelected = requireContext().getString(R.string.browser_menu_read_close),
|
|
||||||
visible = {
|
|
||||||
readerModeAvailable
|
|
||||||
},
|
|
||||||
selected = getSessionById()?.let {
|
|
||||||
activity?.components?.core?.store?.state?.findTab(it.id)?.readerState?.active
|
|
||||||
} ?: false,
|
|
||||||
listener = browserInteractor::onReaderModePressed
|
|
||||||
)
|
|
||||||
|
|
||||||
browserToolbarView.view.addPageAction(readerModeAction)
|
|
||||||
|
|
||||||
thumbnailsFeature.set(
|
|
||||||
feature = BrowserThumbnails(context, view.engineView, components.core.store),
|
|
||||||
owner = this,
|
|
||||||
view = view
|
|
||||||
)
|
|
||||||
|
|
||||||
readerViewFeature.set(
|
|
||||||
feature = components.strictMode.resetAfter(StrictMode.allowThreadDiskReads()) {
|
|
||||||
ReaderViewFeature(
|
|
||||||
context,
|
|
||||||
components.core.engine,
|
|
||||||
components.core.store,
|
|
||||||
view.readerViewControlsBar
|
|
||||||
) { available, active ->
|
|
||||||
if (available) {
|
|
||||||
components.analytics.metrics.track(Event.ReaderModeAvailable)
|
|
||||||
}
|
|
||||||
|
|
||||||
readerModeAvailable = available
|
|
||||||
readerModeAction.setSelected(active)
|
|
||||||
safeInvalidateBrowserToolbarView()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
owner = this,
|
|
||||||
view = view
|
|
||||||
)
|
|
||||||
|
|
||||||
windowFeature.set(
|
|
||||||
feature = WindowFeature(
|
|
||||||
store = components.core.store,
|
store = components.core.store,
|
||||||
tabsUseCases = components.useCases.tabsUseCases
|
sessionManager = components.core.sessionManager
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
val readerModeAction =
|
||||||
|
BrowserToolbar.ToggleButton(
|
||||||
|
image = AppCompatResources.getDrawable(requireContext(), R.drawable.ic_readermode)!!,
|
||||||
|
imageSelected =
|
||||||
|
AppCompatResources.getDrawable(requireContext(), R.drawable.ic_readermode_selected)!!,
|
||||||
|
contentDescription = requireContext().getString(R.string.browser_menu_read),
|
||||||
|
contentDescriptionSelected = requireContext().getString(R.string.browser_menu_read_close),
|
||||||
|
visible = {
|
||||||
|
readerModeAvailable
|
||||||
|
},
|
||||||
|
selected = getSessionById()?.let {
|
||||||
|
activity?.components?.core?.store?.state?.findTab(it.id)?.readerState?.active
|
||||||
|
} ?: false,
|
||||||
|
listener = browserInteractor::onReaderModePressed
|
||||||
|
)
|
||||||
|
|
||||||
|
browserToolbarView.view.addPageAction(readerModeAction)
|
||||||
|
|
||||||
|
thumbnailsFeature.set(
|
||||||
|
feature = BrowserThumbnails(context, view.engineView, components.core.store),
|
||||||
|
owner = this,
|
||||||
|
view = view
|
||||||
|
)
|
||||||
|
|
||||||
|
readerViewFeature.set(
|
||||||
|
feature = components.strictMode.resetAfter(StrictMode.allowThreadDiskReads()) {
|
||||||
|
ReaderViewFeature(
|
||||||
|
context,
|
||||||
|
components.core.engine,
|
||||||
|
components.core.store,
|
||||||
|
view.readerViewControlsBar
|
||||||
|
) { available, active ->
|
||||||
|
if (available) {
|
||||||
|
components.analytics.metrics.track(Event.ReaderModeAvailable)
|
||||||
|
}
|
||||||
|
|
||||||
|
readerModeAvailable = available
|
||||||
|
readerModeAction.setSelected(active)
|
||||||
|
safeInvalidateBrowserToolbarView()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
owner = this,
|
||||||
|
view = view
|
||||||
|
)
|
||||||
|
|
||||||
|
windowFeature.set(
|
||||||
|
feature = WindowFeature(
|
||||||
|
store = components.core.store,
|
||||||
|
tabsUseCases = components.useCases.tabsUseCases
|
||||||
|
),
|
||||||
|
owner = this,
|
||||||
|
view = view
|
||||||
|
)
|
||||||
|
|
||||||
|
if (context.settings().shouldShowOpenInAppCfr) {
|
||||||
|
openInAppOnboardingObserver.set(
|
||||||
|
feature = OpenInAppOnboardingObserver(
|
||||||
|
context = context,
|
||||||
|
store = context.components.core.store,
|
||||||
|
lifecycleOwner = this,
|
||||||
|
navController = findNavController(),
|
||||||
|
settings = context.settings(),
|
||||||
|
appLinksUseCases = context.components.useCases.appLinksUseCases,
|
||||||
|
container = browserLayout as ViewGroup
|
||||||
|
),
|
||||||
|
owner = this,
|
||||||
|
view = view
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (context.settings().shouldShowTrackingProtectionCfr) {
|
||||||
|
trackingProtectionOverlayObserver.set(
|
||||||
|
feature = TrackingProtectionOverlay(
|
||||||
|
context = context,
|
||||||
|
store = context.components.core.store,
|
||||||
|
lifecycleOwner = viewLifecycleOwner,
|
||||||
|
settings = context.settings(),
|
||||||
|
metrics = context.components.analytics.metrics,
|
||||||
|
getToolbar = { browserToolbarView.view }
|
||||||
),
|
),
|
||||||
owner = this,
|
owner = this,
|
||||||
view = view
|
view = view
|
||||||
)
|
)
|
||||||
|
|
||||||
if (context.settings().shouldShowOpenInAppCfr) {
|
|
||||||
openInAppOnboardingObserver.set(
|
|
||||||
feature = OpenInAppOnboardingObserver(
|
|
||||||
context = context,
|
|
||||||
store = context.components.core.store,
|
|
||||||
lifecycleOwner = this,
|
|
||||||
navController = findNavController(),
|
|
||||||
settings = context.settings(),
|
|
||||||
appLinksUseCases = context.components.useCases.appLinksUseCases,
|
|
||||||
container = browserLayout as ViewGroup
|
|
||||||
),
|
|
||||||
owner = this,
|
|
||||||
view = view
|
|
||||||
)
|
|
||||||
}
|
|
||||||
if (context.settings().shouldShowTrackingProtectionCfr) {
|
|
||||||
trackingProtectionOverlayObserver.set(
|
|
||||||
feature = TrackingProtectionOverlay(
|
|
||||||
context = context,
|
|
||||||
store = context.components.core.store,
|
|
||||||
lifecycleOwner = viewLifecycleOwner,
|
|
||||||
settings = context.settings(),
|
|
||||||
metrics = context.components.analytics.metrics,
|
|
||||||
getToolbar = { browserToolbarView.view }
|
|
||||||
),
|
|
||||||
owner = this,
|
|
||||||
view = view
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -219,15 +218,15 @@ class BrowserFragment : BaseBrowserFragment(), UserInteractionHandler {
|
|||||||
nav(R.id.browserFragment, directions)
|
nav(R.id.browserFragment, directions)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun navToTrackingProtectionPanel(session: Session) {
|
override fun navToTrackingProtectionPanel(tab: SessionState) {
|
||||||
val navController = findNavController()
|
val navController = findNavController()
|
||||||
|
|
||||||
requireComponents.useCases.trackingProtectionUseCases.containsException(session.id) { contains ->
|
requireComponents.useCases.trackingProtectionUseCases.containsException(tab.id) { contains ->
|
||||||
val isEnabled = session.trackerBlockingEnabled && !contains
|
val isEnabled = tab.trackingProtection.enabled && !contains
|
||||||
val directions =
|
val directions =
|
||||||
BrowserFragmentDirections.actionBrowserFragmentToTrackingProtectionPanelDialogFragment(
|
BrowserFragmentDirections.actionBrowserFragmentToTrackingProtectionPanelDialogFragment(
|
||||||
sessionId = session.id,
|
sessionId = tab.id,
|
||||||
url = session.url,
|
url = tab.content.url,
|
||||||
trackingProtectionEnabled = isEnabled,
|
trackingProtectionEnabled = isEnabled,
|
||||||
gravity = getAppropriateLayoutGravity()
|
gravity = getAppropriateLayoutGravity()
|
||||||
)
|
)
|
||||||
|
@ -9,7 +9,6 @@ import androidx.annotation.VisibleForTesting
|
|||||||
import androidx.navigation.NavDestination
|
import androidx.navigation.NavDestination
|
||||||
import androidx.navigation.NavDirections
|
import androidx.navigation.NavDirections
|
||||||
import kotlinx.android.synthetic.main.activity_home.*
|
import kotlinx.android.synthetic.main.activity_home.*
|
||||||
import mozilla.components.browser.session.runWithSession
|
|
||||||
import mozilla.components.browser.state.selector.findCustomTab
|
import mozilla.components.browser.state.selector.findCustomTab
|
||||||
import mozilla.components.browser.state.state.SessionState
|
import mozilla.components.browser.state.state.SessionState
|
||||||
import mozilla.components.concept.engine.manifest.WebAppManifestParser
|
import mozilla.components.concept.engine.manifest.WebAppManifestParser
|
||||||
@ -102,12 +101,9 @@ open class ExternalAppBrowserActivity : HomeActivity() {
|
|||||||
// When this activity finishes, the process is staying around and the session still
|
// When this activity finishes, the process is staying around and the session still
|
||||||
// exists then remove it now to free all its resources. Once this activity is finished
|
// exists then remove it now to free all its resources. Once this activity is finished
|
||||||
// then there's no way to get back to it other than relaunching it.
|
// then there's no way to get back to it other than relaunching it.
|
||||||
components.core.sessionManager.runWithSession(getExternalTabId()) { session ->
|
val tabId = getExternalTabId()
|
||||||
// If the custom tag config has been removed we are opening this in normal browsing
|
if (tabId != null) {
|
||||||
if (session.customTabConfig != null) {
|
components.useCases.customTabsUseCases.remove(tabId)
|
||||||
remove(session)
|
|
||||||
}
|
|
||||||
true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,6 @@ import androidx.navigation.fragment.navArgs
|
|||||||
import kotlinx.android.synthetic.main.component_browser_top_toolbar.*
|
import kotlinx.android.synthetic.main.component_browser_top_toolbar.*
|
||||||
import kotlinx.android.synthetic.main.fragment_browser.*
|
import kotlinx.android.synthetic.main.fragment_browser.*
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
import mozilla.components.browser.session.Session
|
|
||||||
import mozilla.components.browser.state.state.SessionState
|
import mozilla.components.browser.state.state.SessionState
|
||||||
import mozilla.components.concept.engine.manifest.WebAppManifestParser
|
import mozilla.components.concept.engine.manifest.WebAppManifestParser
|
||||||
import mozilla.components.concept.engine.manifest.getOrNull
|
import mozilla.components.concept.engine.manifest.getOrNull
|
||||||
@ -52,113 +51,109 @@ class ExternalAppBrowserFragment : BaseBrowserFragment(), UserInteractionHandler
|
|||||||
private val hideToolbarFeature = ViewBoundFeatureWrapper<WebAppHideToolbarFeature>()
|
private val hideToolbarFeature = ViewBoundFeatureWrapper<WebAppHideToolbarFeature>()
|
||||||
|
|
||||||
@Suppress("LongMethod", "ComplexMethod")
|
@Suppress("LongMethod", "ComplexMethod")
|
||||||
override fun initializeUI(view: View): Session? {
|
override fun initializeUI(view: View, tab: SessionState) {
|
||||||
return super.initializeUI(view)?.also {
|
super.initializeUI(view, tab)
|
||||||
val activity = requireActivity()
|
|
||||||
val components = activity.components
|
|
||||||
|
|
||||||
val manifest = args.webAppManifest?.let { json ->
|
val customTabSessionId = customTabSessionId ?: return
|
||||||
WebAppManifestParser().parse(json).getOrNull()
|
val activity = requireActivity()
|
||||||
}
|
val components = activity.components
|
||||||
|
val manifest = args.webAppManifest?.let { json -> WebAppManifestParser().parse(json).getOrNull() }
|
||||||
|
|
||||||
customTabSessionId?.let { customTabSessionId ->
|
customTabsIntegration.set(
|
||||||
customTabsIntegration.set(
|
feature = CustomTabsIntegration(
|
||||||
feature = CustomTabsIntegration(
|
sessionManager = requireComponents.core.sessionManager,
|
||||||
sessionManager = requireComponents.core.sessionManager,
|
store = requireComponents.core.store,
|
||||||
store = requireComponents.core.store,
|
useCases = requireComponents.useCases.customTabsUseCases,
|
||||||
useCases = requireComponents.useCases.customTabsUseCases,
|
toolbar = toolbar,
|
||||||
toolbar = toolbar,
|
sessionId = customTabSessionId,
|
||||||
sessionId = customTabSessionId,
|
activity = activity,
|
||||||
activity = activity,
|
onItemTapped = { browserInteractor.onBrowserToolbarMenuItemTapped(it) },
|
||||||
onItemTapped = { browserInteractor.onBrowserToolbarMenuItemTapped(it) },
|
isPrivate = tab.content.private,
|
||||||
isPrivate = it.private,
|
shouldReverseItems = !activity.settings().shouldUseBottomToolbar
|
||||||
shouldReverseItems = !activity.settings().shouldUseBottomToolbar
|
),
|
||||||
),
|
owner = this,
|
||||||
owner = this,
|
view = view
|
||||||
view = view
|
)
|
||||||
)
|
|
||||||
|
|
||||||
windowFeature.set(
|
windowFeature.set(
|
||||||
feature = CustomTabWindowFeature(
|
feature = CustomTabWindowFeature(
|
||||||
activity,
|
activity,
|
||||||
components.core.store,
|
components.core.store,
|
||||||
customTabSessionId
|
customTabSessionId
|
||||||
) { uri ->
|
) { uri ->
|
||||||
val intent =
|
val intent =
|
||||||
Intent.parseUri("${BuildConfig.DEEP_LINK_SCHEME}://open?url=$uri", 0)
|
Intent.parseUri("${BuildConfig.DEEP_LINK_SCHEME}://open?url=$uri", 0)
|
||||||
if (intent.action == Intent.ACTION_VIEW) {
|
if (intent.action == Intent.ACTION_VIEW) {
|
||||||
intent.addCategory(Intent.CATEGORY_BROWSABLE)
|
intent.addCategory(Intent.CATEGORY_BROWSABLE)
|
||||||
intent.component = null
|
intent.component = null
|
||||||
intent.selector = null
|
intent.selector = null
|
||||||
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||||
}
|
|
||||||
activity.startActivity(intent)
|
|
||||||
},
|
|
||||||
owner = this,
|
|
||||||
view = view
|
|
||||||
)
|
|
||||||
|
|
||||||
hideToolbarFeature.set(
|
|
||||||
feature = WebAppHideToolbarFeature(
|
|
||||||
store = requireComponents.core.store,
|
|
||||||
customTabsStore = requireComponents.core.customTabsStore,
|
|
||||||
tabId = customTabSessionId,
|
|
||||||
manifest = manifest
|
|
||||||
) { toolbarVisible ->
|
|
||||||
browserToolbarView.view.isVisible = toolbarVisible
|
|
||||||
webAppToolbarShouldBeVisible = toolbarVisible
|
|
||||||
if (!toolbarVisible) {
|
|
||||||
engineView.setDynamicToolbarMaxHeight(0)
|
|
||||||
val browserEngine =
|
|
||||||
swipeRefresh.layoutParams as CoordinatorLayout.LayoutParams
|
|
||||||
browserEngine.bottomMargin = 0
|
|
||||||
}
|
|
||||||
},
|
|
||||||
owner = this,
|
|
||||||
view = toolbar
|
|
||||||
)
|
|
||||||
|
|
||||||
if (manifest != null) {
|
|
||||||
activity.lifecycle.addObservers(
|
|
||||||
WebAppActivityFeature(
|
|
||||||
activity,
|
|
||||||
components.core.icons,
|
|
||||||
manifest
|
|
||||||
),
|
|
||||||
ManifestUpdateFeature(
|
|
||||||
activity.applicationContext,
|
|
||||||
requireComponents.core.store,
|
|
||||||
requireComponents.core.webAppShortcutManager,
|
|
||||||
requireComponents.core.webAppManifestStorage,
|
|
||||||
customTabSessionId,
|
|
||||||
manifest
|
|
||||||
)
|
|
||||||
)
|
|
||||||
viewLifecycleOwner.lifecycle.addObserver(
|
|
||||||
WebAppSiteControlsFeature(
|
|
||||||
activity.applicationContext,
|
|
||||||
requireComponents.core.store,
|
|
||||||
requireComponents.useCases.sessionUseCases.reload,
|
|
||||||
customTabSessionId,
|
|
||||||
manifest,
|
|
||||||
WebAppSiteControlsBuilder(
|
|
||||||
requireComponents.core.sessionManager,
|
|
||||||
requireComponents.useCases.sessionUseCases.reload,
|
|
||||||
customTabSessionId,
|
|
||||||
manifest
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
viewLifecycleOwner.lifecycle.addObserver(
|
|
||||||
PoweredByNotification(
|
|
||||||
activity.applicationContext,
|
|
||||||
requireComponents.core.store,
|
|
||||||
customTabSessionId
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
activity.startActivity(intent)
|
||||||
|
},
|
||||||
|
owner = this,
|
||||||
|
view = view
|
||||||
|
)
|
||||||
|
|
||||||
|
hideToolbarFeature.set(
|
||||||
|
feature = WebAppHideToolbarFeature(
|
||||||
|
store = requireComponents.core.store,
|
||||||
|
customTabsStore = requireComponents.core.customTabsStore,
|
||||||
|
tabId = customTabSessionId,
|
||||||
|
manifest = manifest
|
||||||
|
) { toolbarVisible ->
|
||||||
|
browserToolbarView.view.isVisible = toolbarVisible
|
||||||
|
webAppToolbarShouldBeVisible = toolbarVisible
|
||||||
|
if (!toolbarVisible) {
|
||||||
|
engineView.setDynamicToolbarMaxHeight(0)
|
||||||
|
val browserEngine =
|
||||||
|
swipeRefresh.layoutParams as CoordinatorLayout.LayoutParams
|
||||||
|
browserEngine.bottomMargin = 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
owner = this,
|
||||||
|
view = toolbar
|
||||||
|
)
|
||||||
|
|
||||||
|
if (manifest != null) {
|
||||||
|
activity.lifecycle.addObservers(
|
||||||
|
WebAppActivityFeature(
|
||||||
|
activity,
|
||||||
|
components.core.icons,
|
||||||
|
manifest
|
||||||
|
),
|
||||||
|
ManifestUpdateFeature(
|
||||||
|
activity.applicationContext,
|
||||||
|
requireComponents.core.store,
|
||||||
|
requireComponents.core.webAppShortcutManager,
|
||||||
|
requireComponents.core.webAppManifestStorage,
|
||||||
|
customTabSessionId,
|
||||||
|
manifest
|
||||||
|
)
|
||||||
|
)
|
||||||
|
viewLifecycleOwner.lifecycle.addObserver(
|
||||||
|
WebAppSiteControlsFeature(
|
||||||
|
activity.applicationContext,
|
||||||
|
requireComponents.core.store,
|
||||||
|
requireComponents.useCases.sessionUseCases.reload,
|
||||||
|
customTabSessionId,
|
||||||
|
manifest,
|
||||||
|
WebAppSiteControlsBuilder(
|
||||||
|
requireComponents.core.sessionManager,
|
||||||
|
requireComponents.useCases.sessionUseCases.reload,
|
||||||
|
customTabSessionId,
|
||||||
|
manifest
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
viewLifecycleOwner.lifecycle.addObserver(
|
||||||
|
PoweredByNotification(
|
||||||
|
activity.applicationContext,
|
||||||
|
requireComponents.core.store,
|
||||||
|
customTabSessionId
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -197,14 +192,14 @@ class ExternalAppBrowserFragment : BaseBrowserFragment(), UserInteractionHandler
|
|||||||
nav(R.id.externalAppBrowserFragment, directions)
|
nav(R.id.externalAppBrowserFragment, directions)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun navToTrackingProtectionPanel(session: Session) {
|
override fun navToTrackingProtectionPanel(tab: SessionState) {
|
||||||
requireComponents.useCases.trackingProtectionUseCases.containsException(session.id) { contains ->
|
requireComponents.useCases.trackingProtectionUseCases.containsException(tab.id) { contains ->
|
||||||
val isEnabled = session.trackerBlockingEnabled && !contains
|
val isEnabled = tab.trackingProtection.enabled && !contains
|
||||||
val directions =
|
val directions =
|
||||||
ExternalAppBrowserFragmentDirections
|
ExternalAppBrowserFragmentDirections
|
||||||
.actionGlobalTrackingProtectionPanelDialogFragment(
|
.actionGlobalTrackingProtectionPanelDialogFragment(
|
||||||
sessionId = session.id,
|
sessionId = tab.id,
|
||||||
url = session.url,
|
url = tab.content.url,
|
||||||
trackingProtectionEnabled = isEnabled,
|
trackingProtectionEnabled = isEnabled,
|
||||||
gravity = getAppropriateLayoutGravity()
|
gravity = getAppropriateLayoutGravity()
|
||||||
)
|
)
|
||||||
|
@ -87,13 +87,13 @@ class BrowserFragmentTest {
|
|||||||
every { browserFragment.onboarding } returns onboarding
|
every { browserFragment.onboarding } returns onboarding
|
||||||
|
|
||||||
every { browserFragment.requireContext() } returns context
|
every { browserFragment.requireContext() } returns context
|
||||||
every { browserFragment.initializeUI(any()) } returns mockk()
|
every { browserFragment.initializeUI(any(), any()) } returns mockk()
|
||||||
every { browserFragment.fullScreenChanged(any()) } returns Unit
|
every { browserFragment.fullScreenChanged(any()) } returns Unit
|
||||||
every { browserFragment.resumeDownloadDialogState(any(), any(), any(), any(), any()) } returns Unit
|
every { browserFragment.resumeDownloadDialogState(any(), any(), any(), any(), any()) } returns Unit
|
||||||
|
|
||||||
|
testTab = createTab(url = "https://mozilla.org")
|
||||||
store = BrowserStore()
|
store = BrowserStore()
|
||||||
every { context.components.core.store } returns store
|
every { context.components.core.store } returns store
|
||||||
testTab = createTab(url = "https://mozilla.org")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
@ -122,10 +122,10 @@ class BrowserFragmentTest {
|
|||||||
@Test
|
@Test
|
||||||
fun `GIVEN browser UI is not initialized WHEN selected tab changes THEN browser UI is initialized`() {
|
fun `GIVEN browser UI is not initialized WHEN selected tab changes THEN browser UI is initialized`() {
|
||||||
browserFragment.observeTabSelection(store)
|
browserFragment.observeTabSelection(store)
|
||||||
verify(exactly = 0) { browserFragment.initializeUI(view) }
|
verify(exactly = 0) { browserFragment.initializeUI(view, testTab) }
|
||||||
|
|
||||||
addAndSelectTab(testTab)
|
addAndSelectTab(testTab)
|
||||||
verify(exactly = 1) { browserFragment.initializeUI(view) }
|
verify(exactly = 1) { browserFragment.initializeUI(view, testTab) }
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
Loading…
Reference in New Issue
Block a user