1
0
Fork 0

Use ShareData with ShareFragment (#6698)

master
Tiger Oakes 2019-11-25 11:07:21 -08:00 committed by GitHub
parent d69db50968
commit 7e8f079269
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 76 additions and 120 deletions

View File

@ -23,6 +23,7 @@ import kotlinx.coroutines.launch
import mozilla.components.browser.session.Session import mozilla.components.browser.session.Session
import mozilla.components.browser.session.SessionManager import mozilla.components.browser.session.SessionManager
import mozilla.components.concept.engine.EngineView import mozilla.components.concept.engine.EngineView
import mozilla.components.concept.engine.prompt.ShareData
import mozilla.components.support.ktx.kotlin.isUrl import mozilla.components.support.ktx.kotlin.isUrl
import org.mozilla.fenix.NavGraphDirections import org.mozilla.fenix.NavGraphDirections
import org.mozilla.fenix.R import org.mozilla.fenix.R
@ -32,8 +33,8 @@ import org.mozilla.fenix.browser.browsingmode.BrowsingMode
import org.mozilla.fenix.browser.browsingmode.BrowsingModeManager import org.mozilla.fenix.browser.browsingmode.BrowsingModeManager
import org.mozilla.fenix.browser.readermode.ReaderModeController import org.mozilla.fenix.browser.readermode.ReaderModeController
import org.mozilla.fenix.collections.SaveCollectionStep import org.mozilla.fenix.collections.SaveCollectionStep
import org.mozilla.fenix.components.TabCollectionStorage
import org.mozilla.fenix.components.FenixSnackbar import org.mozilla.fenix.components.FenixSnackbar
import org.mozilla.fenix.components.TabCollectionStorage
import org.mozilla.fenix.components.metrics.Event import org.mozilla.fenix.components.metrics.Event
import org.mozilla.fenix.ext.components import org.mozilla.fenix.ext.components
import org.mozilla.fenix.ext.nav import org.mozilla.fenix.ext.nav
@ -144,11 +145,11 @@ class DefaultBrowserToolbarController(
} }
} }
ToolbarMenu.Item.Share -> { ToolbarMenu.Item.Share -> {
val currentUrl = currentSession?.url val directions = NavGraphDirections.actionGlobalShareFragment(
currentUrl?.apply { data = arrayOf(ShareData(url = currentSession?.url, title = currentSession?.title)),
val directions = NavGraphDirections.actionGlobalShareFragment(this) showPage = true
navController.navigate(directions) )
} navController.navigate(directions)
} }
ToolbarMenu.Item.NewTab -> { ToolbarMenu.Item.NewTab -> {
val directions = BrowserFragmentDirections.actionBrowserFragmentToSearchFragment( val directions = BrowserFragmentDirections.actionBrowserFragmentToSearchFragment(

View File

@ -37,7 +37,6 @@ import androidx.transition.TransitionInflater
import com.google.android.material.snackbar.Snackbar import com.google.android.material.snackbar.Snackbar
import kotlinx.android.synthetic.main.fragment_home.* import kotlinx.android.synthetic.main.fragment_home.*
import kotlinx.android.synthetic.main.fragment_home.view.* import kotlinx.android.synthetic.main.fragment_home.view.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.Dispatchers.Main import kotlinx.coroutines.Dispatchers.Main
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
@ -47,6 +46,7 @@ import mozilla.appservices.places.BookmarkRoot
import mozilla.components.browser.menu.BrowserMenu import mozilla.components.browser.menu.BrowserMenu
import mozilla.components.browser.session.Session import mozilla.components.browser.session.Session
import mozilla.components.browser.session.SessionManager import mozilla.components.browser.session.SessionManager
import mozilla.components.concept.engine.prompt.ShareData
import mozilla.components.concept.sync.AccountObserver import mozilla.components.concept.sync.AccountObserver
import mozilla.components.concept.sync.AuthType import mozilla.components.concept.sync.AuthType
import mozilla.components.concept.sync.OAuthAccount import mozilla.components.concept.sync.OAuthAccount
@ -95,7 +95,6 @@ import org.mozilla.fenix.mvi.getManagedEmitter
import org.mozilla.fenix.onboarding.FenixOnboarding import org.mozilla.fenix.onboarding.FenixOnboarding
import org.mozilla.fenix.settings.SupportUtils import org.mozilla.fenix.settings.SupportUtils
import org.mozilla.fenix.settings.deletebrowsingdata.deleteAndQuit import org.mozilla.fenix.settings.deletebrowsingdata.deleteAndQuit
import org.mozilla.fenix.share.ShareTab
import org.mozilla.fenix.utils.FragmentPreDrawManager import org.mozilla.fenix.utils.FragmentPreDrawManager
import org.mozilla.fenix.utils.allowUndo import org.mozilla.fenix.utils.allowUndo
import org.mozilla.fenix.whatsnew.WhatsNew import org.mozilla.fenix.whatsnew.WhatsNew
@ -230,14 +229,14 @@ class HomeFragment : Fragment() {
setupHomeMenu() setupHomeMenu()
viewLifecycleOwner.lifecycleScope.launch(Dispatchers.IO) { viewLifecycleOwner.lifecycleScope.launch(IO) {
val iconSize = resources.getDimension(R.dimen.preference_icon_drawable_size).toInt() val iconSize = resources.getDimensionPixelSize(R.dimen.preference_icon_drawable_size)
val searchEngine = requireComponents.search.provider.getDefaultEngine(requireContext()) val searchEngine = requireComponents.search.provider.getDefaultEngine(requireContext())
val searchIcon = BitmapDrawable(resources, searchEngine.icon) val searchIcon = BitmapDrawable(resources, searchEngine.icon)
searchIcon.setBounds(0, 0, iconSize, iconSize) searchIcon.setBounds(0, 0, iconSize, iconSize)
withContext(Dispatchers.Main) { withContext(Main) {
search_engine_icon?.setImageDrawable(searchIcon) search_engine_icon?.setImageDrawable(searchIcon)
} }
} }
@ -409,7 +408,7 @@ class HomeFragment : Fragment() {
is TabAction.Share -> { is TabAction.Share -> {
invokePendingDeleteJobs() invokePendingDeleteJobs()
sessionManager.findSessionById(action.sessionId)?.let { session -> sessionManager.findSessionById(action.sessionId)?.let { session ->
share(session.url) share(listOf(ShareData(url = session.url)))
} }
} }
is TabAction.PauseMedia -> { is TabAction.PauseMedia -> {
@ -449,11 +448,11 @@ class HomeFragment : Fragment() {
is TabAction.ShareTabs -> { is TabAction.ShareTabs -> {
invokePendingDeleteJobs() invokePendingDeleteJobs()
val shareTabs = sessionManager val shareData = sessionManager
.sessionsOfType(private = browsingModeManager.mode.isPrivate) .sessionsOfType(private = browsingModeManager.mode.isPrivate)
.map { ShareTab(it.url, it.title) } .map { ShareData(url = it.url, title = it.title) }
.toList() .toList()
share(tabs = shareTabs) share(shareData)
} }
} }
} }
@ -583,8 +582,7 @@ class HomeFragment : Fragment() {
components.analytics.metrics.track(Event.CollectionAllTabsRestored) components.analytics.metrics.track(Event.CollectionAllTabsRestored)
} }
is CollectionAction.ShareTabs -> { is CollectionAction.ShareTabs -> {
val shareTabs = action.collection.tabs.map { ShareTab(it.url, it.title) } share(action.collection.tabs.map { ShareData(url = it.url, title = it.title) })
share(tabs = shareTabs)
requireComponents.analytics.metrics.track(Event.CollectionShared) requireComponents.analytics.metrics.track(Event.CollectionShared)
} }
is CollectionAction.RemoveTab -> { is CollectionAction.RemoveTab -> {
@ -853,12 +851,10 @@ class HomeFragment : Fragment() {
showCollectionCreationFragment(step, selectedTabId?.let { arrayOf(it) }) showCollectionCreationFragment(step, selectedTabId?.let { arrayOf(it) })
} }
private fun share(url: String? = null, tabs: List<ShareTab>? = null) { private fun share(data: List<ShareData>) {
val directions = val directions = HomeFragmentDirections.actionHomeFragmentToShareFragment(
HomeFragmentDirections.actionHomeFragmentToShareFragment( data = data.toTypedArray()
url = url, )
tabs = tabs?.toTypedArray()
)
nav(R.id.homeFragment, directions) nav(R.id.homeFragment, directions)
} }

View File

@ -11,6 +11,7 @@ import android.content.res.Resources
import androidx.core.content.getSystemService import androidx.core.content.getSystemService
import androidx.navigation.NavController import androidx.navigation.NavController
import androidx.navigation.NavDirections import androidx.navigation.NavDirections
import mozilla.components.concept.engine.prompt.ShareData
import mozilla.components.concept.storage.BookmarkNode import mozilla.components.concept.storage.BookmarkNode
import org.mozilla.fenix.BrowserDirection import org.mozilla.fenix.BrowserDirection
import org.mozilla.fenix.HomeActivity import org.mozilla.fenix.HomeActivity
@ -21,7 +22,6 @@ import org.mozilla.fenix.components.Services
import org.mozilla.fenix.components.metrics.Event import org.mozilla.fenix.components.metrics.Event
import org.mozilla.fenix.ext.components import org.mozilla.fenix.ext.components
import org.mozilla.fenix.ext.nav import org.mozilla.fenix.ext.nav
import org.mozilla.fenix.share.ShareTab
/** /**
* [BookmarkFragment] controller. * [BookmarkFragment] controller.
@ -84,9 +84,7 @@ class DefaultBookmarkController(
override fun handleBookmarkSharing(item: BookmarkNode) { override fun handleBookmarkSharing(item: BookmarkNode) {
navigate( navigate(
BookmarkFragmentDirections.actionBookmarkFragmentToShareFragment( BookmarkFragmentDirections.actionBookmarkFragmentToShareFragment(
url = item.url!!, data = arrayOf(ShareData(url = item.url, title = item.title))
title = item.title,
tabs = arrayOf(ShareTab(item.url!!, item.title!!))
) )
) )
} }

View File

@ -29,6 +29,7 @@ import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import mozilla.appservices.places.BookmarkRoot import mozilla.appservices.places.BookmarkRoot
import mozilla.components.concept.engine.prompt.ShareData
import mozilla.components.concept.storage.BookmarkNode import mozilla.components.concept.storage.BookmarkNode
import mozilla.components.concept.storage.BookmarkNodeType import mozilla.components.concept.storage.BookmarkNodeType
import mozilla.components.concept.sync.AccountObserver import mozilla.components.concept.sync.AccountObserver
@ -46,7 +47,6 @@ import org.mozilla.fenix.ext.minus
import org.mozilla.fenix.ext.nav import org.mozilla.fenix.ext.nav
import org.mozilla.fenix.ext.toShortUrl import org.mozilla.fenix.ext.toShortUrl
import org.mozilla.fenix.library.LibraryPageFragment import org.mozilla.fenix.library.LibraryPageFragment
import org.mozilla.fenix.share.ShareTab
import org.mozilla.fenix.utils.allowUndo import org.mozilla.fenix.utils.allowUndo
@Suppress("TooManyFunctions", "LargeClass") @Suppress("TooManyFunctions", "LargeClass")
@ -196,9 +196,7 @@ class BookmarkFragment : LibraryPageFragment<BookmarkNode>(), BackHandler {
val bookmark = bookmarkStore.state.mode.selectedItems.first() val bookmark = bookmarkStore.state.mode.selectedItems.first()
navigate( navigate(
BookmarkFragmentDirections.actionBookmarkFragmentToShareFragment( BookmarkFragmentDirections.actionBookmarkFragmentToShareFragment(
url = bookmark.url, data = arrayOf(ShareData(url = bookmark.url, title = bookmark.title))
title = bookmark.title,
tabs = arrayOf(ShareTab(bookmark.url.orEmpty(), bookmark.title.orEmpty()))
) )
) )
true true

View File

@ -21,6 +21,7 @@ import kotlinx.android.synthetic.main.fragment_history.view.*
import kotlinx.coroutines.Dispatchers.Main import kotlinx.coroutines.Dispatchers.Main
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import mozilla.components.concept.engine.prompt.ShareData
import mozilla.components.lib.state.ext.consumeFrom import mozilla.components.lib.state.ext.consumeFrom
import mozilla.components.support.base.feature.BackHandler import mozilla.components.support.base.feature.BackHandler
import org.mozilla.fenix.BrowserDirection import org.mozilla.fenix.BrowserDirection
@ -35,7 +36,6 @@ import org.mozilla.fenix.ext.components
import org.mozilla.fenix.ext.nav import org.mozilla.fenix.ext.nav
import org.mozilla.fenix.ext.requireComponents import org.mozilla.fenix.ext.requireComponents
import org.mozilla.fenix.library.LibraryPageFragment import org.mozilla.fenix.library.LibraryPageFragment
import org.mozilla.fenix.share.ShareTab
@SuppressWarnings("TooManyFunctions", "LargeClass") @SuppressWarnings("TooManyFunctions", "LargeClass")
class HistoryFragment : LibraryPageFragment<HistoryItem>(), BackHandler { class HistoryFragment : LibraryPageFragment<HistoryItem>(), BackHandler {
@ -143,18 +143,8 @@ class HistoryFragment : LibraryPageFragment<HistoryItem>(), BackHandler {
override fun onOptionsItemSelected(item: MenuItem): Boolean = when (item.itemId) { override fun onOptionsItemSelected(item: MenuItem): Boolean = when (item.itemId) {
R.id.share_history_multi_select -> { R.id.share_history_multi_select -> {
val selectedHistory = historyStore.state.mode.selectedItems val selectedHistory = historyStore.state.mode.selectedItems
val shareTabs = selectedHistory.map { ShareTab(it.url, it.title) } val shareTabs = selectedHistory.map { ShareData(url = it.url, title = it.title) }
when { share(shareTabs)
selectedHistory.size == 1 ->
share(
url = selectedHistory.first().url,
title = selectedHistory.first().title,
tabs = shareTabs
)
selectedHistory.size > 1 -> {
share(tabs = shareTabs)
}
}
true true
} }
R.id.delete_history_multi_select -> { R.id.delete_history_multi_select -> {
@ -243,14 +233,11 @@ class HistoryFragment : LibraryPageFragment<HistoryItem>(), BackHandler {
} }
} }
private fun share(url: String? = null, title: String? = null, tabs: List<ShareTab>? = null) { private fun share(data: List<ShareData>) {
requireComponents.analytics.metrics.track(Event.HistoryItemShared) requireComponents.analytics.metrics.track(Event.HistoryItemShared)
val directions = val directions = HistoryFragmentDirections.actionHistoryFragmentToShareFragment(
HistoryFragmentDirections.actionHistoryFragmentToShareFragment( data = data.toTypedArray()
url = url, )
title = title,
tabs = tabs?.toTypedArray()
)
nav(R.id.historyFragment, directions) nav(R.id.historyFragment, directions)
} }
} }

View File

@ -9,6 +9,7 @@ import android.view.ViewGroup
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import kotlinx.android.extensions.LayoutContainer import kotlinx.android.extensions.LayoutContainer
import kotlinx.android.synthetic.main.share_close.* import kotlinx.android.synthetic.main.share_close.*
import mozilla.components.concept.engine.prompt.ShareData
import org.mozilla.fenix.R import org.mozilla.fenix.R
import org.mozilla.fenix.share.listadapters.ShareTabsAdapter import org.mozilla.fenix.share.listadapters.ShareTabsAdapter
@ -36,7 +37,7 @@ class ShareCloseView(
shared_site_list.adapter = adapter shared_site_list.adapter = adapter
} }
fun setTabs(tabs: List<ShareTab>) { fun setTabs(tabs: List<ShareData>) {
adapter.submitList(tabs) adapter.submitList(tabs)
} }
} }

View File

@ -16,6 +16,7 @@ import kotlinx.coroutines.Deferred
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import mozilla.components.concept.engine.prompt.ShareData
import mozilla.components.concept.sync.Device import mozilla.components.concept.sync.Device
import mozilla.components.concept.sync.TabData import mozilla.components.concept.sync.TabData
import mozilla.components.feature.sendtab.SendTabUseCases import mozilla.components.feature.sendtab.SendTabUseCases
@ -47,7 +48,7 @@ interface ShareController {
* Default behavior of [ShareController]. Other implementations are possible. * Default behavior of [ShareController]. Other implementations are possible.
* *
* @param context [Context] used for various Android interactions. * @param context [Context] used for various Android interactions.
* @param sharedTabs the list of [ShareTab]s that can be shared. * @param shareData the list of [ShareData]s that can be shared.
* @param sendTabUseCases instance of [SendTabUseCases] which allows sending tabs to account devices. * @param sendTabUseCases instance of [SendTabUseCases] which allows sending tabs to account devices.
* @param snackbarPresenter - instance of [FenixSnackbarPresenter] for displaying styled snackbars * @param snackbarPresenter - instance of [FenixSnackbarPresenter] for displaying styled snackbars
* @param navController - [NavController] used for navigation. * @param navController - [NavController] used for navigation.
@ -56,12 +57,13 @@ interface ShareController {
@Suppress("TooManyFunctions") @Suppress("TooManyFunctions")
class DefaultShareController( class DefaultShareController(
private val context: Context, private val context: Context,
private val sharedTabs: List<ShareTab>, private val shareData: List<ShareData>,
private val sendTabUseCases: SendTabUseCases, private val sendTabUseCases: SendTabUseCases,
private val snackbarPresenter: FenixSnackbarPresenter, private val snackbarPresenter: FenixSnackbarPresenter,
private val navController: NavController, private val navController: NavController,
private val dismiss: () -> Unit private val dismiss: () -> Unit
) : ShareController { ) : ShareController {
override fun handleReauth() { override fun handleReauth() {
val directions = ShareFragmentDirections.actionShareFragmentToAccountProblemFragment() val directions = ShareFragmentDirections.actionShareFragmentToAccountProblemFragment()
navController.nav(R.id.shareFragment, directions) navController.nav(R.id.shareFragment, directions)
@ -99,11 +101,11 @@ class DefaultShareController(
override fun handleShareToDevice(device: Device) { override fun handleShareToDevice(device: Device) {
context.metrics.track(Event.SendTab) context.metrics.track(Event.SendTab)
shareToDevicesWithRetry { sendTabUseCases.sendToDeviceAsync(device.id, sharedTabs.toTabData()) } shareToDevicesWithRetry { sendTabUseCases.sendToDeviceAsync(device.id, shareData.toTabData()) }
} }
override fun handleShareToAllDevices(devices: List<Device>) { override fun handleShareToAllDevices(devices: List<Device>) {
shareToDevicesWithRetry { sendTabUseCases.sendToAllAsync(sharedTabs.toTabData()) } shareToDevicesWithRetry { sendTabUseCases.sendToAllAsync(shareData.toTabData()) }
} }
override fun handleSignIn() { override fun handleSignIn() {
@ -146,19 +148,20 @@ class DefaultShareController(
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
fun getSuccessMessage(): String = with(context) { fun getSuccessMessage(): String = with(context) {
when (sharedTabs.size) { when (shareData.size) {
1 -> getString(R.string.sync_sent_tab_snackbar) 1 -> getString(R.string.sync_sent_tab_snackbar)
else -> getString(R.string.sync_sent_tabs_snackbar) else -> getString(R.string.sync_sent_tabs_snackbar)
} }
} }
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) @VisibleForTesting
fun getShareText() = sharedTabs.joinToString("\n") { tab -> tab.url } fun getShareText() = shareData.joinToString("\n") { data ->
listOfNotNull(data.url, data.text).joinToString(" ")
}
// Navigation between app fragments uses ShareTab as arguments. SendTabUseCases uses TabData. // Navigation between app fragments uses ShareTab as arguments. SendTabUseCases uses TabData.
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) @VisibleForTesting
fun ShareTab.toTabData() = TabData(title, url) fun List<ShareData>.toTabData() = map { data ->
TabData(data.title.orEmpty(), data.url.orEmpty())
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) }
fun List<ShareTab>.toTabData() = map { it.toTabData() }
} }

View File

@ -6,7 +6,6 @@ package org.mozilla.fenix.share
import android.content.Context import android.content.Context
import android.os.Bundle import android.os.Bundle
import android.os.Parcelable
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
@ -16,7 +15,6 @@ import androidx.lifecycle.ViewModelProvider.AndroidViewModelFactory
import androidx.lifecycle.observe import androidx.lifecycle.observe
import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.findNavController
import androidx.navigation.fragment.navArgs import androidx.navigation.fragment.navArgs
import kotlinx.android.parcel.Parcelize
import kotlinx.android.synthetic.main.fragment_share.view.* import kotlinx.android.synthetic.main.fragment_share.view.*
import mozilla.components.feature.sendtab.SendTabUseCases import mozilla.components.feature.sendtab.SendTabUseCases
import org.mozilla.fenix.R import org.mozilla.fenix.R
@ -51,15 +49,14 @@ class ShareFragment : AppCompatDialogFragment() {
): View? { ): View? {
val view = inflater.inflate(R.layout.fragment_share, container, false) val view = inflater.inflate(R.layout.fragment_share, container, false)
val args by navArgs<ShareFragmentArgs>() val args by navArgs<ShareFragmentArgs>()
check(!(args.url == null && args.tabs.isNullOrEmpty())) { "URL and tabs cannot both be null." } val shareData = args.data.toList()
val tabs = args.tabs?.toList() ?: listOf(ShareTab(args.url!!, args.title.orEmpty()))
val accountManager = requireComponents.backgroundServices.accountManager val accountManager = requireComponents.backgroundServices.accountManager
shareInteractor = ShareInteractor( shareInteractor = ShareInteractor(
DefaultShareController( DefaultShareController(
context = requireContext(), context = requireContext(),
sharedTabs = tabs, shareData = shareData,
snackbarPresenter = FenixSnackbarPresenter(activity!!.getRootView()!!), snackbarPresenter = FenixSnackbarPresenter(activity!!.getRootView()!!),
navController = findNavController(), navController = findNavController(),
sendTabUseCases = SendTabUseCases(accountManager), sendTabUseCases = SendTabUseCases(accountManager),
@ -71,17 +68,16 @@ class ShareFragment : AppCompatDialogFragment() {
shareToAccountDevicesView = shareToAccountDevicesView =
ShareToAccountDevicesView(view.devicesShareLayout, shareInteractor) ShareToAccountDevicesView(view.devicesShareLayout, shareInteractor)
if (args.url != null && args.tabs == null) { if (args.showPage) {
// If sharing one tab from the browser fragment, show it. // Show the previous fragment underneath the share background scrim
// If URL is set and tabs is null, we assume the browser is visible, since navigation // by making it translucent.
// does not tell us the back stack state.
view.closeSharingScrim.alpha = SHOW_PAGE_ALPHA view.closeSharingScrim.alpha = SHOW_PAGE_ALPHA
view.shareWrapper.setOnClickListener { shareInteractor.onShareClosed() } view.shareWrapper.setOnClickListener { shareInteractor.onShareClosed() }
} else { } else {
// Otherwise, show a list of tabs to share. // Otherwise, show a list of tabs to share.
view.closeSharingScrim.alpha = 1.0f view.closeSharingScrim.alpha = 1.0f
shareCloseView = ShareCloseView(view.closeSharingContent, shareInteractor) shareCloseView = ShareCloseView(view.closeSharingContent, shareInteractor)
shareCloseView.setTabs(tabs) shareCloseView.setTabs(shareData)
} }
shareToAppsView = ShareToAppsView(view.appsShareLayout, shareInteractor) shareToAppsView = ShareToAppsView(view.appsShareLayout, shareInteractor)
@ -102,6 +98,3 @@ class ShareFragment : AppCompatDialogFragment() {
const val SHOW_PAGE_ALPHA = 0.6f const val SHOW_PAGE_ALPHA = 0.6f
} }
} }
@Parcelize
data class ShareTab(val url: String, val title: String) : Parcelable

View File

@ -11,16 +11,16 @@ import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import kotlinx.android.synthetic.main.share_tab_item.view.* import kotlinx.android.synthetic.main.share_tab_item.view.*
import mozilla.components.concept.engine.prompt.ShareData
import org.mozilla.fenix.R import org.mozilla.fenix.R
import org.mozilla.fenix.ext.components import org.mozilla.fenix.ext.components
import org.mozilla.fenix.ext.loadIntoView import org.mozilla.fenix.ext.loadIntoView
import org.mozilla.fenix.share.ShareTab
/** /**
* Adapter for a list of tabs to be shared. * Adapter for a list of tabs to be shared.
*/ */
class ShareTabsAdapter : class ShareTabsAdapter :
ListAdapter<ShareTab, ShareTabsAdapter.ShareTabViewHolder>(ShareTabDiffCallback) { ListAdapter<ShareData, ShareTabsAdapter.ShareTabViewHolder>(ShareTabDiffCallback) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ShareTabViewHolder( override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ShareTabViewHolder(
LayoutInflater.from(parent.context) LayoutInflater.from(parent.context)
@ -32,18 +32,18 @@ class ShareTabsAdapter :
class ShareTabViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { class ShareTabViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
fun bind(item: ShareTab) = with(itemView) { fun bind(item: ShareData) = with(itemView) {
context.components.core.icons.loadIntoView(itemView.share_tab_favicon, item.url) context.components.core.icons.loadIntoView(itemView.share_tab_favicon, item.url.orEmpty())
itemView.share_tab_title.text = item.title itemView.share_tab_title.text = item.title
itemView.share_tab_url.text = item.url itemView.share_tab_url.text = item.url
} }
} }
private object ShareTabDiffCallback : DiffUtil.ItemCallback<ShareTab>() { private object ShareTabDiffCallback : DiffUtil.ItemCallback<ShareData>() {
override fun areItemsTheSame(oldItem: ShareTab, newItem: ShareTab) = override fun areItemsTheSame(oldItem: ShareData, newItem: ShareData) =
oldItem.url == newItem.url oldItem.url == newItem.url
override fun areContentsTheSame(oldItem: ShareTab, newItem: ShareTab) = override fun areContentsTheSame(oldItem: ShareData, newItem: ShareData) =
oldItem == newItem oldItem == newItem
} }
} }

View File

@ -542,20 +542,12 @@
android:name="org.mozilla.fenix.share.ShareFragment" android:name="org.mozilla.fenix.share.ShareFragment"
tools:layout="@layout/fragment_share"> tools:layout="@layout/fragment_share">
<argument <argument
android:name="url" android:name="data"
android:defaultValue="@null" app:argType="mozilla.components.concept.engine.prompt.ShareData[]" />
app:argType="string"
app:nullable="true" />
<argument <argument
android:name="title" android:name="showPage"
android:defaultValue="@null" app:argType="boolean"
app:argType="string" android:defaultValue="false" />
app:nullable="true" />
<argument
android:name="tabs"
android:defaultValue="@null"
app:argType="org.mozilla.fenix.share.ShareTab[]"
app:nullable="true" />
<action <action
android:id="@+id/action_shareFragment_to_turnOnSyncFragment" android:id="@+id/action_shareFragment_to_turnOnSyncFragment"
app:destination="@+id/turnOnSyncFragment" app:destination="@+id/turnOnSyncFragment"

View File

@ -34,7 +34,6 @@ import org.junit.After
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
import org.mozilla.fenix.HomeActivity import org.mozilla.fenix.HomeActivity
import org.mozilla.fenix.NavGraphDirections
import org.mozilla.fenix.R import org.mozilla.fenix.R
import org.mozilla.fenix.browser.BrowserFragment import org.mozilla.fenix.browser.BrowserFragment
import org.mozilla.fenix.browser.BrowserFragmentDirections import org.mozilla.fenix.browser.BrowserFragmentDirections
@ -306,12 +305,11 @@ class DefaultBrowserToolbarControllerTest {
val item = ToolbarMenu.Item.Share val item = ToolbarMenu.Item.Share
every { currentSession.url } returns "https://mozilla.org" every { currentSession.url } returns "https://mozilla.org"
val directions = NavGraphDirections.actionGlobalShareFragment(currentSession.url)
controller.handleToolbarItemInteraction(item) controller.handleToolbarItemInteraction(item)
verify { metrics.track(Event.BrowserMenuItemTapped(Event.BrowserMenuItemTapped.Item.SHARE)) } verify { metrics.track(Event.BrowserMenuItemTapped(Event.BrowserMenuItemTapped.Item.SHARE)) }
verify { navController.navigate(directions) } verify { navController.navigate(any<NavDirections>()) }
} }
@Test @Test

View File

@ -10,7 +10,6 @@ import android.content.Intent
import androidx.navigation.NavController import androidx.navigation.NavController
import assertk.assertAll import assertk.assertAll
import assertk.assertThat import assertk.assertThat
import assertk.assertions.isDataClassEqualTo
import assertk.assertions.isEqualTo import assertk.assertions.isEqualTo
import assertk.assertions.isNotEqualTo import assertk.assertions.isNotEqualTo
import assertk.assertions.isSameAs import assertk.assertions.isSameAs
@ -25,6 +24,7 @@ import io.mockk.slot
import io.mockk.spyk import io.mockk.spyk
import io.mockk.verify import io.mockk.verify
import io.mockk.verifyOrder import io.mockk.verifyOrder
import mozilla.components.concept.engine.prompt.ShareData
import mozilla.components.concept.sync.Device import mozilla.components.concept.sync.Device
import mozilla.components.concept.sync.DeviceType import mozilla.components.concept.sync.DeviceType
import mozilla.components.concept.sync.TabData import mozilla.components.concept.sync.TabData
@ -50,22 +50,22 @@ class ShareControllerTest {
// Need a valid context to retrieve Strings for example, but we also need it to return our "metrics" // Need a valid context to retrieve Strings for example, but we also need it to return our "metrics"
private val context: Context = spyk(testContext) private val context: Context = spyk(testContext)
private val metrics: MetricController = mockk(relaxed = true) private val metrics: MetricController = mockk(relaxed = true)
private val shareTabs = listOf( private val shareData = listOf(
ShareTab("url0", "title0"), ShareData(url = "url0", title = "title0"),
ShareTab("url1", "title1") ShareData(url = "url1", title = "title1")
) )
// Navigation between app fragments uses ShareTab as arguments. SendTabUseCases uses TabData. // Navigation between app fragments uses ShareTab as arguments. SendTabUseCases uses TabData.
private val tabsData = listOf( private val tabsData = listOf(
TabData("title0", "url0"), TabData("title0", "url0"),
TabData("title1", "url1") TabData("title1", "url1")
) )
private val textToShare = "${shareTabs[0].url}\n${shareTabs[1].url}" private val textToShare = "${shareData[0].url}\n${shareData[1].url}"
private val sendTabUseCases = mockk<SendTabUseCases>(relaxed = true) private val sendTabUseCases = mockk<SendTabUseCases>(relaxed = true)
private val snackbarPresenter = mockk<FenixSnackbarPresenter>(relaxed = true) private val snackbarPresenter = mockk<FenixSnackbarPresenter>(relaxed = true)
private val navController = mockk<NavController>(relaxed = true) private val navController = mockk<NavController>(relaxed = true)
private val dismiss = mockk<() -> Unit>(relaxed = true) private val dismiss = mockk<() -> Unit>(relaxed = true)
private val controller = DefaultShareController( private val controller = DefaultShareController(
context, shareTabs, sendTabUseCases, snackbarPresenter, navController, dismiss context, shareData, sendTabUseCases, snackbarPresenter, navController, dismiss
) )
@Before @Before
@ -90,7 +90,7 @@ class ShareControllerTest {
// needed for capturing the actual Intent used the `slot` one doesn't have this flag so we // needed for capturing the actual Intent used the `slot` one doesn't have this flag so we
// need to use an Activity Context. // need to use an Activity Context.
val activityContext: Context = mockk<Activity>() val activityContext: Context = mockk<Activity>()
val testController = DefaultShareController(activityContext, shareTabs, mockk(), mockk(), mockk(), dismiss) val testController = DefaultShareController(activityContext, shareData, mockk(), mockk(), mockk(), dismiss)
every { activityContext.startActivity(capture(shareIntent)) } just Runs every { activityContext.startActivity(capture(shareIntent)) } just Runs
testController.handleShareToApp(appShareOption) testController.handleShareToApp(appShareOption)
@ -245,7 +245,7 @@ class ShareControllerTest {
@Test @Test
fun `getSuccessMessage should return different strings depending on the number of shared tabs`() { fun `getSuccessMessage should return different strings depending on the number of shared tabs`() {
val controllerWithOneSharedTab = DefaultShareController( val controllerWithOneSharedTab = DefaultShareController(
context, listOf(ShareTab("url0", "title0")), mockk(), mockk(), mockk(), mockk() context, listOf(ShareData(url = "url0", title = "title0")), mockk(), mockk(), mockk(), mockk()
) )
val controllerWithMoreSharedTabs = controller val controllerWithMoreSharedTabs = controller
val expectedTabSharedMessage = context.getString(R.string.sync_sent_tab_snackbar) val expectedTabSharedMessage = context.getString(R.string.sync_sent_tab_snackbar)
@ -266,23 +266,12 @@ class ShareControllerTest {
assertThat(controller.getShareText()).isEqualTo(textToShare) assertThat(controller.getShareText()).isEqualTo(textToShare)
} }
@Test
fun `ShareTab#toTabData maps a ShareTab to a TabData`() {
var tabData: TabData
with(controller) {
tabData = shareTabs[0].toTabData()
}
assertThat(tabData).isDataClassEqualTo(tabsData[0])
}
@Test @Test
fun `ShareTab#toTabData maps a list of ShareTab to a TabData list`() { fun `ShareTab#toTabData maps a list of ShareTab to a TabData list`() {
var tabData: List<TabData> var tabData: List<TabData>
with(controller) { with(controller) {
tabData = shareTabs.toTabData() tabData = shareData.toTabData()
} }
assertThat(tabData).isEqualTo(tabsData) assertThat(tabData).isEqualTo(tabsData)