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 UImaster
parent
6b8938e47e
commit
8fbbcceb21
|
@ -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 {
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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"
|
||||||
|
|
Loading…
Reference in New Issue