1
0
Fork 0

Issue #9128 & #9222 & #9499: Refactors snackbar creation and fixes placement (#9628)

master
Sawyer Blatz 2020-04-02 12:30:13 -07:00 committed by GitHub
parent 8c43935ba3
commit e3ed7ed268
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
22 changed files with 174 additions and 52 deletions

View File

@ -26,7 +26,11 @@ internal fun getFormattedAmount(amount: Int): String {
* @param text The text to display in the [FenixSnackbar]. * @param text The text to display in the [FenixSnackbar].
*/ */
internal fun showSnackBar(view: View, text: String) { internal fun showSnackBar(view: View, text: String) {
FenixSnackbar.make(view, FenixSnackbar.LENGTH_SHORT) FenixSnackbar.make(
view = view,
duration = FenixSnackbar.LENGTH_SHORT,
isDisplayedOnBrowserFragment = true
)
.setText(text) .setText(text)
.show() .show()
} }

View File

@ -305,7 +305,11 @@ abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler, Session
download = download, download = download,
tryAgain = downloadFeature::tryAgain, tryAgain = downloadFeature::tryAgain,
onCannotOpenFile = { onCannotOpenFile = {
FenixSnackbar.makeWithToolbarPadding(view, Snackbar.LENGTH_SHORT) FenixSnackbar.make(
view = view,
duration = Snackbar.LENGTH_SHORT,
isDisplayedOnBrowserFragment = true
)
.setText(context.getString(R.string.mozac_feature_downloads_could_not_open_file)) .setText(context.getString(R.string.mozac_feature_downloads_could_not_open_file))
.show() .show()
} }
@ -422,7 +426,11 @@ abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler, Session
customTabSessionId customTabSessionId
) { inFullScreen -> ) { inFullScreen ->
if (inFullScreen) { if (inFullScreen) {
FenixSnackbar.make(view.rootView, Snackbar.LENGTH_SHORT) FenixSnackbar.make(
view = view,
duration = Snackbar.LENGTH_SHORT,
isDisplayedOnBrowserFragment = true
)
.setText(getString(R.string.full_screen_notification)) .setText(getString(R.string.full_screen_notification))
.show() .show()
activity?.enterToImmersiveMode() activity?.enterToImmersiveMode()
@ -785,7 +793,11 @@ abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler, Session
requireComponents.analytics.metrics.track(Event.AddBookmark) requireComponents.analytics.metrics.track(Event.AddBookmark)
view?.let { view -> view?.let { view ->
FenixSnackbar.makeWithToolbarPadding(view, FenixSnackbar.LENGTH_LONG) FenixSnackbar.make(
view = view,
duration = FenixSnackbar.LENGTH_LONG,
isDisplayedOnBrowserFragment = true
)
.setText(getString(R.string.bookmark_saved_snackbar)) .setText(getString(R.string.bookmark_saved_snackbar))
.setAction(getString(R.string.edit_bookmark_snackbar_action)) { .setAction(getString(R.string.edit_bookmark_snackbar_action)) {
nav( nav(

View File

@ -210,7 +210,11 @@ class BrowserFragment : BaseBrowserFragment(), UserInteractionHandler {
private fun showTabSavedToCollectionSnackbar() { private fun showTabSavedToCollectionSnackbar() {
view?.let { view -> view?.let { view ->
FenixSnackbar.makeWithToolbarPadding(view, Snackbar.LENGTH_SHORT) FenixSnackbar.make(
view = view,
duration = Snackbar.LENGTH_SHORT,
isDisplayedOnBrowserFragment = true
)
.setText(view.context.getString(R.string.create_collection_tab_saved)) .setText(view.context.getString(R.string.create_collection_tab_saved))
.show() .show()
} }

View File

@ -19,12 +19,19 @@ class FenixSnackbarDelegate(val view: View) :
listener: ((v: View) -> Unit)? listener: ((v: View) -> Unit)?
) { ) {
if (listener != null && action != 0) { if (listener != null && action != 0) {
FenixSnackbar.makeWithToolbarPadding(view, duration = FenixSnackbar.LENGTH_SHORT) FenixSnackbar.make(
view = view,
duration = FenixSnackbar.LENGTH_SHORT,
isDisplayedOnBrowserFragment = true
)
.setText(view.context.getString(text)) .setText(view.context.getString(text))
.setAction(view.context.getString(action)) { listener.invoke(view) } .setAction(view.context.getString(action)) { listener.invoke(view) }
.show() .show()
} else { } else {
FenixSnackbar.makeWithToolbarPadding(view, duration = FenixSnackbar.LENGTH_SHORT) FenixSnackbar.make(view,
duration = FenixSnackbar.LENGTH_SHORT,
isDisplayedOnBrowserFragment = true
)
.setText(view.context.getString(text)) .setText(view.context.getString(text))
.show() .show()
} }

View File

@ -10,12 +10,14 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.FrameLayout import android.widget.FrameLayout
import androidx.appcompat.content.res.AppCompatResources import androidx.appcompat.content.res.AppCompatResources
import androidx.appcompat.widget.ContentFrameLayout
import androidx.coordinatorlayout.widget.CoordinatorLayout import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.core.widget.TextViewCompat import androidx.core.widget.TextViewCompat
import com.google.android.material.snackbar.BaseTransientBottomBar import com.google.android.material.snackbar.BaseTransientBottomBar
import com.google.android.material.snackbar.ContentViewCallback import com.google.android.material.snackbar.ContentViewCallback
import com.google.android.material.snackbar.Snackbar import com.google.android.material.snackbar.Snackbar
import kotlinx.android.synthetic.main.fenix_snackbar.view.* import kotlinx.android.synthetic.main.fenix_snackbar.view.*
import org.mozilla.fenix.FeatureFlags
import org.mozilla.fenix.R import org.mozilla.fenix.R
import org.mozilla.fenix.ext.increaseTapArea import org.mozilla.fenix.ext.increaseTapArea
import org.mozilla.fenix.ext.settings import org.mozilla.fenix.ext.settings
@ -86,8 +88,20 @@ class FenixSnackbar private constructor(
/** /**
* Display a snackbar in the given view with duration and proper normal/error styling. * Display a snackbar in the given view with duration and proper normal/error styling.
* Note: Duration is overriden for users with accessibility settings enabled * Note: Duration is overriden for users with accessibility settings enabled
* displayedOnFragmentWithToolbar should be true for all snackbars that will end up
* being displayed on a BrowserFragment and must be true in cases where the fragment is
* going to pop TO BrowserFragment (e.g. EditBookmarkFragment, ShareFragment)
*
* Suppressing ComplexCondition. Yes it's unfortunately complex but that's the nature
* of the snackbar handling by Android. It will be simpler once dynamic toolbar is always on.
*/ */
fun make(view: View, duration: Int, isError: Boolean = false): FenixSnackbar { @Suppress("ComplexCondition")
fun make(
view: View,
duration: Int = LENGTH_LONG,
isError: Boolean = false,
isDisplayedOnBrowserFragment: Boolean
): FenixSnackbar {
val parent = findSuitableParent(view) ?: run { val parent = findSuitableParent(view) ?: run {
throw IllegalArgumentException( throw IllegalArgumentException(
"No suitable parent found from the given view. Please provide a valid view." "No suitable parent found from the given view. Please provide a valid view."
@ -104,30 +118,31 @@ class FenixSnackbar private constructor(
} }
val callback = FenixSnackbarCallback(content) val callback = FenixSnackbarCallback(content)
return FenixSnackbar(parent, content, callback, isError).also { val shouldUseBottomToolbar = view.context.settings().shouldUseBottomToolbar
it.duration = durationOrAccessibleDuration val toolbarHeight = view.context.resources
}
}
/**
* Considers BrowserToolbar for padding when making snackbar. The vast majority of the time
* you will want to pass in `fragment.view`.
*/
fun makeWithToolbarPadding(
fragmentView: View,
duration: Int = LENGTH_LONG,
isError: Boolean = false
): FenixSnackbar {
val shouldUseBottomToolbar = fragmentView.context.settings().shouldUseBottomToolbar
val toolbarHeight = fragmentView.context.resources
.getDimensionPixelSize(R.dimen.browser_toolbar_height) .getDimensionPixelSize(R.dimen.browser_toolbar_height)
return make(fragmentView, duration, isError).apply { return FenixSnackbar(parent, content, callback, isError).also {
this.view.setPadding( it.duration = durationOrAccessibleDuration
it.view.setPadding(
0, 0,
0, 0,
0, 0,
if (shouldUseBottomToolbar) toolbarHeight else 0 if (
isDisplayedOnBrowserFragment &&
shouldUseBottomToolbar &&
// If the view passed in is a ContentFrameLayout, it does not matter
// if the user has a dynamicBottomToolbar or not, as the Android system
// can't intelligently position the snackbar on the upper most view.
// Ideally we should not pass ContentFrameLayout in, but it's the only
// way to display snackbars through a fragment transition.
(!FeatureFlags.dynamicBottomToolbar || view is ContentFrameLayout)
) {
toolbarHeight
} else {
0
}
) )
} }
} }

View File

@ -166,7 +166,11 @@ class DefaultBrowserToolbarController(
topSiteStorage.addTopSite(it.title, it.url) topSiteStorage.addTopSite(it.title, it.url)
} }
MainScope().launch { MainScope().launch {
FenixSnackbar.makeWithToolbarPadding(swipeRefresh, Snackbar.LENGTH_SHORT) FenixSnackbar.make(
view = swipeRefresh,
duration = Snackbar.LENGTH_SHORT,
isDisplayedOnBrowserFragment = true
)
.setText( .setText(
swipeRefresh.context.getString(R.string.snackbar_added_to_top_sites) swipeRefresh.context.getString(R.string.snackbar_added_to_top_sites)
) )
@ -258,7 +262,11 @@ class DefaultBrowserToolbarController(
// browsing data on quit" is activated). After the deletion is over, the snackbar // browsing data on quit" is activated). After the deletion is over, the snackbar
// is dismissed. // is dismissed.
val snackbar: FenixSnackbar? = activity.getRootView()?.let { v -> val snackbar: FenixSnackbar? = activity.getRootView()?.let { v ->
FenixSnackbar.makeWithToolbarPadding(v) FenixSnackbar.make(
view = v,
duration = Snackbar.LENGTH_LONG,
isDisplayedOnBrowserFragment = true
)
.setText(v.context.getString(R.string.deleting_browsing_data_in_progress)) .setText(v.context.getString(R.string.deleting_browsing_data_in_progress))
} }

View File

@ -108,9 +108,10 @@ class BrowserToolbarView(
clipboard.text = selectedSession?.url clipboard.text = selectedSession?.url
} }
FenixSnackbar.makeWithToolbarPadding( FenixSnackbar.make(
view.rootView.findViewById(android.R.id.content), view = view,
Snackbar.LENGTH_SHORT duration = Snackbar.LENGTH_SHORT,
isDisplayedOnBrowserFragment = true
) )
.setText(view.context.getString(R.string.browser_toolbar_url_copied_to_clipboard_snackbar)) .setText(view.context.getString(R.string.browser_toolbar_url_copied_to_clipboard_snackbar))
.show() .show()

View File

@ -85,7 +85,11 @@ class ExternalAppBrowserFragment : BaseBrowserFragment(), UserInteractionHandler
customTabSessionId customTabSessionId
) { exception -> ) { exception ->
components.analytics.crashReporter.submitCaughtException(exception) components.analytics.crashReporter.submitCaughtException(exception)
FenixSnackbar.make(view.swipeRefresh, FenixSnackbar.LENGTH_LONG).apply { FenixSnackbar.make(
view = view.swipeRefresh,
duration = FenixSnackbar.LENGTH_LONG,
isDisplayedOnBrowserFragment = true
).apply {
setText(resources.getString(R.string.unknown_scheme_error_message)) setText(resources.getString(R.string.unknown_scheme_error_message))
setAppropriateBackground(true) setAppropriateBackground(true)
}.show() }.show()

View File

@ -384,7 +384,10 @@ class HomeFragment : Fragment() {
override fun onAuthenticated(account: OAuthAccount, authType: AuthType) { override fun onAuthenticated(account: OAuthAccount, authType: AuthType) {
if (authType != AuthType.Existing) { if (authType != AuthType.Existing) {
view?.let { view?.let {
FenixSnackbar.make(it, Snackbar.LENGTH_SHORT) FenixSnackbar.make(view = it,
duration = Snackbar.LENGTH_SHORT,
isDisplayedOnBrowserFragment = false
)
.setText(it.context.getString(R.string.onboarding_firefox_account_sync_is_on)) .setText(it.context.getString(R.string.onboarding_firefox_account_sync_is_on))
.setAnchorView(toolbarLayout) .setAnchorView(toolbarLayout)
.show() .show()
@ -589,7 +592,7 @@ class HomeFragment : Fragment() {
nav(R.id.homeFragment, directions) nav(R.id.homeFragment, directions)
} }
@SuppressWarnings("ComplexMethod") @SuppressWarnings("ComplexMethod", "LongMethod")
private fun createHomeMenu(context: Context, menuButtonView: WeakReference<MenuButton>) = HomeMenu( private fun createHomeMenu(context: Context, menuButtonView: WeakReference<MenuButton>) = HomeMenu(
this, this,
context, context,
@ -649,7 +652,11 @@ class HomeFragment : Fragment() {
deleteAndQuit( deleteAndQuit(
activity, activity,
lifecycleScope, lifecycleScope,
view?.let { view -> FenixSnackbar.makeWithToolbarPadding(view) } view?.let { view -> FenixSnackbar.make(
view = view,
isDisplayedOnBrowserFragment = false
)
}
) )
} }
HomeMenu.Item.Sync -> { HomeMenu.Item.Sync -> {
@ -876,7 +883,10 @@ class HomeFragment : Fragment() {
} else { } else {
R.string.create_collection_tab_saved R.string.create_collection_tab_saved
} }
FenixSnackbar.make(view, Snackbar.LENGTH_LONG) FenixSnackbar.make(view = view,
duration = Snackbar.LENGTH_LONG,
isDisplayedOnBrowserFragment = false
)
.setText(view.context.getString(stringRes)) .setText(view.context.getString(stringRes))
.setAnchorView(snackbarAnchorView) .setAnchorView(snackbarAnchorView)
.show() .show()
@ -887,7 +897,11 @@ class HomeFragment : Fragment() {
private fun showRenamedSnackbar() { private fun showRenamedSnackbar() {
view?.let { view -> view?.let { view ->
val string = view.context.getString(R.string.snackbar_collection_renamed) val string = view.context.getString(R.string.snackbar_collection_renamed)
FenixSnackbar.make(view, Snackbar.LENGTH_LONG) FenixSnackbar.make(
view = view,
duration = Snackbar.LENGTH_LONG,
isDisplayedOnBrowserFragment = false
)
.setText(string) .setText(string)
.setAnchorView(snackbarAnchorView) .setAnchorView(snackbarAnchorView)
.show() .show()

View File

@ -39,7 +39,11 @@ class OnboardingAutomaticSignInViewHolder(private val view: View) : RecyclerView
R.string.onboarding_firefox_account_auto_signin_confirm R.string.onboarding_firefox_account_auto_signin_confirm
) )
it.turn_on_sync_button.isEnabled = true it.turn_on_sync_button.isEnabled = true
FenixSnackbar.make(it, Snackbar.LENGTH_SHORT).setText( FenixSnackbar.make(
view = it,
duration = Snackbar.LENGTH_SHORT,
isDisplayedOnBrowserFragment = false
).setText(
it.context.getString(R.string.onboarding_firefox_account_automatic_signin_failed) it.context.getString(R.string.onboarding_firefox_account_automatic_signin_failed)
).show() ).show()
} }

View File

@ -88,7 +88,11 @@ class BookmarkFragment : LibraryPageFragment<BookmarkNode>(), UserInteractionHan
bookmarksController = DefaultBookmarkController( bookmarksController = DefaultBookmarkController(
context = context!!, context = context!!,
navController = findNavController(), navController = findNavController(),
snackbar = FenixSnackbar.make(view, FenixSnackbar.LENGTH_LONG), snackbar = FenixSnackbar.make(
view = view,
duration = FenixSnackbar.LENGTH_LONG,
isDisplayedOnBrowserFragment = false
),
deleteBookmarkNodes = ::deleteMulti, deleteBookmarkNodes = ::deleteMulti,
invokePendingDeletion = ::invokePendingDeletion invokePendingDeletion = ::invokePendingDeletion
), ),

View File

@ -164,7 +164,10 @@ class EditBookmarkFragment : Fragment(R.layout.fragment_edit_bookmark) {
.popBackStack() .popBackStack()
bookmarkNode?.let { bookmark -> bookmarkNode?.let { bookmark ->
FenixSnackbar.makeWithToolbarPadding(activity.getRootView()!!) FenixSnackbar.make(
view = activity.getRootView()!!,
isDisplayedOnBrowserFragment = true
)
.setText( .setText(
getString( getString(
R.string.bookmark_deletion_snackbar_message, R.string.bookmark_deletion_snackbar_message,

View File

@ -64,7 +64,11 @@ class HistoryFragment : LibraryPageFragment<HistoryItem>(), UserInteractionHandl
historyStore, historyStore,
findNavController(), findNavController(),
resources, resources,
FenixSnackbar.make(view, FenixSnackbar.LENGTH_LONG), FenixSnackbar.make(
view = view,
duration = FenixSnackbar.LENGTH_LONG,
isDisplayedOnBrowserFragment = false
),
activity?.getSystemService(CLIPBOARD_SERVICE) as ClipboardManager, activity?.getSystemService(CLIPBOARD_SERVICE) as ClipboardManager,
::openItem, ::openItem,
::displayDeleteAllDialog, ::displayDeleteAllDialog,

View File

@ -310,7 +310,11 @@ class AccountSettingsFragment : PreferenceFragmentCompat() {
private fun getChangeListenerForDeviceName(): Preference.OnPreferenceChangeListener { private fun getChangeListenerForDeviceName(): Preference.OnPreferenceChangeListener {
return Preference.OnPreferenceChangeListener { _, newValue -> return Preference.OnPreferenceChangeListener { _, newValue ->
accountSettingsInteractor.onChangeDeviceName(newValue as String) { accountSettingsInteractor.onChangeDeviceName(newValue as String) {
FenixSnackbar.make(view!!, FenixSnackbar.LENGTH_LONG) FenixSnackbar.make(
view = view!!,
duration = FenixSnackbar.LENGTH_LONG,
isDisplayedOnBrowserFragment = false
)
.setText(getString(R.string.empty_device_name_error)) .setText(getString(R.string.empty_device_name_error))
.show() .show()
} }

View File

@ -81,11 +81,19 @@ class TurnOnSyncFragment : Fragment(), AccountObserver {
// Since the snackbar can be presented in BrowserFragment or in SettingsFragment we must // Since the snackbar can be presented in BrowserFragment or in SettingsFragment we must
// base our display method on the padSnackbar argument // base our display method on the padSnackbar argument
if (args.padSnackbar) { if (args.padSnackbar) {
FenixSnackbar.makeWithToolbarPadding(requireView(), snackbarLength) FenixSnackbar.make(
view = requireView(),
duration = snackbarLength,
isDisplayedOnBrowserFragment = true
)
.setText(snackbarText) .setText(snackbarText)
.show() .show()
} else { } else {
FenixSnackbar.make(requireView(), snackbarLength) FenixSnackbar.make(
view = requireView(),
duration = snackbarLength,
isDisplayedOnBrowserFragment = false
)
.setText(snackbarText) .setText(snackbarText)
.show() .show()
} }

View File

@ -136,7 +136,11 @@ class DeleteBrowsingDataFragment : Fragment(R.layout.fragment_delete_browsing_da
updateItemCounts() updateItemCounts()
FenixSnackbar.makeWithToolbarPadding(requireView(), FenixSnackbar.LENGTH_SHORT) FenixSnackbar.make(
view = requireView(),
duration = FenixSnackbar.LENGTH_SHORT,
isDisplayedOnBrowserFragment = true
)
.setText(resources.getString(R.string.preferences_delete_browsing_data_snackbar)) .setText(resources.getString(R.string.preferences_delete_browsing_data_snackbar))
.show() .show()

View File

@ -181,7 +181,11 @@ class SavedLoginSiteInfoFragment : Fragment(R.layout.fragment_saved_login_site_i
private fun showCopiedSnackbar(copiedItem: String) { private fun showCopiedSnackbar(copiedItem: String) {
view?.let { view?.let {
FenixSnackbar.make(it, Snackbar.LENGTH_SHORT).setText(copiedItem).show() FenixSnackbar.make(
view = it,
duration = Snackbar.LENGTH_SHORT,
isDisplayedOnBrowserFragment = false
).setText(copiedItem).show()
} }
} }
} }

View File

@ -208,7 +208,10 @@ class AddSearchEngineFragment : Fragment(), CompoundButton.OnCheckedChangeListen
.getString(R.string.search_add_custom_engine_success_message, name) .getString(R.string.search_add_custom_engine_success_message, name)
view?.also { view?.also {
FenixSnackbar.make(it, FenixSnackbar.LENGTH_SHORT) FenixSnackbar.make(view = it,
duration = FenixSnackbar.LENGTH_SHORT,
isDisplayedOnBrowserFragment = false
)
.setText(successMessage) .setText(successMessage)
.show() .show()
} }

View File

@ -154,7 +154,11 @@ class EditCustomSearchEngineFragment : Fragment(R.layout.fragment_add_search_eng
.getString(R.string.search_edit_custom_engine_success_message, name) .getString(R.string.search_edit_custom_engine_success_message, name)
view?.also { view?.also {
FenixSnackbar.make(it, FenixSnackbar.LENGTH_SHORT) FenixSnackbar.make(
view = it,
duration = FenixSnackbar.LENGTH_SHORT,
isDisplayedOnBrowserFragment = false
)
.setText(successMessage) .setText(successMessage)
.show() .show()
} }

View File

@ -67,7 +67,10 @@ class ShareFragment : AppCompatDialogFragment() {
DefaultShareController( DefaultShareController(
context = requireContext(), context = requireContext(),
shareData = shareData, shareData = shareData,
snackbar = FenixSnackbar.makeWithToolbarPadding(requireActivity().getRootView()!!), snackbar = FenixSnackbar.make(
view = requireActivity().getRootView()!!,
isDisplayedOnBrowserFragment = true
),
navController = findNavController(), navController = findNavController(),
sendTabUseCases = SendTabUseCases(accountManager), sendTabUseCases = SendTabUseCases(accountManager),
recentAppsStorage = RecentAppsStorage(requireContext()), recentAppsStorage = RecentAppsStorage(requireContext()),

View File

@ -15,7 +15,11 @@ class ItsNotBrokenSnack(val context: Context) {
context.getRootView() context.getRootView()
rootView?.let { rootView?.let {
FenixSnackbar.make(it, FenixSnackbar.LENGTH_SHORT) FenixSnackbar.make(
view = it,
duration = FenixSnackbar.LENGTH_SHORT,
isDisplayedOnBrowserFragment = false
)
.setText(message.replace("%", issueNumber)) .setText(message.replace("%", issueNumber))
.setAction("Add Tab to Issue") { .setAction("Add Tab to Issue") {
context.components.useCases.tabsUseCases.addTab context.components.useCases.tabsUseCases.addTab

View File

@ -44,7 +44,11 @@ fun CoroutineScope.allowUndo(
fun showUndoSnackbar() { fun showUndoSnackbar() {
val snackbar = FenixSnackbar val snackbar = FenixSnackbar
.make(view, FenixSnackbar.LENGTH_INDEFINITE) .make(
view = view,
duration = FenixSnackbar.LENGTH_INDEFINITE,
isDisplayedOnBrowserFragment = false
)
.setText(message) .setText(message)
.setAnchorView(anchorView) .setAnchorView(anchorView)
.setAction(undoActionTitle) { .setAction(undoActionTitle) {