Unverified Commit c7c4ad05 authored by Sawyer Blatz's avatar Sawyer Blatz Committed by GitHub
Browse files

For #6413: Adds more snackbar positioning logic (#7444)

* For #6413: Adds more snackbar positioning logic

* Refactor
parent f6e286fd
......@@ -64,7 +64,6 @@ import org.mozilla.fenix.NavGraphDirections
import org.mozilla.fenix.R
import org.mozilla.fenix.browser.readermode.DefaultReaderModeController
import org.mozilla.fenix.components.FenixSnackbar
import org.mozilla.fenix.components.BrowserSnackbarPresenter
import org.mozilla.fenix.components.FindInPageIntegration
import org.mozilla.fenix.components.StoreProvider
import org.mozilla.fenix.components.metrics.Event
......@@ -160,7 +159,7 @@ abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler, Session
// browsing data on quit" is activated). After the deletion is over, the snackbar
// is dismissed.
val snackbar: FenixSnackbar? = requireActivity().getRootView()?.let { v ->
FenixSnackbar.make(v, Snackbar.LENGTH_INDEFINITE)
FenixSnackbar.makeWithToolbarPadding(v)
.setText(v.context.getString(R.string.deleting_browsing_data_in_progress))
}
......@@ -283,12 +282,10 @@ abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler, Session
download = download,
tryAgain = downloadFeature::tryAgain,
onCannotOpenFile = {
BrowserSnackbarPresenter(view).present(
text = context.getString(R.string.mozac_feature_downloads_could_not_open_file),
length = Snackbar.LENGTH_SHORT
)
FenixSnackbar.makeWithToolbarPadding(view, Snackbar.LENGTH_SHORT)
.setText(context.getString(R.string.mozac_feature_downloads_could_not_open_file))
.show()
}
)
dialog.show()
}
......@@ -520,9 +517,9 @@ abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler, Session
@CallSuper
override fun onBackPressed(): Boolean {
return findInPageIntegration.onBackPressed() ||
fullScreenFeature.onBackPressed() ||
sessionFeature.onBackPressed() ||
removeSessionIfNeeded()
fullScreenFeature.onBackPressed() ||
sessionFeature.onBackPressed() ||
removeSessionIfNeeded()
}
/**
......@@ -703,17 +700,16 @@ abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler, Session
requireComponents.analytics.metrics.track(Event.AddBookmark)
view?.let { view ->
BrowserSnackbarPresenter(view).present(
text = getString(R.string.bookmark_saved_snackbar),
action = { nav(
R.id.browserFragment,
BrowserFragmentDirections.actionBrowserFragmentToBookmarkEditFragment(
guid
))
},
actionName = getString(R.string.edit_bookmark_snackbar_action),
length = Snackbar.LENGTH_LONG
)
FenixSnackbar.makeWithToolbarPadding(view)
.setText(getString(R.string.bookmark_saved_snackbar))
.setAction(getString(R.string.edit_bookmark_snackbar_action)) {
nav(
R.id.browserFragment,
BrowserFragmentDirections.actionBrowserFragmentToBookmarkEditFragment(
guid
))
}
.show()
}
}
}
......
......@@ -30,7 +30,7 @@ import mozilla.components.support.base.feature.UserInteractionHandler
import mozilla.components.support.base.feature.ViewBoundFeatureWrapper
import org.mozilla.fenix.HomeActivity
import org.mozilla.fenix.R
import org.mozilla.fenix.components.BrowserSnackbarPresenter
import org.mozilla.fenix.components.FenixSnackbar
import org.mozilla.fenix.components.TabCollectionStorage
import org.mozilla.fenix.components.metrics.Event
import org.mozilla.fenix.ext.components
......@@ -230,10 +230,9 @@ class BrowserFragment : BaseBrowserFragment(), UserInteractionHandler {
private fun showTabSavedToCollectionSnackbar() {
view?.let { view ->
BrowserSnackbarPresenter(view).present(
text = view.context.getString(R.string.create_collection_tab_saved),
length = Snackbar.LENGTH_SHORT
)
FenixSnackbar.makeWithToolbarPadding(view, Snackbar.LENGTH_SHORT)
.setText(view.context.getString(R.string.create_collection_tab_saved))
.show()
}
}
}
......
......@@ -6,9 +6,8 @@ package org.mozilla.fenix.browser
import android.view.View
import androidx.annotation.StringRes
import com.google.android.material.snackbar.Snackbar
import mozilla.components.feature.contextmenu.ContextMenuCandidate
import org.mozilla.fenix.components.BrowserSnackbarPresenter
import org.mozilla.fenix.components.FenixSnackbar
class FenixSnackbarDelegate(val view: View) :
ContextMenuCandidate.SnackbarDelegate {
......@@ -20,17 +19,14 @@ class FenixSnackbarDelegate(val view: View) :
listener: ((v: View) -> Unit)?
) {
if (listener != null && action != 0) {
BrowserSnackbarPresenter(view).present(
text = view.context.getString(text),
length = Snackbar.LENGTH_LONG,
actionName = view.context.getString(action),
action = { listener.invoke(view) }
)
FenixSnackbar.makeWithToolbarPadding(view)
.setText(view.context.getString(text))
.setAction(view.context.getString(action)) { listener.invoke(view) }
.show()
} else {
BrowserSnackbarPresenter(view).present(
text = view.context.getString(text),
length = Snackbar.LENGTH_LONG
)
FenixSnackbar.makeWithToolbarPadding(view)
.setText(view.context.getString(text))
.show()
}
}
}
......@@ -32,11 +32,7 @@ class FenixSnackbar private constructor(
init {
view.background = null
view.snackbar_layout.background = if (isError) {
AppCompatResources.getDrawable(context, R.drawable.fenix_snackbar_error_background)
} else {
AppCompatResources.getDrawable(context, R.drawable.fenix_snackbar_background)
}
setAppropriateBackground(isError)
content.snackbar_btn.increaseTapArea(actionButtonIncreaseDps)
......@@ -49,10 +45,22 @@ class FenixSnackbar private constructor(
)
}
fun setAppropriateBackground(isError: Boolean) {
view.snackbar_layout.background = if (isError) {
AppCompatResources.getDrawable(context, R.drawable.fenix_snackbar_error_background)
} else {
AppCompatResources.getDrawable(context, R.drawable.fenix_snackbar_background)
}
}
fun setText(text: String) = this.apply {
view.snackbar_text.text = text
}
fun setLength(duration: Int) = this.apply {
this.duration = duration
}
fun setAction(text: String, action: () -> Unit) = this.apply {
view.snackbar_btn.apply {
setText(text)
......@@ -90,6 +98,28 @@ class FenixSnackbar private constructor(
}
}
/**
* Considers BrowserToolbar for padding when making snackbar
*/
fun makeWithToolbarPadding(
view: View,
duration: Int = LENGTH_LONG,
isError: Boolean = false
): FenixSnackbar {
val shouldUseBottomToolbar = view.context.settings().shouldUseBottomToolbar
val toolbarHeight = view.context.resources
.getDimensionPixelSize(R.dimen.browser_toolbar_height)
return make(view, duration, isError).apply {
this.view.setPadding(
0,
0,
0,
if (shouldUseBottomToolbar) toolbarHeight else 0
)
}
}
// Use the same implementation of `Snackbar`
private fun findSuitableParent(_view: View?): ViewGroup? {
var view = _view
......@@ -147,35 +177,3 @@ private class FenixSnackbarCallback(
private const val animateOutDuration = 150L
}
}
/**
* This snackbar presenter should be used when displaying a snackbar that will appear in
* the BrowserFragment as it takes into account the position of the BrowserToolbar
*/
class BrowserSnackbarPresenter(
private val view: View
) {
fun present(
text: String,
length: Int = FenixSnackbar.LENGTH_LONG,
action: (() -> Unit)? = null,
actionName: String? = null,
isError: Boolean = false
) {
val shouldUseBottomToolbar = view.context.settings().shouldUseBottomToolbar
val toolbarHeight = view.context.resources
.getDimensionPixelSize(R.dimen.browser_toolbar_height)
FenixSnackbar.make(view, length, isError).apply {
if (action != null && actionName != null) setAction(actionName, action)
setText(text)
view.setPadding(
0,
0,
0,
if (shouldUseBottomToolbar) toolbarHeight else 0
)
show()
}
}
}
......@@ -20,10 +20,10 @@ import androidx.annotation.StringRes
import androidx.appcompat.app.AlertDialog
import androidx.constraintlayout.widget.ConstraintSet
import androidx.constraintlayout.widget.ConstraintSet.BOTTOM
import androidx.constraintlayout.widget.ConstraintSet.TOP
import androidx.constraintlayout.widget.ConstraintSet.START
import androidx.constraintlayout.widget.ConstraintSet.END
import androidx.constraintlayout.widget.ConstraintSet.PARENT_ID
import androidx.constraintlayout.widget.ConstraintSet.START
import androidx.constraintlayout.widget.ConstraintSet.TOP
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.Lifecycle
......@@ -41,12 +41,12 @@ import androidx.transition.TransitionInflater
import com.google.android.material.snackbar.Snackbar
import kotlinx.android.synthetic.main.fragment_home.*
import kotlinx.android.synthetic.main.fragment_home.view.*
import kotlinx.coroutines.delay
import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.Dispatchers.Main
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.Dispatchers.Main
import mozilla.appservices.places.BookmarkRoot
import mozilla.components.browser.menu.BrowserMenu
import mozilla.components.browser.session.Session
......@@ -546,11 +546,7 @@ class HomeFragment : Fragment() {
deleteAndQuit(
activity,
lifecycleScope,
view?.let { view ->
FenixSnackbar.make(view, Snackbar.LENGTH_INDEFINITE)
.setText(view.context.getString(R.string.deleting_browsing_data_in_progress))
.setAnchorView(bottom_bar)
}
view?.let { view -> FenixSnackbar.makeWithToolbarPadding(view) }
)
}
}
......
......@@ -17,7 +17,7 @@ import org.mozilla.fenix.BrowserDirection
import org.mozilla.fenix.HomeActivity
import org.mozilla.fenix.R
import org.mozilla.fenix.browser.browsingmode.BrowsingMode
import org.mozilla.fenix.components.BrowserSnackbarPresenter
import org.mozilla.fenix.components.FenixSnackbar
import org.mozilla.fenix.components.Services
import org.mozilla.fenix.components.metrics.Event
import org.mozilla.fenix.ext.components
......@@ -46,7 +46,7 @@ interface BookmarkController {
class DefaultBookmarkController(
private val context: Context,
private val navController: NavController,
private val snackbarPresenter: BrowserSnackbarPresenter,
private val snackbar: FenixSnackbar,
private val deleteBookmarkNodes: (Set<BookmarkNode>, Event) -> Unit,
private val invokePendingDeletion: () -> Unit
) : BookmarkController {
......@@ -72,13 +72,15 @@ class DefaultBookmarkController(
}
override fun handleBookmarkSelected(node: BookmarkNode) {
snackbarPresenter.present(resources.getString(R.string.bookmark_cannot_edit_root))
snackbar.setText(resources.getString(R.string.bookmark_cannot_edit_root))
snackbar.show()
}
override fun handleCopyUrl(item: BookmarkNode) {
val urlClipData = ClipData.newPlainText(item.url, item.url)
context.getSystemService<ClipboardManager>()?.primaryClip = urlClipData
snackbarPresenter.present(resources.getString(R.string.url_copied))
snackbar.setText(resources.getString(R.string.url_copied))
snackbar.show()
}
override fun handleBookmarkSharing(item: BookmarkNode) {
......
......@@ -38,7 +38,7 @@ import mozilla.components.concept.sync.OAuthAccount
import mozilla.components.lib.state.ext.consumeFrom
import mozilla.components.support.base.feature.UserInteractionHandler
import org.mozilla.fenix.R
import org.mozilla.fenix.components.BrowserSnackbarPresenter
import org.mozilla.fenix.components.FenixSnackbar
import org.mozilla.fenix.components.StoreProvider
import org.mozilla.fenix.components.metrics.Event
import org.mozilla.fenix.ext.bookmarkStorage
......@@ -87,7 +87,7 @@ class BookmarkFragment : LibraryPageFragment<BookmarkNode>(), UserInteractionHan
bookmarksController = DefaultBookmarkController(
context = context!!,
navController = findNavController(),
snackbarPresenter = BrowserSnackbarPresenter(view),
snackbar = FenixSnackbar.make(view, FenixSnackbar.LENGTH_LONG),
deleteBookmarkNodes = ::deleteMulti,
invokePendingDeletion = ::invokePendingDeletion
),
......
......@@ -37,7 +37,7 @@ import mozilla.components.concept.storage.BookmarkNodeType
import mozilla.components.support.ktx.android.content.getColorFromAttr
import mozilla.components.support.ktx.android.view.hideKeyboard
import org.mozilla.fenix.R
import org.mozilla.fenix.components.BrowserSnackbarPresenter
import org.mozilla.fenix.components.FenixSnackbar
import org.mozilla.fenix.components.metrics.Event
import org.mozilla.fenix.ext.components
import org.mozilla.fenix.ext.getRootView
......@@ -187,13 +187,14 @@ class EditBookmarkFragment : Fragment(R.layout.fragment_edit_bookmark) {
.popBackStack()
bookmarkNode?.let { bookmark ->
BrowserSnackbarPresenter(activity.getRootView()!!).present(
getString(
R.string.bookmark_deletion_snackbar_message,
bookmark.url?.toShortUrl(context.components.publicSuffixList)
?: bookmark.title
FenixSnackbar.makeWithToolbarPadding(activity.getRootView()!!)
.setText(
getString(R.string.bookmark_deletion_snackbar_message,
bookmark.url?.toShortUrl(context.components.publicSuffixList)
?: bookmark.title
)
)
)
.show()
}
}
}
......
......@@ -18,7 +18,6 @@ import mozilla.components.concept.sync.AuthType
import mozilla.components.concept.sync.OAuthAccount
import org.mozilla.fenix.R
import org.mozilla.fenix.components.FenixSnackbar
import org.mozilla.fenix.components.BrowserSnackbarPresenter
import org.mozilla.fenix.components.metrics.Event
import org.mozilla.fenix.ext.requireComponents
import org.mozilla.fenix.ext.showToolbar
......@@ -26,6 +25,9 @@ import org.mozilla.fenix.ext.showToolbar
@SuppressWarnings("TooManyFunctions")
class TurnOnSyncFragment : Fragment(), AccountObserver {
private val safeArguments get() = requireNotNull(arguments)
private val args get() = TurnOnSyncFragmentArgs.fromBundle(safeArguments)
private val signInClickListener = View.OnClickListener {
requireComponents.services.accountsAuthFeature.beginAuthentication(requireContext())
// TODO The sign-in web content populates session history,
......@@ -74,9 +76,19 @@ class TurnOnSyncFragment : Fragment(), AccountObserver {
}
override fun onAuthenticated(account: OAuthAccount, authType: AuthType) {
BrowserSnackbarPresenter(requireView()).present(
text = requireContext().getString(R.string.sync_syncing_in_progress),
length = FenixSnackbar.LENGTH_SHORT
)
val snackbarText = requireContext().getString(R.string.sync_syncing_in_progress)
val snackbarLength = FenixSnackbar.LENGTH_SHORT
// Since the snackbar can be presented in BrowserFragment or in SettingsFragment we must
// base our display method on the padSnackbar argument
if (args.padSnackbar) {
FenixSnackbar.makeWithToolbarPadding(requireView(), snackbarLength)
.setText(snackbarText)
.show()
} else {
FenixSnackbar.make(requireView(), snackbarLength)
.setText(snackbarText)
.show()
}
}
}
......@@ -5,11 +5,13 @@
package org.mozilla.fenix.settings.deletebrowsingdata
import android.app.Activity
import com.google.android.material.snackbar.Snackbar
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.joinAll
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.mozilla.fenix.R
import org.mozilla.fenix.components.FenixSnackbar
import org.mozilla.fenix.ext.settings
......@@ -21,7 +23,11 @@ fun deleteAndQuit(activity: Activity, coroutineScope: CoroutineScope, snackbar:
val settings = activity.settings()
val controller = DefaultDeleteBrowsingDataController(activity, coroutineContext)
snackbar?.show()
snackbar?.apply {
setText(activity.getString(R.string.deleting_browsing_data_in_progress))
duration = Snackbar.LENGTH_INDEFINITE
show()
}
DeleteBrowsingDataOnQuitType.values().map { type ->
launch {
......
......@@ -146,7 +146,7 @@ class DeleteBrowsingDataFragment : Fragment(R.layout.fragment_delete_browsing_da
updateItemCounts()
FenixSnackbar.make(view!!, FenixSnackbar.LENGTH_SHORT)
FenixSnackbar.makeWithToolbarPadding(requireView(), FenixSnackbar.LENGTH_SHORT)
.setText(resources.getString(R.string.preferences_delete_browsing_data_snackbar))
.show()
......
......@@ -22,7 +22,7 @@ import mozilla.components.concept.sync.Device
import mozilla.components.concept.sync.TabData
import mozilla.components.feature.accounts.push.SendTabUseCases
import org.mozilla.fenix.R
import org.mozilla.fenix.components.BrowserSnackbarPresenter
import org.mozilla.fenix.components.FenixSnackbar
import org.mozilla.fenix.components.metrics.Event
import org.mozilla.fenix.ext.metrics
import org.mozilla.fenix.ext.nav
......@@ -53,7 +53,7 @@ interface ShareController {
* @param context [Context] used for various Android interactions.
* @param shareData the list of [ShareData]s that can be shared.
* @param sendTabUseCases instance of [SendTabUseCases] which allows sending tabs to account devices.
* @param snackbarPresenter - instance of [BrowserSnackbarPresenter] for displaying styled snackbars
* @param snackbar - instance of [FenixSnackbar] for displaying styled snackbars
* @param navController - [NavController] used for navigation.
* @param dismiss - callback signalling sharing can be closed.
*/
......@@ -62,7 +62,7 @@ class DefaultShareController(
private val context: Context,
private val shareData: List<ShareData>,
private val sendTabUseCases: SendTabUseCases,
private val snackbarPresenter: BrowserSnackbarPresenter,
private val snackbar: FenixSnackbar,
private val navController: NavController,
private val dismiss: (ShareController.Result) -> Unit
) : ShareController {
......@@ -89,7 +89,8 @@ class DefaultShareController(
context.startActivity(intent)
ShareController.Result.SUCCESS
} catch (e: SecurityException) {
snackbarPresenter.present(context.getString(R.string.share_error_snackbar))
snackbar.setText(context.getString(R.string.share_error_snackbar))
snackbar.show()
ShareController.Result.SHARE_ERROR
}
dismiss(result)
......@@ -111,7 +112,8 @@ class DefaultShareController(
override fun handleSignIn() {
context.metrics.track(Event.SignInToSendTab)
val directions = ShareFragmentDirections.actionShareFragmentToTurnOnSyncFragment()
val directions =
ShareFragmentDirections.actionShareFragmentToTurnOnSyncFragment(padSnackbar = true)
navController.nav(R.id.shareFragment, directions)
dismiss(ShareController.Result.DISMISSED)
}
......@@ -132,21 +134,20 @@ class DefaultShareController(
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
fun showSuccess() {
snackbarPresenter.present(
getSuccessMessage(),
Snackbar.LENGTH_SHORT
)
snackbar.apply {
setText(getSuccessMessage())
setLength(Snackbar.LENGTH_SHORT)
show()
}
}
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
fun showFailureWithRetryOption(operation: () -> Unit) {
snackbarPresenter.present(
text = context.getString(R.string.sync_sent_tab_error_snackbar),
length = Snackbar.LENGTH_LONG,
action = operation,
actionName = context.getString(R.string.sync_sent_tab_error_snackbar_action),
isError = true
)
snackbar.setText(context.getString(R.string.sync_sent_tab_error_snackbar))
snackbar.setLength(Snackbar.LENGTH_LONG)
snackbar.setAction(context.getString(R.string.sync_sent_tab_error_snackbar_action), operation)
snackbar.setAppropriateBackground(true)
snackbar.show()
}
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
......
......@@ -21,7 +21,7 @@ import mozilla.components.browser.state.selector.findTabOrCustomTab
import mozilla.components.concept.engine.prompt.PromptRequest
import mozilla.components.feature.accounts.push.SendTabUseCases
import org.mozilla.fenix.R
import org.mozilla.fenix.components.BrowserSnackbarPresenter
import org.mozilla.fenix.components.FenixSnackbar
import org.mozilla.fenix.ext.getRootView
import org.mozilla.fenix.ext.requireComponents
......@@ -65,7 +65,7 @@ class ShareFragment : AppCompatDialogFragment() {
DefaultShareController(
context = requireContext(),
shareData = shareData,
snackbarPresenter = BrowserSnackbarPresenter(requireActivity().getRootView()!!),
snackbar = FenixSnackbar.makeWithToolbarPadding(requireActivity().getRootView()!!),
navController = findNavController(),
sendTabUseCases = SendTabUseCases(accountManager)
) { result ->
......
......@@ -444,6 +444,10 @@
android:id="@+id/turnOnSyncFragment"
android:name="org.mozilla.fenix.settings.account.TurnOnSyncFragment"
android:label="@string/preferences_sync">
<argument
android:name="padSnackbar"
app:argType="boolean"
android:defaultValue="false" />
<action
android:id="@+id/action_turnOnSyncFragment_to_pairFragment"
app:destination="@id/pairFragment" />
......@@ -555,7 +559,8 @@
android:id="@+id/action_shareFragment_to_turnOnSyncFragment"
app:destination="@+id/turnOnSyncFragment"
app:popUpTo="@id/shareFragment"
app:popUpToInclusive="true" />
app:popUpToInclusive="true" >
</action>
<action
android:id="@+id/action_shareFragment_to_accountProblemFragment"
app:destination="@id/accountProblemFragment" />
......
......@@ -29,7 +29,7 @@ import org.mozilla.fenix.BrowserDirection
import org.mozilla.fenix.HomeActivity
import org.mozilla.fenix.R
import org.mozilla.fenix.browser.browsingmode.BrowsingMode
import org.mozilla.fenix.components.BrowserSnackbarPresenter
import org.mozilla.fenix.components.FenixSnackbar
import org.mozilla.fenix.components.Services
import org.mozilla.fenix.components.metrics.Event
import org.mozilla.fenix.ext.components
......@@ -41,7 +41,7 @@ class BookmarkControllerTest {
private val context: Context = mockk(relaxed = true)
private val navController: NavController = mockk(relaxed = true)
private val snackbarPresenter: BrowserSnackbarPresenter = mockk(relaxed = true)
private val snackbar: FenixSnackbar = mockk(relaxed = true)
private val deleteBookmarkNodes: (Set<BookmarkNode>, Event) -> Unit = mockk(relaxed = true)
private val invokePendingDeletion: () -> Unit = mockk(relaxed = true)
......@@ -90,7 +90,7 @@ class BookmarkControllerTest {
controller = DefaultBookmarkController(
context = homeActivity,
navController = navController,
snackbarPresenter = snackbarPresenter,
snackbar = snackbar,
deleteBookmarkNodes = deleteBookmarkNodes,
invokePendingDeletion = invokePendingDeletion
)
......@@ -165,7 +165,8 @@ class BookmarkControllerTest {
controller.handleBookmarkSelected(root)