* For #2886: Fix sending multiple tabs to another device * Update share methods to use new APImaster
parent
65fe58e24a
commit
3da6cfd98a
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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"
|
||||||
|
|
Loading…
Reference in New Issue