1
0
Fork 0

Adds send tab functionality to UI (#2790)

* Closes #2782: Hide send tab when no devices available

* For #2752: Enabled send tab for debug and nightly builds

* For #2753: Add Send Tab functionality to UI
master
Jonathan Almeida 2019-05-23 18:38:03 -04:00 committed by Stefan Arentz
parent 6b8938e47e
commit 8fbbcceb21
6 changed files with 57 additions and 10 deletions

View File

@ -241,7 +241,7 @@ android.applicationVariants.all { variant ->
// ------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------
// Feature build flags // Feature build flags
// ------------------------------------------------------------------------------------------------- // -------------------------------------------------------------------------------------------------
buildConfigField 'Boolean', 'SEND_TAB_ENABLED', "false" buildConfigField 'Boolean', 'SEND_TAB_ENABLED', (buildType == "nightly" || !isReleased).toString()
} }
androidExtensions { androidExtensions {

View File

@ -60,13 +60,14 @@ class AccountDevicesShareAdapter(
return list return list
} }
list.add(SyncShareOption.AddNewDevice)
accountManager.authenticatedAccount()?.deviceConstellation()?.state()?.otherDevices?.let { devices -> accountManager.authenticatedAccount()?.deviceConstellation()?.state()?.otherDevices?.let { devices ->
val shareableDevices = devices val shareableDevices = devices.filter { it.capabilities.contains(DeviceCapability.SEND_TAB) }
.filter {
it.capabilities.contains(DeviceCapability.SEND_TAB) if (shareableDevices.isEmpty()) {
} list.add(SyncShareOption.AddNewDevice)
actionEmitter.onNext(ShareAction.HideSendTab)
}
val shareOptions = shareableDevices.map { val shareOptions = shareableDevices.map {
when (it.deviceType) { when (it.deviceType) {
DeviceType.MOBILE -> SyncShareOption.Mobile(it.displayName, it) DeviceType.MOBILE -> SyncShareOption.Mobile(it.displayName, it)

View File

@ -23,6 +23,7 @@ sealed class ShareAction : Action {
object Close : ShareAction() object Close : ShareAction()
object SignInClicked : ShareAction() object SignInClicked : ShareAction()
object AddNewDeviceClicked : ShareAction() object AddNewDeviceClicked : ShareAction()
object HideSendTab : ShareAction()
data class ShareDeviceClicked(val device: Device) : ShareAction() data class ShareDeviceClicked(val device: Device) : ShareAction()
data class SendAllClicked(val devices: List<Device>) : ShareAction() data class SendAllClicked(val devices: List<Device>) : ShareAction()
data class ShareAppClicked(val packageName: String) : ShareAction() data class ShareAppClicked(val packageName: String) : ShareAction()

View File

@ -12,11 +12,14 @@ import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.fragment.app.DialogFragment import androidx.appcompat.app.AppCompatDialogFragment
import androidx.navigation.fragment.NavHostFragment.findNavController
import kotlinx.android.synthetic.main.component_share.*
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 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
@ -24,12 +27,13 @@ import org.mozilla.fenix.mvi.ActionBusFactory
import org.mozilla.fenix.mvi.getAutoDisposeObservable import org.mozilla.fenix.mvi.getAutoDisposeObservable
import kotlin.coroutines.CoroutineContext import kotlin.coroutines.CoroutineContext
class ShareFragment : DialogFragment(), CoroutineScope { class ShareFragment : AppCompatDialogFragment(), CoroutineScope {
override val coroutineContext: CoroutineContext override val coroutineContext: CoroutineContext
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 lateinit var url: String
private lateinit var title: String
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@ -42,6 +46,7 @@ class ShareFragment : DialogFragment(), CoroutineScope {
job = Job() job = Job()
url = args.url url = args.url
title = args.title ?: ""
component = ShareComponent( component = ShareComponent(
view.share_wrapper, view.share_wrapper,
ActionBusFactory.get(this), ActionBusFactory.get(this),
@ -66,15 +71,43 @@ class ShareFragment : DialogFragment(), CoroutineScope {
job.cancel() job.cancel()
} }
@SuppressWarnings("ComplexMethod")
private fun subscribeToActions() { private fun subscribeToActions() {
getAutoDisposeObservable<ShareAction>().subscribe { getAutoDisposeObservable<ShareAction>().subscribe {
when (it) { when (it) {
ShareAction.Close -> { ShareAction.Close -> {
dismiss() dismiss()
} }
ShareAction.SignInClicked -> {
val directions = ShareFragmentDirections.actionShareFragmentToTurnOnSyncFragment()
findNavController(this@ShareFragment).navigate(directions)
}
ShareAction.AddNewDeviceClicked -> { ShareAction.AddNewDeviceClicked -> {
requireComponents.useCases.tabsUseCases.addTab.invoke(ADD_NEW_DEVICES_URL, true) requireComponents.useCases.tabsUseCases.addTab.invoke(ADD_NEW_DEVICES_URL, true)
} }
ShareAction.HideSendTab -> {
send_tab_group.visibility = View.GONE
}
is ShareAction.ShareDeviceClicked -> {
val authAccount = requireComponents.backgroundServices.accountManager.authenticatedAccount()
authAccount?.run {
deviceConstellation().sendEventToDeviceAsync(
it.device.id,
DeviceEventOutgoing.SendTab(title, url)
)
}
}
is ShareAction.SendAllClicked -> {
val authAccount = requireComponents.backgroundServices.accountManager.authenticatedAccount()
authAccount?.run {
it.devices.forEach { device ->
deviceConstellation().sendEventToDeviceAsync(
device.id,
DeviceEventOutgoing.SendTab(title, url)
)
}
}
}
is ShareAction.ShareAppClicked -> { is ShareAction.ShareAppClicked -> {
val intent = Intent(ACTION_SEND).apply { val intent = Intent(ACTION_SEND).apply {
putExtra(EXTRA_TEXT, url) putExtra(EXTRA_TEXT, url)
@ -84,13 +117,13 @@ class ShareFragment : DialogFragment(), CoroutineScope {
} }
startActivity(intent) startActivity(intent)
} }
// TODO support other actions in a follow-up issue
} }
dismiss() dismiss()
} }
} }
companion object { companion object {
// TODO Replace this link with the correct one when provided.
const val ADD_NEW_DEVICES_URL = "https://accounts.firefox.com/connect_another_device" const val ADD_NEW_DEVICES_URL = "https://accounts.firefox.com/connect_another_device"
} }
} }

View File

@ -17,6 +17,8 @@
android:importantForAccessibility="no" android:importantForAccessibility="no"
android:layout_marginTop="8dp" android:layout_marginTop="8dp"
android:background="@drawable/device_background" android:background="@drawable/device_background"
android:clickable="false"
android:focusable="false"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"

View File

@ -395,6 +395,16 @@
<argument <argument
android:name="url" android:name="url"
app:argType="string" /> app:argType="string" />
<argument
android:name="title"
android:defaultValue="@null"
app:argType="string"
app:nullable="true" />
<action
android:id="@+id/action_shareFragment_to_turnOnSyncFragment"
app:destination="@+id/turnOnSyncFragment"
app:popUpTo="@id/shareFragment"
app:popUpToInclusive="true" />
</dialog> </dialog>
<dialog <dialog
android:id="@+id/quickSettingsSheetDialogFragment" android:id="@+id/quickSettingsSheetDialogFragment"