1
0
Fork 0

For #2886: Fix sending multiple tabs to another device (#2923)

* For #2886: Fix sending multiple tabs to another device

* Update share methods to use new API
master
Jonathan Almeida 2019-05-28 18:05:16 -04:00 committed by Sawyer Blatz
parent 65fe58e24a
commit 3da6cfd98a
5 changed files with 61 additions and 36 deletions

View File

@ -70,6 +70,7 @@ import org.mozilla.fenix.mvi.getAutoDisposeObservable
import org.mozilla.fenix.mvi.getManagedEmitter 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.share.ShareTab
import org.mozilla.fenix.utils.ItsNotBrokenSnack import org.mozilla.fenix.utils.ItsNotBrokenSnack
import kotlin.coroutines.CoroutineContext import kotlin.coroutines.CoroutineContext
import kotlin.math.roundToInt import kotlin.math.roundToInt
@ -323,10 +324,9 @@ class HomeFragment : Fragment(), CoroutineScope, AccountObserver {
} }
is TabAction.Share -> { is TabAction.Share -> {
invokePendingDeleteJobs() invokePendingDeleteJobs()
requireComponents.core.sessionManager.findSessionById(action.sessionId) requireComponents.core.sessionManager.findSessionById(action.sessionId)?.let { session ->
?.let { session -> share(session.url)
share(session.url) }
}
} }
is TabAction.CloseAll -> { is TabAction.CloseAll -> {
removeAllTabsWithUndo(action.private) removeAllTabsWithUndo(action.private)
@ -346,10 +346,10 @@ class HomeFragment : Fragment(), CoroutineScope, AccountObserver {
} }
is TabAction.ShareTabs -> { is TabAction.ShareTabs -> {
invokePendingDeleteJobs() invokePendingDeleteJobs()
val shareText = requireComponents.core.sessionManager.sessions.joinToString("\n") { val shareTabs = requireComponents.core.sessionManager.sessions.map {
it.url ShareTab(it.url, it.title, it.id)
} }
share(shareText) share(tabs = shareTabs)
} }
} }
} }
@ -433,10 +433,8 @@ class HomeFragment : Fragment(), CoroutineScope, AccountObserver {
} }
} }
is CollectionAction.ShareTabs -> { is CollectionAction.ShareTabs -> {
val shareText = action.collection.tabs.joinToString("\n") { val shareTabs = action.collection.tabs.map { ShareTab(it.url, it.title) }
it.url share(tabs = shareTabs)
}
share(shareText)
} }
is CollectionAction.RemoveTab -> { is CollectionAction.RemoveTab -> {
launch(Dispatchers.IO) { launch(Dispatchers.IO) {
@ -664,8 +662,9 @@ class HomeFragment : Fragment(), CoroutineScope, AccountObserver {
} }
} }
private fun share(text: String) { private fun share(url: String? = null, tabs: List<ShareTab>? = null) {
val directions = HomeFragmentDirections.actionHomeFragmentToShareFragment(text) val directions =
HomeFragmentDirections.actionHomeFragmentToShareFragment(url = url, tabs = tabs?.toTypedArray())
Navigation.findNavController(view!!).navigate(directions) Navigation.findNavController(view!!).navigate(directions)
} }

View File

@ -223,10 +223,12 @@ class BookmarkFragment : Fragment(), CoroutineScope, BackHandler, AccountObserve
} }
is BookmarkAction.Share -> { is BookmarkAction.Share -> {
it.item.url?.apply { it.item.url?.apply {
navigation navigation.navigate(
.navigate( BookmarkFragmentDirections.actionBookmarkFragmentToShareFragment(
BookmarkFragmentDirections.actionBookmarkFragmentToShareFragment(this) this,
it.item.title
) )
)
requireComponents.analytics.metrics.track(Event.ShareBookmark) requireComponents.analytics.metrics.track(Event.ShareBookmark)
} }
} }

View File

@ -41,6 +41,7 @@ import org.mozilla.fenix.ext.requireComponents
import org.mozilla.fenix.mvi.ActionBusFactory import org.mozilla.fenix.mvi.ActionBusFactory
import org.mozilla.fenix.mvi.getAutoDisposeObservable import org.mozilla.fenix.mvi.getAutoDisposeObservable
import org.mozilla.fenix.mvi.getManagedEmitter import org.mozilla.fenix.mvi.getManagedEmitter
import org.mozilla.fenix.share.ShareTab
import java.net.MalformedURLException import java.net.MalformedURLException
import java.net.URL import java.net.URL
import kotlin.coroutines.CoroutineContext import kotlin.coroutines.CoroutineContext
@ -183,10 +184,8 @@ class HistoryFragment : Fragment(), CoroutineScope, BackHandler {
when { when {
selectedHistory.size == 1 -> share(selectedHistory.first().url) selectedHistory.size == 1 -> share(selectedHistory.first().url)
selectedHistory.size > 1 -> { selectedHistory.size > 1 -> {
val shareText = selectedHistory.joinToString("\n") { val shareTabs = selectedHistory.map { ShareTab(it.url, it.title) }
it.url share(tabs = shareTabs)
}
share(shareText)
} }
} }
true true
@ -283,8 +282,9 @@ class HistoryFragment : Fragment(), CoroutineScope, BackHandler {
} }
} }
private fun share(text: String) { private fun share(url: String? = null, tabs: List<ShareTab>? = null) {
val directions = HistoryFragmentDirections.actionHistoryFragmentToShareFragment(text) val directions =
HistoryFragmentDirections.actionHistoryFragmentToShareFragment(url = url, tabs = tabs?.toTypedArray())
Navigation.findNavController(view!!).navigate(directions) Navigation.findNavController(view!!).navigate(directions)
} }
} }

View File

@ -9,6 +9,7 @@ import android.content.Intent.ACTION_SEND
import android.content.Intent.EXTRA_TEXT import android.content.Intent.EXTRA_TEXT
import android.content.Intent.FLAG_ACTIVITY_NEW_TASK import android.content.Intent.FLAG_ACTIVITY_NEW_TASK
import android.os.Bundle import android.os.Bundle
import android.os.Parcelable
import android.view.ContextThemeWrapper import android.view.ContextThemeWrapper
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
@ -16,11 +17,13 @@ import android.view.ViewGroup
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatDialogFragment import androidx.appcompat.app.AppCompatDialogFragment
import androidx.navigation.fragment.NavHostFragment.findNavController import androidx.navigation.fragment.NavHostFragment.findNavController
import kotlinx.android.parcel.Parcelize
import kotlinx.android.synthetic.main.fragment_share.view.* import kotlinx.android.synthetic.main.fragment_share.view.*
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
import mozilla.components.concept.sync.DeviceEventOutgoing import mozilla.components.concept.sync.DeviceEventOutgoing
import mozilla.components.concept.sync.OAuthAccount
import org.mozilla.fenix.FenixViewModelProvider import org.mozilla.fenix.FenixViewModelProvider
import org.mozilla.fenix.R import org.mozilla.fenix.R
import org.mozilla.fenix.ext.requireComponents import org.mozilla.fenix.ext.requireComponents
@ -33,8 +36,7 @@ class ShareFragment : AppCompatDialogFragment(), CoroutineScope {
get() = Dispatchers.Main + job get() = Dispatchers.Main + job
private lateinit var job: Job private lateinit var job: Job
private lateinit var component: ShareComponent private lateinit var component: ShareComponent
private lateinit var url: String private var tabs: Array<ShareTab> = emptyArray()
private lateinit var title: String
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@ -45,9 +47,13 @@ class ShareFragment : AppCompatDialogFragment(), CoroutineScope {
val view = inflater.inflate(R.layout.fragment_share, container, false) val view = inflater.inflate(R.layout.fragment_share, container, false)
val args = ShareFragmentArgs.fromBundle(arguments!!) val args = ShareFragmentArgs.fromBundle(arguments!!)
if (args.url == null && args.tabs.isNullOrEmpty()) {
throw IllegalStateException("URL and tabs cannot both be null.")
}
job = Job() job = Job()
url = args.url tabs = args.tabs ?: arrayOf(ShareTab(args.url!!, args.title ?: ""))
title = args.title ?: ""
component = ShareComponent( component = ShareComponent(
view.share_wrapper, view.share_wrapper,
ActionBusFactory.get(this), ActionBusFactory.get(this),
@ -99,10 +105,7 @@ class ShareFragment : AppCompatDialogFragment(), CoroutineScope {
is ShareAction.ShareDeviceClicked -> { is ShareAction.ShareDeviceClicked -> {
val authAccount = requireComponents.backgroundServices.accountManager.authenticatedAccount() val authAccount = requireComponents.backgroundServices.accountManager.authenticatedAccount()
authAccount?.run { authAccount?.run {
deviceConstellation().sendEventToDeviceAsync( sendSendTab(this, it.device.id, tabs)
it.device.id,
DeviceEventOutgoing.SendTab(title, url)
)
} }
dismiss() dismiss()
} }
@ -110,17 +113,17 @@ class ShareFragment : AppCompatDialogFragment(), CoroutineScope {
val authAccount = requireComponents.backgroundServices.accountManager.authenticatedAccount() val authAccount = requireComponents.backgroundServices.accountManager.authenticatedAccount()
authAccount?.run { authAccount?.run {
it.devices.forEach { device -> it.devices.forEach { device ->
deviceConstellation().sendEventToDeviceAsync( sendSendTab(this, device.id, tabs)
device.id,
DeviceEventOutgoing.SendTab(title, url)
)
} }
} }
dismiss() dismiss()
} }
is ShareAction.ShareAppClicked -> { is ShareAction.ShareAppClicked -> {
val shareText = tabs.joinToString("\n") { tab -> tab.url }
val intent = Intent(ACTION_SEND).apply { val intent = Intent(ACTION_SEND).apply {
putExtra(EXTRA_TEXT, url) putExtra(EXTRA_TEXT, shareText)
type = "text/plain" type = "text/plain"
flags = FLAG_ACTIVITY_NEW_TASK flags = FLAG_ACTIVITY_NEW_TASK
`package` = it.packageName `package` = it.packageName
@ -131,4 +134,18 @@ class ShareFragment : AppCompatDialogFragment(), CoroutineScope {
} }
} }
} }
private fun sendSendTab(account: OAuthAccount, deviceId: String, tabs: Array<ShareTab>) {
account.run {
tabs.forEach { tab ->
deviceConstellation().sendEventToDeviceAsync(
deviceId,
DeviceEventOutgoing.SendTab(tab.title, tab.url)
)
}
}
}
} }
@Parcelize
data class ShareTab(val url: String, val title: String, val sessionId: String? = null) : Parcelable

View File

@ -402,12 +402,19 @@
tools:layout="@layout/fragment_share" > tools:layout="@layout/fragment_share" >
<argument <argument
android:name="url" android:name="url"
app:argType="string" /> android:defaultValue="@null"
app:argType="string"
app:nullable="true" />
<argument <argument
android:name="title" android:name="title"
android:defaultValue="@null" android:defaultValue="@null"
app:argType="string" app:argType="string"
app:nullable="true" /> app:nullable="true" />
<argument
android:name="tabs"
android:defaultValue="@null"
app:nullable="true"
app:argType="org.mozilla.fenix.share.ShareTab[]" />
<action <action
android:id="@+id/action_shareFragment_to_turnOnSyncFragment" android:id="@+id/action_shareFragment_to_turnOnSyncFragment"
app:destination="@+id/turnOnSyncFragment" app:destination="@+id/turnOnSyncFragment"