[fenix] For https://github.com/mozilla-mobile/fenix/issues/21791 Adds tab auto-close prompt
parent
1bb5f1479d
commit
0658de464f
@ -0,0 +1,44 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
package org.mozilla.fenix.tabstray.browser
|
||||
|
||||
import androidx.annotation.VisibleForTesting
|
||||
import mozilla.components.browser.state.state.TabSessionState
|
||||
import mozilla.components.browser.state.store.BrowserStore
|
||||
import mozilla.components.concept.tabstray.TabsTray
|
||||
import mozilla.components.feature.tabs.ext.toTabs
|
||||
import org.mozilla.fenix.utils.Settings
|
||||
|
||||
class InactiveTabsAutoCloseDialogController(
|
||||
private val browserStore: BrowserStore,
|
||||
private val settings: Settings,
|
||||
private val tabFilter: (TabSessionState) -> Boolean,
|
||||
private val tray: TabsTray
|
||||
) {
|
||||
/**
|
||||
* Dismiss the auto-close dialog.
|
||||
*/
|
||||
fun close() {
|
||||
settings.hasInactiveTabsAutoCloseDialogBeenDismissed = true
|
||||
refeshInactiveTabsSecion()
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable the auto-close feature with the after a month setting.
|
||||
*/
|
||||
fun enableAutoClosed() {
|
||||
settings.closeTabsAfterOneMonth = true
|
||||
settings.closeTabsAfterOneWeek = false
|
||||
settings.closeTabsAfterOneDay = false
|
||||
settings.manuallyCloseTabs = false
|
||||
refeshInactiveTabsSecion()
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
internal fun refeshInactiveTabsSecion() {
|
||||
val tabs = browserStore.state.toTabs { tabFilter.invoke(it) }
|
||||
tray.updateTabs(tabs)
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
package org.mozilla.fenix.tabstray.browser
|
||||
|
||||
interface InactiveTabsAutoCloseDialogInteractor {
|
||||
fun onCloseClicked()
|
||||
fun onEnabledAutoCloseClicked()
|
||||
}
|
||||
|
||||
class DefaultInactiveTabsAutoCloseDialogInteractor(
|
||||
private val controller: InactiveTabsAutoCloseDialogController
|
||||
) : InactiveTabsAutoCloseDialogInteractor {
|
||||
override fun onCloseClicked() {
|
||||
controller.close()
|
||||
}
|
||||
|
||||
override fun onEnabledAutoCloseClicked() {
|
||||
controller.enableAutoClosed()
|
||||
}
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<stroke
|
||||
android:width="1dp"
|
||||
android:color="?toolbarDivider" />
|
||||
|
||||
<corners android:radius="8dp" />
|
||||
|
||||
<solid android:color="?above" />
|
||||
</shape>
|
@ -0,0 +1,79 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
android:paddingHorizontal="1dp"
|
||||
android:background="@color/photonLightGrey30">
|
||||
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?above"
|
||||
android:clickable="false"
|
||||
android:clipToPadding="false"
|
||||
android:focusable="true"
|
||||
android:padding="16dp">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/banner_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:clickable="false"
|
||||
android:clipToPadding="false"
|
||||
android:background="@drawable/inactive_tab_auto_close_border_background"
|
||||
android:focusable="true"
|
||||
android:padding="16dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/banner_info_message"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="0dp"
|
||||
android:padding="8dp"
|
||||
android:text="@string/tab_tray_inactive_auto_close_title"
|
||||
android:textAppearance="@style/Header14TextStyle"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@+id/close_button"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageButton
|
||||
android:id="@+id/close_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?android:attr/selectableItemBackgroundBorderless"
|
||||
android:contentDescription="@string/tab_tray_inactive_auto_close_button_content_description"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:srcCompat="@drawable/ic_close" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/message"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="0dp"
|
||||
android:padding="8dp"
|
||||
android:text="@string/tab_tray_inactive_auto_close_body"
|
||||
android:textAppearance="@style/Body14TextStyle"
|
||||
app:layout_constraintTop_toBottomOf="@id/banner_info_message"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/action"
|
||||
style="@style/DialogButtonStyleDark"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_marginEnd="3dp"
|
||||
android:textAllCaps="true"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
android:text="@string/tab_tray_inactive_turn_on_auto_close_button"
|
||||
app:layout_constraintTop_toBottomOf="@+id/message" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</FrameLayout>
|
||||
</FrameLayout>
|
@ -0,0 +1,32 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
package org.mozilla.fenix.tabstray.browser
|
||||
|
||||
import io.mockk.mockk
|
||||
import io.mockk.verify
|
||||
import org.junit.Test
|
||||
|
||||
class DefaultInactiveTabsAutoCloseDialogInteractorTest {
|
||||
|
||||
@Test
|
||||
fun `WHEN onCloseClicked THEN close`() {
|
||||
val controller: InactiveTabsAutoCloseDialogController = mockk(relaxed = true)
|
||||
val interactor = DefaultInactiveTabsAutoCloseDialogInteractor(controller)
|
||||
|
||||
interactor.onCloseClicked()
|
||||
|
||||
verify { controller.close() }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `WHEN onEnabledAutoCloseClicked THEN enableAutoClosed`() {
|
||||
val controller: InactiveTabsAutoCloseDialogController = mockk(relaxed = true)
|
||||
val interactor = DefaultInactiveTabsAutoCloseDialogInteractor(controller)
|
||||
|
||||
interactor.onEnabledAutoCloseClicked()
|
||||
|
||||
verify { controller.enableAutoClosed() }
|
||||
}
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
package org.mozilla.fenix.tabstray.browser
|
||||
|
||||
import io.mockk.Runs
|
||||
import io.mockk.every
|
||||
import io.mockk.just
|
||||
import io.mockk.mockk
|
||||
import io.mockk.spyk
|
||||
import io.mockk.verify
|
||||
import mozilla.components.browser.state.state.TabSessionState
|
||||
import mozilla.components.browser.state.store.BrowserStore
|
||||
import mozilla.components.concept.tabstray.TabsTray
|
||||
import org.junit.Test
|
||||
import org.mozilla.fenix.utils.Settings
|
||||
|
||||
class InactiveTabsAutoCloseDialogControllerTest {
|
||||
|
||||
@Test
|
||||
fun `WHEN close THEN update settings and refresh`() {
|
||||
val filter: (TabSessionState) -> Boolean = { !it.content.private }
|
||||
val store = BrowserStore()
|
||||
val settings: Settings = mockk(relaxed = true)
|
||||
val tray: TabsTray = mockk(relaxed = true)
|
||||
val controller = spyk(InactiveTabsAutoCloseDialogController(store, settings, filter, tray))
|
||||
|
||||
every { controller.refeshInactiveTabsSecion() } just Runs
|
||||
|
||||
controller.close()
|
||||
|
||||
verify { settings.hasInactiveTabsAutoCloseDialogBeenDismissed = true }
|
||||
verify { controller.refeshInactiveTabsSecion() }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `WHEN enableAutoClosed THEN update closeTabsAfterOneMonth settings and refresh`() {
|
||||
val filter: (TabSessionState) -> Boolean = { !it.content.private }
|
||||
val store = BrowserStore()
|
||||
val settings: Settings = mockk(relaxed = true)
|
||||
val tray: TabsTray = mockk(relaxed = true)
|
||||
val controller = spyk(InactiveTabsAutoCloseDialogController(store, settings, filter, tray))
|
||||
|
||||
every { controller.refeshInactiveTabsSecion() } just Runs
|
||||
|
||||
controller.enableAutoClosed()
|
||||
|
||||
verify { settings.closeTabsAfterOneMonth = true }
|
||||
verify { settings.closeTabsAfterOneWeek = false }
|
||||
verify { settings.closeTabsAfterOneDay = false }
|
||||
verify { settings.manuallyCloseTabs = false }
|
||||
verify { controller.refeshInactiveTabsSecion() }
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue