1
0
Fork 0

For #2897 - Add Action States To Share Sheet

master
Emily Kager 2019-09-05 11:13:03 -07:00 committed by Emily Kager
parent 2e2bac4ccd
commit 9a4610f068
9 changed files with 112 additions and 11 deletions

View File

@ -28,6 +28,7 @@ import org.mozilla.fenix.share.listadapters.AppShareOption
* Delegated by View Interactors, handles container business logic and operates changes on it.
*/
interface ShareController {
fun handleReauth()
fun handleShareClosed()
fun handleShareToApp(app: AppShareOption)
fun handleAddNewDevice()
@ -53,6 +54,12 @@ class DefaultShareController(
private val navController: NavController,
private val dismiss: () -> Unit
) : ShareController {
override fun handleReauth() {
val directions = ShareFragmentDirections.actionShareFragmentToAccountProblemFragment()
navController.nav(R.id.shareFragment, directions)
dismiss()
}
override fun handleShareClosed() {
dismiss()
}

View File

@ -9,6 +9,9 @@ import android.content.Intent
import android.content.Intent.ACTION_SEND
import android.content.Intent.FLAG_ACTIVITY_NEW_TASK
import android.content.pm.ResolveInfo
import android.net.ConnectivityManager
import android.net.Network
import android.net.NetworkRequest
import android.os.Bundle
import android.os.Parcelable
import android.view.LayoutInflater
@ -45,10 +48,16 @@ class ShareFragment : AppCompatDialogFragment() {
private lateinit var shareToAppsView: ShareToAppsView
private lateinit var appsListDeferred: Deferred<List<AppShareOption>>
private lateinit var devicesListDeferred: Deferred<List<SyncShareOption>>
private var connectivityManager: ConnectivityManager? = null
override fun onAttach(context: Context) {
super.onAttach(context)
connectivityManager =
context.getSystemService(Context.CONNECTIVITY_SERVICE) as? ConnectivityManager
val networkRequest = NetworkRequest.Builder().build()
connectivityManager?.registerNetworkCallback(networkRequest, networkCallback)
// Start preparing the data as soon as we have a valid Context
appsListDeferred = lifecycleScope.async(Dispatchers.IO) {
val shareIntent = Intent(ACTION_SEND).apply {
@ -70,6 +79,35 @@ class ShareFragment : AppCompatDialogFragment() {
setStyle(STYLE_NO_TITLE, R.style.ShareDialogStyle)
}
private val networkCallback = object : ConnectivityManager.NetworkCallback() {
override fun onLost(network: Network?) {
reloadDevices()
}
override fun onAvailable(network: Network?) {
reloadDevices()
}
}
private fun reloadDevices() {
context?.let {
val fxaAccountManager = it.components.backgroundServices.accountManager
lifecycleScope.launch {
val refreshDevicesAsync =
fxaAccountManager.authenticatedAccount()?.deviceConstellation()
?.refreshDevicesAsync()
refreshDevicesAsync?.await()
val devicesShareOptions = buildDeviceList(fxaAccountManager)
shareToAccountDevicesView.setSharetargets(devicesShareOptions)
}
}
}
override fun onDetach() {
connectivityManager?.unregisterNetworkCallback(networkCallback)
super.onDetach()
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
@ -95,11 +133,8 @@ class ShareFragment : AppCompatDialogFragment() {
)
)
if (isSharingToDevicesAvailable(requireContext().applicationContext)) {
shareToAccountDevicesView = ShareToAccountDevicesView(view.devicesShareLayout, shareInteractor)
} else {
view.devicesShareGroup.visibility = View.GONE
}
shareToAccountDevicesView =
ShareToAccountDevicesView(view.devicesShareLayout, shareInteractor)
shareCloseView = ShareCloseView(view.closeSharingLayout, shareInteractor)
shareToAppsView = ShareToAppsView(view.appsShareLayout, shareInteractor)
@ -117,14 +152,14 @@ class ShareFragment : AppCompatDialogFragment() {
}
}
private fun isSharingToDevicesAvailable(context: Context) =
!context.components.backgroundServices.accountManager.accountNeedsReauth()
private fun getIntentActivities(shareIntent: Intent, context: Context): List<ResolveInfo>? {
return context.packageManager.queryIntentActivities(shareIntent, 0)
}
private fun buildAppsList(intentActivities: List<ResolveInfo>?, context: Context): List<AppShareOption> {
private fun buildAppsList(
intentActivities: List<ResolveInfo>?,
context: Context
): List<AppShareOption> {
return intentActivities?.map { resolveInfo ->
AppShareOption(
resolveInfo.loadLabel(context.packageManager).toString(),
@ -135,16 +170,30 @@ class ShareFragment : AppCompatDialogFragment() {
} ?: emptyList()
}
@Suppress("ReturnCount")
private fun buildDeviceList(accountManager: FxaAccountManager): List<SyncShareOption> {
val list = mutableListOf<SyncShareOption>()
val activeNetwork = connectivityManager?.activeNetworkInfo
if (activeNetwork?.isConnected != true) {
list.add(SyncShareOption.Offline)
return list
}
if (accountManager.authenticatedAccount() == null) {
list.add(SyncShareOption.SignIn)
return list
}
accountManager.authenticatedAccount()?.deviceConstellation()?.state()?.otherDevices?.let { devices ->
val shareableDevices = devices.filter { it.capabilities.contains(DeviceCapability.SEND_TAB) }
if (accountManager.accountNeedsReauth()) {
list.add(SyncShareOption.Reconnect)
return list
}
accountManager.authenticatedAccount()?.deviceConstellation()?.state()
?.otherDevices?.let { devices ->
val shareableDevices =
devices.filter { it.capabilities.contains(DeviceCapability.SEND_TAB) }
if (shareableDevices.isEmpty()) {
list.add(SyncShareOption.AddNewDevice)

View File

@ -13,6 +13,10 @@ import org.mozilla.fenix.share.listadapters.AppShareOption
class ShareInteractor(
private val controller: ShareController
) : ShareCloseInteractor, ShareToAccountDevicesInteractor, ShareToAppsInteractor {
override fun onReauth() {
controller.handleReauth()
}
override fun onShareClosed() {
controller.handleShareClosed()
}

View File

@ -18,6 +18,7 @@ import org.mozilla.fenix.share.listadapters.SyncShareOption
*/
interface ShareToAccountDevicesInteractor {
fun onSignIn()
fun onReauth()
fun onAddNewDevice()
fun onShareToDevice(device: Device)
fun onShareToAllDevices(devices: List<Device>)

View File

@ -37,6 +37,8 @@ class AccountDevicesShareAdapter(
}
sealed class SyncShareOption {
object Reconnect : SyncShareOption()
object Offline : SyncShareOption()
object SignIn : SyncShareOption()
object AddNewDevice : SyncShareOption()
data class SendAll(val devices: List<Device>) : SyncShareOption()

View File

@ -37,6 +37,10 @@ class AccountDeviceViewHolder(
is SyncShareOption.SendAll -> interactor.onShareToAllDevices(option.devices)
is SyncShareOption.Mobile -> interactor.onShareToDevice(option.device)
is SyncShareOption.Desktop -> interactor.onShareToDevice(option.device)
SyncShareOption.Reconnect -> interactor.onReauth()
SyncShareOption.Offline -> {
// nothing we are offline
}
}
}
}
@ -48,6 +52,16 @@ class AccountDeviceViewHolder(
R.drawable.mozac_ic_sync,
R.color.default_share_background
)
SyncShareOption.Reconnect -> Triple(
context.getText(R.string.sync_reconnect),
R.drawable.mozac_ic_warning,
R.color.default_share_background
)
SyncShareOption.Offline -> Triple(
context.getText(R.string.sync_offline),
R.drawable.mozac_ic_warning,
R.color.default_share_background
)
SyncShareOption.AddNewDevice -> Triple(
context.getText(R.string.sync_connect_device),
R.drawable.mozac_ic_new,
@ -75,6 +89,7 @@ class AccountDeviceViewHolder(
background.setColorFilter(ContextCompat.getColor(context, colorRes), PorterDuff.Mode.SRC_IN)
drawable.setTint(ContextCompat.getColor(context, R.color.device_foreground))
}
itemView.isClickable = option != SyncShareOption.Offline
itemView.deviceName.text = name
}

View File

@ -490,6 +490,9 @@
app:destination="@+id/turnOnSyncFragment"
app:popUpTo="@id/shareFragment"
app:popUpToInclusive="true" />
<action
android:id="@+id/action_shareFragment_to_accountProblemFragment"
app:destination="@id/accountProblemFragment" />
</dialog>
<dialog
android:id="@+id/quickSettingsSheetDialogFragment"

View File

@ -175,6 +175,19 @@ class ShareControllerTest {
}
}
@Test
fun `handleReauth should navigate to the Account Problem Fragment and dismiss this one`() {
controller.handleReauth()
verifyOrder {
navController.nav(
R.id.shareFragment,
ShareFragmentDirections.actionShareFragmentToAccountProblemFragment()
)
dismiss()
}
}
@Test
fun `getShareText should respect concatenate shared tabs urls`() {
assertThat(controller.getShareText()).isEqualTo(textToShare)

View File

@ -28,6 +28,13 @@ class ShareInteractorTest {
verify { controller.handleSignIn() }
}
@Test
fun onReauth() {
interactor.onReauth()
verify { controller.handleReauth() }
}
@Test
fun onAddNewDevice() {
interactor.onAddNewDevice()