mirror of
https://github.com/fork-maintainers/iceraven-browser
synced 2024-11-17 15:26:23 +00:00
[fenix] For https://github.com/mozilla-mobile/fenix/issues/4007 - ShareFragment will set the contained Views' state
ShareFragment which acts as a container would contain all business logic needed for populating it's Views. Data initialization should be done only once since the app state has no reason to change after the ShareFragment is created and is done as soon as possible, in onAttach(). Because of the expected short lifespan of this fragment, given the fact that the state has no reason to change and we handle orientation changes ourselves to keep things simple I didn't use a ViewModel to persist the state.
This commit is contained in:
parent
a8cbf8b1d8
commit
051f09a15a
@ -4,16 +4,33 @@
|
||||
|
||||
package org.mozilla.fenix.share
|
||||
|
||||
import android.content.Context
|
||||
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.os.Bundle
|
||||
import android.os.Parcelable
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.appcompat.app.AppCompatDialogFragment
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import kotlinx.android.parcel.Parcelize
|
||||
import kotlinx.android.synthetic.main.fragment_share.view.*
|
||||
import kotlinx.coroutines.Deferred
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.launch
|
||||
import mozilla.components.concept.sync.DeviceCapability
|
||||
import mozilla.components.concept.sync.DeviceType
|
||||
import mozilla.components.service.fxa.manager.FxaAccountManager
|
||||
import org.mozilla.fenix.R
|
||||
import org.mozilla.fenix.ext.components
|
||||
import org.mozilla.fenix.share.listadapters.AppShareOption
|
||||
import org.mozilla.fenix.share.listadapters.SyncShareOption
|
||||
|
||||
@Suppress("TooManyFunctions")
|
||||
class ShareFragment : AppCompatDialogFragment() {
|
||||
interface TabsSharedCallback {
|
||||
fun onTabsShared(tabsSize: Int)
|
||||
@ -23,7 +40,27 @@ class ShareFragment : AppCompatDialogFragment() {
|
||||
private lateinit var shareCloseView: ShareCloseView
|
||||
private lateinit var shareToAccountDevicesView: ShareToAccountDevicesView
|
||||
private lateinit var shareToAppsView: ShareToAppsView
|
||||
private var tabs: Array<ShareTab> = emptyArray()
|
||||
private lateinit var appsListDeferred: Deferred<List<AppShareOption>>
|
||||
private lateinit var devicesListDeferred: Deferred<List<SyncShareOption>>
|
||||
|
||||
override fun onAttach(context: Context) {
|
||||
super.onAttach(context)
|
||||
|
||||
// Start preparing the data as soon as we have a valid Context
|
||||
appsListDeferred = lifecycleScope.async(Dispatchers.IO) {
|
||||
val shareIntent = Intent(ACTION_SEND).apply {
|
||||
type = "text/plain"
|
||||
flags = FLAG_ACTIVITY_NEW_TASK
|
||||
}
|
||||
val shareAppsActivities = getIntentActivities(shareIntent, context)
|
||||
buildAppsList(shareAppsActivities, context)
|
||||
}
|
||||
|
||||
devicesListDeferred = lifecycleScope.async(Dispatchers.IO) {
|
||||
val fxaAccountManager = context.components.backgroundServices.accountManager
|
||||
buildDeviceList(fxaAccountManager)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
@ -41,16 +78,79 @@ class ShareFragment : AppCompatDialogFragment() {
|
||||
throw IllegalStateException("URL and tabs cannot both be null.")
|
||||
}
|
||||
|
||||
tabs = args.tabs ?: arrayOf(ShareTab(args.url!!, args.title ?: ""))
|
||||
val tabs = args.tabs?.toList() ?: listOf(ShareTab(args.url!!, args.title ?: ""))
|
||||
|
||||
shareInteractor = ShareInteractor()
|
||||
|
||||
shareCloseView = ShareCloseView(view.closeSharingLayout, shareInteractor)
|
||||
if (isSharingToDevicesAvailable(requireContext().applicationContext)) {
|
||||
shareToAccountDevicesView = ShareToAccountDevicesView(view.devicesShareLayout, shareInteractor)
|
||||
} else {
|
||||
view.devicesShareGroup.visibility = View.GONE
|
||||
}
|
||||
shareCloseView = ShareCloseView(view.closeSharingLayout, shareInteractor)
|
||||
shareToAppsView = ShareToAppsView(view.appsShareLayout, shareInteractor)
|
||||
|
||||
return view
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
lifecycleScope.launch {
|
||||
val devicesShareOptions = devicesListDeferred.await()
|
||||
shareToAccountDevicesView.setSharetargets(devicesShareOptions)
|
||||
val appsToShareTo = appsListDeferred.await()
|
||||
shareToAppsView.setSharetargets(appsToShareTo)
|
||||
}
|
||||
}
|
||||
|
||||
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> {
|
||||
return intentActivities?.map { resolveInfo ->
|
||||
AppShareOption(
|
||||
resolveInfo.loadLabel(context.packageManager).toString(),
|
||||
resolveInfo.loadIcon(context.packageManager),
|
||||
resolveInfo.activityInfo.packageName,
|
||||
resolveInfo.activityInfo.name
|
||||
)
|
||||
} ?: emptyList()
|
||||
}
|
||||
|
||||
private fun buildDeviceList(accountManager: FxaAccountManager): List<SyncShareOption> {
|
||||
val list = mutableListOf<SyncShareOption>()
|
||||
|
||||
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 (shareableDevices.isEmpty()) {
|
||||
list.add(SyncShareOption.AddNewDevice)
|
||||
}
|
||||
|
||||
val shareOptions = shareableDevices.map {
|
||||
when (it.deviceType) {
|
||||
DeviceType.MOBILE -> SyncShareOption.Mobile(it.displayName, it)
|
||||
else -> SyncShareOption.Desktop(it.displayName, it)
|
||||
}
|
||||
}
|
||||
list.addAll(shareOptions)
|
||||
|
||||
if (shareableDevices.size > 1) {
|
||||
list.add(SyncShareOption.SendAll(shareableDevices))
|
||||
}
|
||||
}
|
||||
return list
|
||||
}
|
||||
}
|
||||
|
||||
@Parcelize
|
||||
|
@ -5,7 +5,7 @@
|
||||
package org.mozilla.fenix.share
|
||||
|
||||
import mozilla.components.concept.sync.Device
|
||||
import org.mozilla.fenix.share.listadapters.Application
|
||||
import org.mozilla.fenix.share.listadapters.AppShareOption
|
||||
|
||||
/**
|
||||
* Interactor for the share screen.
|
||||
@ -31,7 +31,7 @@ class ShareInteractor : ShareCloseInteractor, ShareToAccountDevicesInteractor, S
|
||||
TODO("not yet!? implemented")
|
||||
}
|
||||
|
||||
override fun onShareToApp(appToShareTo: Application) {
|
||||
override fun onShareToApp(appToShareTo: AppShareOption) {
|
||||
TODO("not yet!? implemented")
|
||||
}
|
||||
}
|
||||
|
@ -7,8 +7,11 @@ package org.mozilla.fenix.share
|
||||
import android.view.LayoutInflater
|
||||
import android.view.ViewGroup
|
||||
import kotlinx.android.extensions.LayoutContainer
|
||||
import kotlinx.android.synthetic.main.share_to_account_devices.*
|
||||
import mozilla.components.concept.sync.Device
|
||||
import org.mozilla.fenix.R
|
||||
import org.mozilla.fenix.share.listadapters.AccountDevicesShareAdapter
|
||||
import org.mozilla.fenix.share.listadapters.SyncShareOption
|
||||
|
||||
/**
|
||||
* Callbacks for possible user interactions on the [ShareToAccountDevicesView]
|
||||
@ -27,5 +30,13 @@ class ShareToAccountDevicesView(
|
||||
init {
|
||||
LayoutInflater.from(containerView.context)
|
||||
.inflate(R.layout.share_to_account_devices, containerView, true)
|
||||
|
||||
devicesList.adapter = AccountDevicesShareAdapter(interactor)
|
||||
}
|
||||
|
||||
fun setSharetargets(targets: List<SyncShareOption>) {
|
||||
with(devicesList.adapter as AccountDevicesShareAdapter) {
|
||||
updateData(targets)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,24 +5,38 @@
|
||||
package org.mozilla.fenix.share
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import kotlinx.android.extensions.LayoutContainer
|
||||
import org.mozilla.fenix.R
|
||||
import org.mozilla.fenix.share.listadapters.Application
|
||||
import org.mozilla.fenix.share.listadapters.AppShareOption
|
||||
import kotlinx.android.synthetic.main.share_to_apps.*
|
||||
import org.mozilla.fenix.share.listadapters.AppShareAdapter
|
||||
|
||||
/**
|
||||
* Callbacks for possible user interactions on the [ShareCloseView]
|
||||
*/
|
||||
interface ShareToAppsInteractor {
|
||||
fun onShareToApp(appToShareTo: Application)
|
||||
fun onShareToApp(appToShareTo: AppShareOption)
|
||||
}
|
||||
|
||||
class ShareToAppsView(
|
||||
override val containerView: ViewGroup,
|
||||
private val interactor: ShareToAppsInteractor
|
||||
interactor: ShareToAppsInteractor
|
||||
) : LayoutContainer {
|
||||
init {
|
||||
LayoutInflater.from(containerView.context)
|
||||
.inflate(R.layout.share_to_apps, containerView, true)
|
||||
|
||||
appsList.adapter = AppShareAdapter(interactor)
|
||||
}
|
||||
|
||||
fun setSharetargets(targets: List<AppShareOption>) {
|
||||
progressBar.visibility = View.GONE
|
||||
appsList.visibility = View.VISIBLE
|
||||
|
||||
with(appsList.adapter as AppShareAdapter) {
|
||||
updateData(targets)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user