For #349: View Downloads

pull/35/head
Kate Glazko 4 years ago committed by kglazko
parent 929ec541b0
commit f83372b67c

@ -48,4 +48,9 @@ object FeatureFlags {
* Enables downloads with external download managers.
*/
val externalDownloadManager = Config.channel.isNightlyOrDebug
/**
* Enables viewing downloads in browser.
*/
val viewDownloads = Config.channel.isNightlyOrDebug
}

@ -488,7 +488,7 @@ sealed class Event {
NEW_PRIVATE_TAB, SHARE, BACK, FORWARD, RELOAD, STOP, OPEN_IN_FENIX,
SAVE_TO_COLLECTION, ADD_TO_TOP_SITES, ADD_TO_HOMESCREEN, QUIT, READER_MODE_ON,
READER_MODE_OFF, OPEN_IN_APP, BOOKMARK, READER_MODE_APPEARANCE, ADDONS_MANAGER,
BOOKMARKS, HISTORY, SYNC_TABS
BOOKMARKS, HISTORY, SYNC_TABS, DOWNLOADS
}
override val extras: Map<Events.browserMenuActionKeys, String>?

@ -380,6 +380,13 @@ class DefaultBrowserToolbarController(
BrowserFragmentDirections.actionGlobalHistoryFragment()
)
}
ToolbarMenu.Item.Downloads -> browserAnimator.captureEngineViewAndDrawStatically {
navController.nav(
R.id.browserFragment,
BrowserFragmentDirections.actionGlobalDownloadsFragment()
)
}
}
}
@ -414,6 +421,7 @@ class DefaultBrowserToolbarController(
ToolbarMenu.Item.AddonsManager -> Event.BrowserMenuItemTapped.Item.ADDONS_MANAGER
ToolbarMenu.Item.Bookmarks -> Event.BrowserMenuItemTapped.Item.BOOKMARKS
ToolbarMenu.Item.History -> Event.BrowserMenuItemTapped.Item.HISTORY
ToolbarMenu.Item.Downloads -> Event.BrowserMenuItemTapped.Item.DOWNLOADS
}
activity.components.analytics.metrics.track(Event.BrowserMenuItemTapped(eventItem))

@ -179,6 +179,7 @@ class DefaultToolbarMenu(
.shouldDeleteBrowsingDataOnQuit
val menuItems = listOfNotNull(
if (FeatureFlags.viewDownloads) downloadsItem else null,
historyItem,
bookmarksItem,
if (FeatureFlags.syncedTabs) syncedTabs else null,
@ -333,6 +334,14 @@ class DefaultToolbarMenu(
onItemTapped.invoke(ToolbarMenu.Item.Bookmarks)
}
val downloadsItem = BrowserMenuImageText(
"Downloads",
R.drawable.ic_download,
primaryTextColor()
) {
onItemTapped.invoke(ToolbarMenu.Item.Downloads)
}
@ColorRes
private fun primaryTextColor() = ThemeManager.resolveAttribute(R.attr.primaryText, context)

@ -30,6 +30,7 @@ interface ToolbarMenu {
object ReaderModeAppearance : Item()
object Bookmarks : Item()
object History : Item()
object Downloads : Item()
}
val menuBuilder: BrowserMenuBuilder

@ -771,6 +771,15 @@ class HomeFragment : Fragment() {
HomeFragmentDirections.actionGlobalHistoryFragment()
)
}
HomeMenu.Item.Downloads -> {
hideOnboardingIfNeeded()
nav(
R.id.homeFragment,
HomeFragmentDirections.actionGlobalDownloadsFragment()
)
}
HomeMenu.Item.Help -> {
hideOnboardingIfNeeded()
(activity as HomeActivity).openToBrowserAndLoad(

@ -43,6 +43,7 @@ class HomeMenu(
object SyncedTabs : Item()
object History : Item()
object Bookmarks : Item()
object Downloads : Item()
object Quit : Item()
object Sync : Item()
}
@ -144,6 +145,14 @@ class HomeMenu(
onItemTapped.invoke(Item.Help)
}
val downloadsItem = BrowserMenuImageText(
"Downloads",
R.drawable.ic_download,
primaryTextColor
) {
onItemTapped.invoke(Item.Downloads)
}
// Only query account manager if it has been initialized.
// We don't want to cause its initialization just for this check.
val accountAuthItem = if (context.components.backgroundServices.accountManagerAvailableQueue.isReady()) {
@ -161,6 +170,7 @@ class HomeMenu(
if (FeatureFlags.syncedTabs) syncedTabsItem else null,
bookmarksItem,
historyItem,
if (FeatureFlags.viewDownloads) downloadsItem else null,
BrowserMenuDivider(),
addons,
BrowserMenuDivider(),

@ -0,0 +1,41 @@
/* 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.library.downloads
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import org.mozilla.fenix.library.SelectionHolder
import org.mozilla.fenix.library.downloads.viewholders.DownloadsListItemViewHolder
class DownloadAdapter(
private val downloadInteractor: DownloadInteractor
) : RecyclerView.Adapter<DownloadsListItemViewHolder>(), SelectionHolder<DownloadItem> {
private var downloads: List<DownloadItem> = listOf()
private var mode: DownloadFragmentState.Mode = DownloadFragmentState.Mode.Normal
override val selectedItems get() = mode.selectedItems
override fun getItemCount(): Int = downloads.size
override fun getItemViewType(position: Int): Int = DownloadsListItemViewHolder.LAYOUT_ID
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DownloadsListItemViewHolder {
val view = LayoutInflater.from(parent.context).inflate(viewType, parent, false)
return DownloadsListItemViewHolder(view, downloadInteractor, this)
}
fun updateMode(mode: DownloadFragmentState.Mode) {
this.mode = mode
}
override fun onBindViewHolder(holder: DownloadsListItemViewHolder, position: Int) {
holder.bind(downloads[position])
}
fun updateDownloads(downloads: List<DownloadItem>) {
this.downloads = downloads
notifyDataSetChanged()
}
}

@ -0,0 +1,31 @@
/* 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.library.downloads
import org.mozilla.fenix.browser.browsingmode.BrowsingMode
interface DownloadController {
fun handleOpen(item: DownloadItem, mode: BrowsingMode? = null)
fun handleBackPressed(): Boolean
}
class DefaultDownloadController(
private val store: DownloadFragmentStore,
private val openToFileManager: (item: DownloadItem, mode: BrowsingMode?) -> Unit
) : DownloadController {
override fun handleOpen(item: DownloadItem, mode: BrowsingMode?) {
openToFileManager(item, mode)
}
override fun handleBackPressed(): Boolean {
return if (store.state.mode is DownloadFragmentState.Mode.Editing) {
store.dispatch(DownloadFragmentAction.ExitEditMode)
true
} else {
false
}
}
}

@ -0,0 +1,108 @@
/* 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.library.downloads
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import kotlinx.android.synthetic.main.fragment_downloads.view.*
import kotlinx.coroutines.ExperimentalCoroutinesApi
import mozilla.components.feature.downloads.AbstractFetchDownloadService
import mozilla.components.lib.state.ext.consumeFrom
import mozilla.components.support.base.feature.UserInteractionHandler
import org.mozilla.fenix.HomeActivity
import org.mozilla.fenix.R
import org.mozilla.fenix.browser.browsingmode.BrowsingMode
import org.mozilla.fenix.components.StoreProvider
import org.mozilla.fenix.components.metrics.Event
import org.mozilla.fenix.ext.requireComponents
import org.mozilla.fenix.ext.showToolbar
import org.mozilla.fenix.library.LibraryPageFragment
@SuppressWarnings("TooManyFunctions", "LargeClass")
class DownloadFragment : LibraryPageFragment<DownloadItem>(), UserInteractionHandler {
private lateinit var downloadStore: DownloadFragmentStore
private lateinit var downloadView: DownloadView
private lateinit var downloadInteractor: DownloadInteractor
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view = inflater.inflate(R.layout.fragment_downloads, container, false)
val items = requireComponents.core.store.state.downloads.map {
DownloadItem(
it.value.id,
it.value.fileName,
it.value.filePath,
it.value.contentLength.toString(),
it.value.contentType
)
}
downloadStore = StoreProvider.get(this) {
DownloadFragmentStore(
DownloadFragmentState(
items = items,
mode = DownloadFragmentState.Mode.Normal
)
)
}
val downloadController: DownloadController = DefaultDownloadController(
downloadStore,
::openItem
)
downloadInteractor = DownloadInteractor(
downloadController
)
downloadView = DownloadView(view.downloadsLayout, downloadInteractor)
return view
}
override val selectedItems get() = downloadStore.state.mode.selectedItems
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
requireComponents.analytics.metrics.track(Event.HistoryOpened)
setHasOptionsMenu(false)
}
@ExperimentalCoroutinesApi
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
consumeFrom(downloadStore) {
downloadView.update(it)
}
}
override fun onResume() {
super.onResume()
showToolbar(getString(R.string.library_downloads))
}
override fun onBackPressed(): Boolean {
return downloadView.onBackPressed()
}
private fun openItem(item: DownloadItem, mode: BrowsingMode? = null) {
mode?.let { (activity as HomeActivity).browsingModeManager.mode = it }
context?.let {
AbstractFetchDownloadService.openFile(
context = it,
contentType = item.contentType,
filePath = item.filePath
)
}
}
}

@ -0,0 +1,61 @@
/* 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.library.downloads
import mozilla.components.lib.state.Action
import mozilla.components.lib.state.State
import mozilla.components.lib.state.Store
/**
* Class representing a history entry
* @property id Unique id of the download item
* @property fileName File name of the download item
* @property filePath Full path of the download item
* @property size The size in bytes of the download item
* @property contentType The type of file the download is
*/
data class DownloadItem(val id: Long, val fileName: String?, val filePath: String, val size: String, val contentType: String?)
/**
* The [Store] for holding the [DownloadFragmentState] and applying [DownloadFragmentAction]s.
*/
class DownloadFragmentStore(initialState: DownloadFragmentState) :
Store<DownloadFragmentState, DownloadFragmentAction>(initialState, ::downloadStateReducer)
/**
* Actions to dispatch through the `DownloadStore` to modify `DownloadState` through the reducer.
*/
sealed class DownloadFragmentAction : Action {
object ExitEditMode : DownloadFragmentAction()
}
/**
* The state for the Download Screen
* @property items List of DownloadItem to display
* @property mode Current Mode of Download
*/
data class DownloadFragmentState(
val items: List<DownloadItem>,
val mode: Mode
) : State {
sealed class Mode {
open val selectedItems = emptySet<DownloadItem>()
object Normal : Mode()
data class Editing(override val selectedItems: Set<DownloadItem>) : DownloadFragmentState.Mode()
}
}
/**
* The DownloadState Reducer.
*/
private fun downloadStateReducer(
state: DownloadFragmentState,
action: DownloadFragmentAction
): DownloadFragmentState {
return when (action) {
is DownloadFragmentAction.ExitEditMode -> state.copy(mode = DownloadFragmentState.Mode.Normal)
}
}

@ -0,0 +1,29 @@
/* 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.library.downloads
/**
* Interactor for the download screen
* Provides implementations for the DownloadViewInteractor
*/
@SuppressWarnings("TooManyFunctions")
class DownloadInteractor(
private val downloadController: DownloadController
) : DownloadViewInteractor {
override fun open(item: DownloadItem) {
downloadController.handleOpen(item)
}
override fun select(item: DownloadItem) {
TODO("Not yet implemented")
}
override fun deselect(item: DownloadItem) {
TODO("Not yet implemented")
}
override fun onBackPressed(): Boolean {
return downloadController.handleBackPressed()
}
}

@ -0,0 +1,74 @@
/* 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.library.downloads
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.SimpleItemAnimator
import kotlinx.android.synthetic.main.component_downloads.view.*
import mozilla.components.support.base.feature.UserInteractionHandler
import org.mozilla.fenix.R
import org.mozilla.fenix.library.LibraryPageView
import org.mozilla.fenix.library.SelectionInteractor
/**
* Interface for the DownloadViewInteractor. This interface is implemented by objects that want
* to respond to user interaction on the DownloadView
*/
interface DownloadViewInteractor : SelectionInteractor<DownloadItem> {
/**
* Called on backpressed to exit edit mode
*/
fun onBackPressed(): Boolean
}
/**
* View that contains and configures the Downloads List
*/
class DownloadView(
container: ViewGroup,
val interactor: DownloadInteractor
) : LibraryPageView(container), UserInteractionHandler {
val view: View = LayoutInflater.from(container.context)
.inflate(R.layout.component_downloads, container, true)
var mode: DownloadFragmentState.Mode = DownloadFragmentState.Mode.Normal
private set
val downloadAdapter = DownloadAdapter(interactor)
private val layoutManager = LinearLayoutManager(container.context)
init {
view.download_list.apply {
layoutManager = this@DownloadView.layoutManager
adapter = downloadAdapter
(itemAnimator as SimpleItemAnimator).supportsChangeAnimations = false
}
}
fun update(state: DownloadFragmentState) {
view.swipe_refresh.isEnabled =
state.mode === DownloadFragmentState.Mode.Normal
mode = state.mode
downloadAdapter.updateMode(state.mode)
downloadAdapter.updateDownloads(state.items)
setUiForNormalMode(
context.getString(R.string.library_downloads)
)
}
override fun onBackPressed(): Boolean {
return interactor.onBackPressed()
}
}

@ -0,0 +1,46 @@
/* 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.library.downloads.viewholders
import android.view.View
import androidx.recyclerview.widget.RecyclerView
import kotlinx.android.synthetic.main.download_list_item.view.*
import kotlinx.android.synthetic.main.library_site_item.view.*
import org.mozilla.fenix.R
import org.mozilla.fenix.ext.hideAndDisable
import org.mozilla.fenix.library.SelectionHolder
import org.mozilla.fenix.library.downloads.DownloadInteractor
import org.mozilla.fenix.library.downloads.DownloadItem
import mozilla.components.feature.downloads.toMegabyteString
class DownloadsListItemViewHolder(
view: View,
private val downloadInteractor: DownloadInteractor,
private val selectionHolder: SelectionHolder<DownloadItem>
) : RecyclerView.ViewHolder(view) {
private var item: DownloadItem? = null
fun bind(
item: DownloadItem
) {
itemView.download_layout.visibility = View.VISIBLE
itemView.download_layout.titleView.text = item.fileName
itemView.download_layout.urlView.text = item.size.toLong().toMegabyteString()
itemView.download_layout.setSelectionInteractor(item, selectionHolder, downloadInteractor)
itemView.download_layout.changeSelected(item in selectionHolder.selectedItems)
itemView.overflow_menu.hideAndDisable()
itemView.favicon.setImageResource(R.drawable.ic_download_default)
itemView.favicon.isClickable = false
this.item = item
}
companion object {
const val LAYOUT_ID = R.layout.download_list_item
}
}

@ -0,0 +1,15 @@
<!-- 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/. -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M16.69,3C18.5174,3.0017 19.9983,4.4826 20,6.31L20,17.69C19.9983,19.5174 18.5174,20.9983 16.69,21L7.31,21C5.4826,20.9983 4.0017,19.5174 4,17.69L4,6.31C4.0017,4.4826 5.4826,3.0017 7.31,3L16.69,3ZM16.69,5L7.31,5C6.5867,5.0006 6.0006,5.5867 6,6.31L6,17.69C6.0006,18.4133 6.5867,18.9994 7.31,19L16.69,19C17.4133,18.9994 17.9994,18.4133 18,17.69L18,6.31C17.9994,5.5867 17.4133,5.0006 16.69,5ZM15.4286,16C15.7442,16 16,16.2239 16,16.5C16,16.7761 15.7442,17 15.4286,17L8.5714,17C8.2558,17 8,16.7761 8,16.5C8,16.2239 8.2558,16 8.5714,16L15.4286,16ZM15.4286,13C15.7442,13 16,13.2239 16,13.5C16,13.7761 15.7442,14 15.4286,14L8.5714,14C8.2558,14 8,13.7761 8,13.5C8,13.2239 8.2558,13 8.5714,13L15.4286,13ZM12.6429,10C12.8401,10 13,10.2239 13,10.5C13,10.7761 12.8401,11 12.6429,11L8.3571,11C8.1599,11 8,10.7761 8,10.5C8,10.2239 8.1599,10 8.3571,10L12.6429,10ZM11.7143,7C11.8721,7 12,7.2239 12,7.5C12,7.7761 11.8721,8 11.7143,8L8.2857,8C8.1279,8 8,7.7761 8,7.5C8,7.2239 8.1279,7 8.2857,7L11.7143,7ZM14,5L16,5L16,9L14,9L14,5ZM19,7L19,9L15,9L15,7L19,7Z"
android:strokeWidth="1"
android:fillColor="#20123A"
android:fillType="nonZero"
android:strokeColor="#00000000"/>
</vector>

@ -0,0 +1,49 @@
<?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/. -->
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/download_wrapper"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ProgressBar
android:id="@+id/progress_bar"
style="@style/Widget.AppCompat.ProgressBar.Horizontal"
android:layout_width="match_parent"
android:layout_height="8dp"
android:translationY="-3dp"
android:visibility="gone"
android:indeterminate="true"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<TextView
android:id="@+id/download_empty_view"
android:layout_width="0dp"
android:layout_height="0dp"
android:gravity="center"
android:text="@string/download_empty_message"
android:textColor="?secondaryText"
android:textSize="16sp"
android:visibility="gone"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="@+id/swipe_refresh"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/download_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="vertical"
tools:listitem="@layout/download_list_item"/>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

@ -0,0 +1,17 @@
<?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/. -->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_height="wrap_content"
android:layout_width="match_parent" xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical">
<org.mozilla.fenix.library.LibrarySiteItemView
android:id="@+id/download_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="@dimen/library_item_height" />
</LinearLayout>

@ -0,0 +1,12 @@
<?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:tools="http://schemas.android.com/tools"
android:id="@+id/downloadsLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="org.mozilla.fenix.library.downloads.DownloadFragment" />

@ -70,6 +70,9 @@
<action
android:id="@+id/action_global_historyFragment"
app:destination="@id/historyFragment" />
<action android:id="@+id/action_global_downloadsFragment"
app:destination="@id/downloadsFragment" />
<action
android:id="@+id/action_global_accountProblemFragment"
app:destination="@id/accountProblemFragment" />
@ -239,6 +242,12 @@
android:label="@string/library_history"
tools:layout="@layout/fragment_history" />
<fragment
android:id="@+id/downloadsFragment"
android:name="org.mozilla.fenix.library.downloads.DownloadFragment"
android:label="Downloads"
tools:layout="@layout/fragment_downloads" />
<fragment
android:id="@+id/bookmarkFragment"
android:name="org.mozilla.fenix.library.bookmarks.BookmarkFragment"

@ -563,6 +563,13 @@
<!-- Text shown when no history exists -->
<string name="history_empty_message">No history here</string>
<!-- Downloads -->
<!-- Text shown when no download exists -->
<string name="download_empty_message">No downloads here</string>
<!-- History multi select title in app bar
The first parameter is the number of downloads selected -->
<string name="download_multi_select_title">%1$d selected</string>
<!-- Crashes -->
<!-- Title text displayed on the tab crash page. This first parameter is the name of the application (For example: Fenix) -->
<string name="tab_crash_title_2">Sorry. %1$s cant load that page.</string>

@ -0,0 +1,56 @@
/* 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.library.downloads
import androidx.recyclerview.widget.RecyclerView
import io.mockk.Runs
import io.mockk.every
import io.mockk.just
import io.mockk.mockk
import io.mockk.verify
import org.junit.Assert.assertEquals
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
@RunWith(FenixRobolectricTestRunner::class)
class DownloadAdapterTest {
private lateinit var interactor: DownloadInteractor
private lateinit var adapter: DownloadAdapter
@Before
fun setup() {
interactor = mockk()
adapter = DownloadAdapter(interactor)
every { interactor.select(any()) } just Runs
}
@Test
fun `getItemCount should return the number of tab collections`() {
val download = mockk<DownloadItem>()
assertEquals(0, adapter.itemCount)
adapter.updateDownloads(
downloads = listOf(download)
)
assertEquals(1, adapter.itemCount)
}
@Test
fun `updateData inserts item`() {
val download = mockk<DownloadItem> {
}
val observer = mockk<RecyclerView.AdapterDataObserver>(relaxed = true)
adapter.registerAdapterDataObserver(observer)
adapter.updateDownloads(
downloads = listOf(download)
)
verify { observer.onChanged() }
}
}

@ -0,0 +1,63 @@
/* 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.library.downloads
import io.mockk.every
import io.mockk.mockk
import io.mockk.verify
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.TestCoroutineScope
import org.junit.Assert.assertFalse
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mozilla.fenix.browser.browsingmode.BrowsingMode
import org.mozilla.fenix.helpers.FenixRobolectricTestRunner
@ExperimentalCoroutinesApi
@RunWith(FenixRobolectricTestRunner::class)
class DownloadControllerTest {
private val downloadItem = DownloadItem(0, "title", "url", "77", "jpg")
private val scope: CoroutineScope = TestCoroutineScope()
private val store: DownloadFragmentStore = mockk(relaxed = true)
private val state: DownloadFragmentState = mockk(relaxed = true)
private val openToFileManager: (DownloadItem, BrowsingMode?) -> Unit = mockk(relaxed = true)
private val invalidateOptionsMenu: () -> Unit = mockk(relaxed = true)
private val controller = DefaultDownloadController(
store,
openToFileManager
)
@Before
fun setUp() {
every { store.state } returns state
}
@Test
fun onPressDownloadItemInNormalMode() {
controller.handleOpen(downloadItem)
verify {
openToFileManager(downloadItem, null)
}
}
@Test
fun onOpenItemInNormalMode() {
controller.handleOpen(downloadItem, BrowsingMode.Normal)
verify {
openToFileManager(downloadItem, BrowsingMode.Normal)
}
}
@Test
fun onBackPressedInNormalMode() {
every { state.mode } returns DownloadFragmentState.Mode.Normal
assertFalse(controller.handleBackPressed())
}
}

@ -0,0 +1,40 @@
/* 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.library.downloads
import io.mockk.every
import io.mockk.mockk
import io.mockk.verifyAll
import org.junit.Assert.assertTrue
import org.junit.Test
class DownloadInteractorTest {
private val downloadItem = DownloadItem(0, "title", "url", "5.6 mb", "png")
val controller: DownloadController = mockk(relaxed = true)
val interactor = DownloadInteractor(controller)
@Test
fun onOpen() {
interactor.open(downloadItem)
verifyAll {
controller.handleOpen(downloadItem)
}
}
@Test
fun onBackPressed() {
every {
controller.handleBackPressed()
} returns true
val backpressHandled = interactor.onBackPressed()
verifyAll {
controller.handleBackPressed()
}
assertTrue(backpressHandled)
}
}
Loading…
Cancel
Save