Skip to content

Commit

Permalink
Issue mozilla-mobile#2783: Add snackbar to collection deletion
Browse files Browse the repository at this point in the history
  • Loading branch information
rocketsroger committed Jul 28, 2021
1 parent e2af42a commit adca17b
Show file tree
Hide file tree
Showing 6 changed files with 42 additions and 82 deletions.
2 changes: 1 addition & 1 deletion app/src/androidTest/java/org/mozilla/fenix/ui/SmokeTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -1011,10 +1011,10 @@ class SmokeTest {
}.expandCollection(collectionName) {
clickCollectionThreeDotButton()
selectDeleteCollection()
confirmDeleteCollection()
}

homeScreen {
verifySnackBarText("Collection deleted")
verifyNoCollectionsText()
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,6 @@ class CollectionRobot {

fun selectDeleteCollection() {
onView(withText("Delete collection")).click()
mDevice.waitNotNull(Until.findObject(By.res("android:id/message")), waitingTime)
}

fun confirmDeleteCollection() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import mozilla.components.browser.state.state.TabSessionState
import mozilla.components.browser.state.state.createTab
import mozilla.components.feature.tab.collections.Tab
import mozilla.components.feature.tab.collections.TabCollection
import mozilla.components.feature.tab.collections.TabCollectionStorage
Expand Down Expand Up @@ -68,6 +69,15 @@ class TabCollectionStorage(
}
}

suspend fun createCollection(tabCollection: TabCollection): Long? {
return withContext(ioScope.coroutineContext) {
val sessions = tabCollection.tabs.map { createTab(url = it.url, title = it.title) }
val id = collectionStorage.createCollection(tabCollection.title, sessions)
notifyObservers { onCollectionCreated(tabCollection.title, sessions, id) }
id
}
}

suspend fun addTabsToCollection(tabCollection: TabCollection, sessions: List<TabSessionState>): Long? {
return withContext(ioScope.coroutineContext) {
val id = collectionStorage.addTabsToCollection(tabCollection, sessions)
Expand Down
55 changes: 24 additions & 31 deletions app/src/main/java/org/mozilla/fenix/home/HomeFragment.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ package org.mozilla.fenix.home

import android.animation.Animator
import android.content.Context
import android.content.DialogInterface
import android.content.res.Configuration
import android.graphics.drawable.BitmapDrawable
import android.graphics.drawable.ColorDrawable
Expand All @@ -22,7 +21,6 @@ import android.widget.Button
import android.widget.LinearLayout
import android.widget.PopupWindow
import androidx.annotation.VisibleForTesting
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.content.res.AppCompatResources
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.constraintlayout.widget.ConstraintSet
Expand Down Expand Up @@ -134,6 +132,7 @@ import org.mozilla.fenix.utils.allowUndo
import org.mozilla.fenix.whatsnew.WhatsNew
import java.lang.ref.WeakReference
import kotlin.math.min
import mozilla.components.feature.tab.collections.ext.invoke

@ExperimentalCoroutinesApi
@Suppress("TooManyFunctions", "LargeClass")
Expand Down Expand Up @@ -311,7 +310,7 @@ class HomeFragment : Fragment() {
viewLifecycleScope = viewLifecycleOwner.lifecycleScope,
hideOnboarding = ::hideOnboardingAndOpenSearch,
registerCollectionStorageObserver = ::registerCollectionStorageObserver,
showDeleteCollectionPrompt = ::showDeleteCollectionPrompt,
removeCollectionWithUndo = ::removeCollectionWithUndo,
showTabTray = ::openTabsTray,
handleSwipedItemDeletionCancel = ::handleSwipedItemDeletionCancel
),
Expand Down Expand Up @@ -706,34 +705,25 @@ class HomeFragment : Fragment() {
}
}

private fun showDeleteCollectionPrompt(
tabCollection: TabCollection,
title: String?,
message: String,
wasSwiped: Boolean,
handleSwipedItemDeletionCancel: () -> Unit
) {
val context = context ?: return
AlertDialog.Builder(context).apply {
setTitle(title)
setMessage(message)
setNegativeButton(R.string.tab_collection_dialog_negative) { dialog: DialogInterface, _ ->
if (wasSwiped) {
handleSwipedItemDeletionCancel()
}
dialog.cancel()
}
setPositiveButton(R.string.tab_collection_dialog_positive) { dialog: DialogInterface, _ ->
// Use fragment's lifecycle; the view may be gone by the time dialog is interacted with.
lifecycleScope.launch(IO) {
context.components.core.tabCollectionStorage.removeCollection(tabCollection)
context.components.analytics.metrics.track(Event.CollectionRemoved)
}.invokeOnCompletion {
dialog.dismiss()
}
}
create()
}.show()
@VisibleForTesting
internal fun removeCollectionWithUndo(tabCollection: TabCollection) {
val snackbarMessage = getString(R.string.snackbar_collection_deleted)

lifecycleScope.allowUndo(
requireView(),
snackbarMessage,
getString(R.string.snackbar_deleted_undo),
{
requireComponents.core.tabCollectionStorage.createCollection(tabCollection)
},
operation = { },
elevation = ELEVATION,
anchorView = null
)

lifecycleScope.launch(IO) {
requireComponents.core.tabCollectionStorage.removeCollection(tabCollection)
}
}

override fun onResume() {
Expand Down Expand Up @@ -1145,5 +1135,8 @@ class HomeFragment : Fragment() {
private const val FADE_ANIM_DURATION = 150L
private const val CFR_WIDTH_DIVIDER = 1.7
private const val CFR_Y_OFFSET = -20

// Elevation for undo toasts
internal const val ELEVATION = 80f
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -197,13 +197,7 @@ class DefaultSessionControlController(
private val viewLifecycleScope: CoroutineScope,
private val hideOnboarding: () -> Unit,
private val registerCollectionStorageObserver: () -> Unit,
private val showDeleteCollectionPrompt: (
tabCollection: TabCollection,
title: String?,
message: String,
wasSwiped: Boolean,
handleSwipedItemDeletionCancel: () -> Unit
) -> Unit,
private val removeCollectionWithUndo: (tabCollection: TabCollection) -> Unit,
private val showTabTray: () -> Unit,
private val handleSwipedItemDeletionCancel: () -> Unit
) : SessionControlController {
Expand Down Expand Up @@ -266,19 +260,7 @@ class DefaultSessionControlController(
metrics.track(Event.CollectionTabRemoved)

if (collection.tabs.size == 1) {
val title = activity.resources.getString(
R.string.delete_tab_and_collection_dialog_title,
collection.title
)
val message =
activity.resources.getString(R.string.delete_tab_and_collection_dialog_message)
showDeleteCollectionPrompt(
collection,
title,
message,
wasSwiped,
handleSwipedItemDeletionCancel
)
removeCollectionWithUndo(collection)
} else {
viewLifecycleScope.launch {
tabCollectionStorage.removeTabFromCollection(collection, tab)
Expand All @@ -296,9 +278,7 @@ class DefaultSessionControlController(
}

override fun handleDeleteCollectionTapped(collection: TabCollection) {
val message =
activity.resources.getString(R.string.tab_collection_dialog_message, collection.title)
showDeleteCollectionPrompt(collection, null, message, false, handleSwipedItemDeletionCancel)
removeCollectionWithUndo(collection)
}

override fun handleOpenInPrivateTabClicked(topSite: TopSite) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,13 +75,7 @@ class DefaultSessionControlControllerTest {
private val registerCollectionStorageObserver: () -> Unit = mockk(relaxed = true)
private val showTabTray: () -> Unit = mockk(relaxed = true)
private val handleSwipedItemDeletionCancel: () -> Unit = mockk(relaxed = true)
private val showDeleteCollectionPrompt: (
tabCollection: TabCollection,
title: String?,
message: String,
wasSwiped: Boolean,
handleSwipedItemDeletionCancel: () -> Unit
) -> Unit = mockk(relaxed = true)
private val removeCollectionWithUndo: (tabCollection: TabCollection) -> Unit = mockk(relaxed = true)
private val settings: Settings = mockk(relaxed = true)
private val analytics: Analytics = mockk(relaxed = true)
private val scope = TestCoroutineScope()
Expand Down Expand Up @@ -161,7 +155,7 @@ class DefaultSessionControlControllerTest {
viewLifecycleScope = scope,
hideOnboarding = hideOnboarding,
registerCollectionStorageObserver = registerCollectionStorageObserver,
showDeleteCollectionPrompt = showDeleteCollectionPrompt,
removeCollectionWithUndo = removeCollectionWithUndo,
showTabTray = showTabTray,
handleSwipedItemDeletionCancel = handleSwipedItemDeletionCancel
))
Expand Down Expand Up @@ -298,15 +292,7 @@ class DefaultSessionControlControllerTest {
controller.handleCollectionRemoveTab(collection, tab, false)

verify { metrics.track(Event.CollectionTabRemoved) }
verify {
showDeleteCollectionPrompt(
collection,
"Delete Collection?",
"Deleting this tab will delete everything.",
false,
handleSwipedItemDeletionCancel
)
}
verify { removeCollectionWithUndo(collection) }
}

@Test
Expand Down Expand Up @@ -344,15 +330,7 @@ class DefaultSessionControlControllerTest {
} returns "Are you sure you want to delete Collection?"

controller.handleDeleteCollectionTapped(collection)
verify {
showDeleteCollectionPrompt(
collection,
null,
"Are you sure you want to delete Collection?",
false,
handleSwipedItemDeletionCancel
)
}
verify { removeCollectionWithUndo(collection) }
}

@Test
Expand Down

0 comments on commit adca17b

Please sign in to comment.