Skip to content
This repository has been archived by the owner on Feb 20, 2023. It is now read-only.

For #2834: Delete all Private Tabs redesign #4787

Merged
merged 1 commit into from
Aug 20, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions app/src/androidTest/java/org/mozilla/fenix/ui/HomeScreenTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ import org.junit.Test
import org.mozilla.fenix.helpers.HomeActivityTestRule

import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.uiautomator.By
import androidx.test.uiautomator.Until
import org.mozilla.fenix.helpers.TestAssetHelper.waitingTime
import org.mozilla.fenix.ui.robots.PRIVATE_SESSION_MESSAGE
import org.mozilla.fenix.ui.robots.homeScreen

/**
Expand Down Expand Up @@ -88,4 +92,45 @@ class HomeScreenTest {
verifyStartBrowsingButton()
}
}

@Test
fun privateModeScreenItemsTest() {
homeScreen { }.dismissOnboarding()
homeScreen { }.turnOnPrivateMode()

homeScreen {
verifyHomeScreen()
verifyNavigationToolbar()
verifyHomePrivateBrowsingButton()
verifyHomeMenu()
verifyHomeWordmark()
verifyAddTabButton()
verifyShareTabsButton(visible = false)
verifyCloseTabsButton(visible = false)
verifyPrivateSessionHeader()
verifyPrivateSessionMessage(visible = true)
verifyHomeToolbar()
verifyHomeComponent()
}

homeScreen { }.addNewTab()

homeScreen {
// To deal with the race condition where multiple "add tab" buttons are present,
// we need to wait until previous HomeFragment View objects are gone.
mDevice.wait(Until.gone(By.text(PRIVATE_SESSION_MESSAGE)), waitingTime)
verifyHomeScreen()
verifyNavigationToolbar()
verifyHomePrivateBrowsingButton()
verifyHomeMenu()
verifyHomeWordmark()
verifyAddTabButton()
verifyShareTabsButton(visible = true)
verifyCloseTabsButton(visible = true)
verifyPrivateSessionHeader()
verifyPrivateSessionMessage(visible = false)
verifyHomeToolbar()
verifyHomeComponent()
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ package org.mozilla.fenix.ui.robots

import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.matcher.ViewMatchers.withContentDescription
import androidx.test.espresso.matcher.ViewMatchers.withId
import androidx.test.espresso.matcher.ViewMatchers.withText
import androidx.test.platform.app.InstrumentationRegistry
Expand Down Expand Up @@ -48,6 +49,15 @@ class BrowserRobot {
NavigationToolbarRobot().interact()
return NavigationToolbarRobot.Transition()
}

fun openHomeScreen(interact: HomeScreenRobot.() -> Unit): HomeScreenRobot.Transition {
mDevice.waitForIdle()

tabsCounter().click()

HomeScreenRobot().interact()
return HomeScreenRobot.Transition()
}
}
}

Expand All @@ -57,3 +67,5 @@ fun browserScreen(interact: BrowserRobot.() -> Unit): BrowserRobot.Transition {
}

fun navURLBar() = onView(withId(R.id.mozac_browser_toolbar_url_view))

private fun tabsCounter() = onView(withContentDescription("Tabs"))
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ package org.mozilla.fenix.ui.robots

import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.action.ViewActions.click
import androidx.test.espresso.assertion.ViewAssertions.doesNotExist
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.matcher.ViewMatchers
import androidx.test.espresso.matcher.ViewMatchers.Visibility
Expand Down Expand Up @@ -65,6 +66,12 @@ class HomeScreenRobot {
fun verifyPrivacyNoticeButton() = assertPrivacyNoticeButton()
fun verifyStartBrowsingButton() = assertStartBrowsingButton()

// Private mode elements
fun verifyPrivateSessionHeader() = assertPrivateSessionHeader()
fun verifyPrivateSessionMessage(visible: Boolean = true) = assertPrivateSessionMessage(visible)
fun verifyShareTabsButton(visible: Boolean = true) = assertShareTabsButton(visible)
fun verifyCloseTabsButton(visible: Boolean = true) = assertCloseTabsButton(visible)

private fun scrollToElementByText(text: String): UiScrollable {
val appView = UiScrollable(UiSelector().scrollable(true))
appView.scrollTextIntoView(text)
Expand Down Expand Up @@ -97,6 +104,15 @@ class HomeScreenRobot {
fun dismissOnboarding() {
openThreeDotMenu { }.openSettings { }.goBack { }
}

fun addNewTab() {
openSearch { }.openBrowser { }.openHomeScreen { }
}

fun turnOnPrivateMode() {
onView(ViewMatchers.withResourceName("privateBrowsingButton"))
.perform(click())
}
}
}

Expand Down Expand Up @@ -262,3 +278,29 @@ private fun assertPrivacyNoticeButton() =
private fun assertStartBrowsingButton() =
onView(CoreMatchers.allOf(ViewMatchers.withText("Start browsing")))
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))

// Private mode elements
private fun assertPrivateSessionHeader() =
onView(CoreMatchers.allOf(ViewMatchers.withText("Private session")))
.check(matches(withEffectiveVisibility(Visibility.VISIBLE)))

const val PRIVATE_SESSION_MESSAGE = "Firefox Preview clears your search and browsing history " +
"when you quit the app or close all private tabs. While this doesn’t make you anonymous to websites or " +
"your internet service provider, it makes it easier to keep what you do online private from anyone else " +
"who uses this device.\n\nCommon myths about private browsing"

private fun assertPrivateSessionMessage(visible: Boolean) =
onView(CoreMatchers.allOf(ViewMatchers.withText(PRIVATE_SESSION_MESSAGE)))
.check(
if (visible) matches(withEffectiveVisibility(Visibility.VISIBLE)) else doesNotExist()
)

private fun assertShareTabsButton(visible: Boolean) =
onView(CoreMatchers.allOf(ViewMatchers.withResourceName("share_tabs_button")))
.check(matches(withEffectiveVisibility(visibleOrGone(visible))))

private fun assertCloseTabsButton(visible: Boolean) =
onView(CoreMatchers.allOf(ViewMatchers.withResourceName("close_tabs_button")))
.check(matches(withEffectiveVisibility(visibleOrGone(visible))))

private fun visibleOrGone(visibility: Boolean) = if (visibility) Visibility.VISIBLE else Visibility.GONE
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,14 @@ class SearchRobot {

class Transition {
val mDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())

fun openBrowser(interact: BrowserRobot.() -> Unit): BrowserRobot.Transition {
mDevice.waitForIdle()
browserToolbarEditView().perform(typeText("Mozilla\n"))

BrowserRobot().interact()
return BrowserRobot.Transition()
}
}
}

Expand Down
15 changes: 11 additions & 4 deletions app/src/main/java/org/mozilla/fenix/home/HomeFragment.kt
Original file line number Diff line number Diff line change
Expand Up @@ -347,14 +347,15 @@ class HomeFragment : Fragment(), AccountObserver {
}
is TabAction.CloseAll -> {
if (pendingSessionDeletion?.deletionJob == null) removeAllTabsWithUndo(
sessionManager.filteredSessions(action.private)
sessionManager.filteredSessions(action.private),
action.private
) else {
pendingSessionDeletion?.deletionJob?.let {
viewLifecycleOwner.lifecycleScope.launch {
it.invoke()
}.invokeOnCompletion {
pendingSessionDeletion = null
removeAllTabsWithUndo(sessionManager.filteredSessions(action.private))
removeAllTabsWithUndo(sessionManager.filteredSessions(action.private), action.private)
}
}
}
Expand Down Expand Up @@ -581,7 +582,7 @@ class HomeFragment : Fragment(), AccountObserver {
}
}

private fun removeAllTabsWithUndo(listOfSessionsToDelete: List<Session>) {
private fun removeAllTabsWithUndo(listOfSessionsToDelete: List<Session>, private: Boolean) {
val sessionManager = requireComponents.core.sessionManager

getManagedEmitter<SessionControlChange>().onNext(SessionControlChange.TabsChange(listOf()))
Expand All @@ -593,9 +594,15 @@ class HomeFragment : Fragment(), AccountObserver {
}
deleteAllSessionsJob = deleteOperation

val snackbarMessage = if (private) {
getString(R.string.snackbar_private_tabs_deleted)
} else {
getString(R.string.snackbar_tab_deleted)
}

viewLifecycleOwner.lifecycleScope.allowUndo(
view!!,
getString(R.string.snackbar_tabs_deleted),
snackbarMessage,
getString(R.string.snackbar_deleted_undo), {
deleteAllSessionsJob = null
emitSessionChanges()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package org.mozilla.fenix.home.sessioncontrol.viewholders

import android.content.Context
import android.view.View
import androidx.core.view.isVisible
import androidx.recyclerview.widget.RecyclerView
import io.reactivex.Observer
import kotlinx.android.synthetic.main.tab_header.view.*
Expand Down Expand Up @@ -46,6 +47,18 @@ class TabHeaderViewHolder(
}
}

share_tabs_button.run {
setOnClickListener {
actionEmitter.onNext(TabAction.ShareTabs)
}
}

close_tabs_button.run {
setOnClickListener {
actionEmitter.onNext(TabAction.CloseAll(true))
}
}

tabs_overflow_button.run {
setOnClickListener {
tabsMenu.menuBuilder
Expand All @@ -63,7 +76,9 @@ class TabHeaderViewHolder(
val headerTextResourceId =
if (isPrivate) R.string.tabs_header_private_title else R.string.tab_header_label
view.header_text.text = view.context.getString(headerTextResourceId)
view.tabs_overflow_button.visibility = if (hasTabs) View.VISIBLE else View.GONE
view.share_tabs_button.isVisible = isPrivate && hasTabs
view.close_tabs_button.isVisible = isPrivate && hasTabs
view.tabs_overflow_button.isVisible = !isPrivate && hasTabs
}

class TabHeaderMenu(
Expand Down
7 changes: 0 additions & 7 deletions app/src/main/res/layout/private_browsing_description.xml
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,6 @@
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:orientation="vertical">
<TextView
android:textAppearance="@style/TextAppearance.MaterialComponents.Headline6"
android:textColor="?primaryText"
android:text="@string/private_browsing_title"
android:layout_marginBottom="8dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="@+id/private_session_description"
android:layout_width="match_parent"
Expand Down
14 changes: 14 additions & 0 deletions app/src/main/res/layout/tab_header.xml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,20 @@
android:contentDescription="@string/add_tab"
android:src="@drawable/ic_new"/>

<ImageButton
android:id="@+id/share_tabs_button"
android:layout_width="48dp"
android:layout_height="48dp"
android:background="?android:attr/selectableItemBackgroundBorderless"
android:src="@drawable/ic_hollow_share"/>

<ImageButton
android:id="@+id/close_tabs_button"
android:layout_width="48dp"
android:layout_height="48dp"
android:background="?android:attr/selectableItemBackgroundBorderless"
android:src="@drawable/ic_delete"/>

<ImageButton
android:id="@+id/tabs_overflow_button"
android:layout_width="48dp"
Expand Down
2 changes: 2 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -572,6 +572,8 @@
<string name="snackbar_tab_deleted">Tab deleted</string>
<!-- Text shown in snackbar when user deletes all tabs -->
<string name="snackbar_tabs_deleted">Tabs deleted</string>
<!-- Text shown in snackbar when user deletes all private tabs -->
<string name="snackbar_private_tabs_deleted">Private tabs deleted</string>
<!-- Text for action to undo deleting a tab or collection shown in snackbar -->
<string name="snackbar_deleted_undo">UNDO</string>
<!-- QR code scanner prompt which appears after scanning a code, but before navigating to it
Expand Down