parent
f5f0cb8d9c
commit
fe034226a3
|
@ -32,6 +32,7 @@ import kotlinx.coroutines.withContext
|
||||||
import mozilla.appservices.places.BookmarkRoot
|
import mozilla.appservices.places.BookmarkRoot
|
||||||
import mozilla.components.browser.session.Session
|
import mozilla.components.browser.session.Session
|
||||||
import mozilla.components.browser.session.SessionManager
|
import mozilla.components.browser.session.SessionManager
|
||||||
|
import mozilla.components.concept.engine.prompt.ShareData
|
||||||
import mozilla.components.feature.accounts.FxaCapability
|
import mozilla.components.feature.accounts.FxaCapability
|
||||||
import mozilla.components.feature.accounts.FxaWebChannelFeature
|
import mozilla.components.feature.accounts.FxaWebChannelFeature
|
||||||
import mozilla.components.feature.app.links.AppLinksFeature
|
import mozilla.components.feature.app.links.AppLinksFeature
|
||||||
|
@ -42,6 +43,7 @@ import mozilla.components.feature.downloads.DownloadsFeature
|
||||||
import mozilla.components.feature.downloads.manager.FetchDownloadManager
|
import mozilla.components.feature.downloads.manager.FetchDownloadManager
|
||||||
import mozilla.components.feature.intent.ext.EXTRA_SESSION_ID
|
import mozilla.components.feature.intent.ext.EXTRA_SESSION_ID
|
||||||
import mozilla.components.feature.prompts.PromptFeature
|
import mozilla.components.feature.prompts.PromptFeature
|
||||||
|
import mozilla.components.feature.prompts.share.ShareDelegate
|
||||||
import mozilla.components.feature.readerview.ReaderViewFeature
|
import mozilla.components.feature.readerview.ReaderViewFeature
|
||||||
import mozilla.components.feature.session.FullScreenFeature
|
import mozilla.components.feature.session.FullScreenFeature
|
||||||
import mozilla.components.feature.session.SessionFeature
|
import mozilla.components.feature.session.SessionFeature
|
||||||
|
@ -58,6 +60,7 @@ import org.mozilla.fenix.Experiments
|
||||||
import org.mozilla.fenix.FeatureFlags
|
import org.mozilla.fenix.FeatureFlags
|
||||||
import org.mozilla.fenix.HomeActivity
|
import org.mozilla.fenix.HomeActivity
|
||||||
import org.mozilla.fenix.IntentReceiverActivity
|
import org.mozilla.fenix.IntentReceiverActivity
|
||||||
|
import org.mozilla.fenix.NavGraphDirections
|
||||||
import org.mozilla.fenix.R
|
import org.mozilla.fenix.R
|
||||||
import org.mozilla.fenix.browser.readermode.DefaultReaderModeController
|
import org.mozilla.fenix.browser.readermode.DefaultReaderModeController
|
||||||
import org.mozilla.fenix.components.FenixSnackbar
|
import org.mozilla.fenix.components.FenixSnackbar
|
||||||
|
@ -314,6 +317,21 @@ abstract class BaseBrowserFragment : Fragment(), UserInteractionHandler, Session
|
||||||
store = store,
|
store = store,
|
||||||
customTabId = customTabSessionId,
|
customTabId = customTabSessionId,
|
||||||
fragmentManager = parentFragmentManager,
|
fragmentManager = parentFragmentManager,
|
||||||
|
shareDelegate = object : ShareDelegate {
|
||||||
|
override fun showShareSheet(
|
||||||
|
context: Context,
|
||||||
|
shareData: ShareData,
|
||||||
|
onDismiss: () -> Unit,
|
||||||
|
onSuccess: () -> Unit
|
||||||
|
) {
|
||||||
|
val directions = NavGraphDirections.actionGlobalShareFragment(
|
||||||
|
data = arrayOf(shareData),
|
||||||
|
showPage = true,
|
||||||
|
sessionId = getSessionById()?.id
|
||||||
|
)
|
||||||
|
findNavController().navigate(directions)
|
||||||
|
}
|
||||||
|
},
|
||||||
onNeedToRequestPermissions = { permissions ->
|
onNeedToRequestPermissions = { permissions ->
|
||||||
requestPermissions(permissions, REQUEST_CODE_PROMPT_PERMISSIONS)
|
requestPermissions(permissions, REQUEST_CODE_PROMPT_PERMISSIONS)
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -9,6 +9,7 @@ import android.content.Intent
|
||||||
import android.content.Intent.ACTION_SEND
|
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.net.Uri
|
||||||
import androidx.annotation.VisibleForTesting
|
import androidx.annotation.VisibleForTesting
|
||||||
import androidx.navigation.NavController
|
import androidx.navigation.NavController
|
||||||
import com.google.android.material.snackbar.Snackbar
|
import com.google.android.material.snackbar.Snackbar
|
||||||
|
@ -21,10 +22,8 @@ import mozilla.components.concept.sync.Device
|
||||||
import mozilla.components.concept.sync.TabData
|
import mozilla.components.concept.sync.TabData
|
||||||
import mozilla.components.feature.sendtab.SendTabUseCases
|
import mozilla.components.feature.sendtab.SendTabUseCases
|
||||||
import org.mozilla.fenix.R
|
import org.mozilla.fenix.R
|
||||||
import org.mozilla.fenix.components.FenixSnackbar
|
|
||||||
import org.mozilla.fenix.components.FenixSnackbarPresenter
|
import org.mozilla.fenix.components.FenixSnackbarPresenter
|
||||||
import org.mozilla.fenix.components.metrics.Event
|
import org.mozilla.fenix.components.metrics.Event
|
||||||
import org.mozilla.fenix.ext.getRootView
|
|
||||||
import org.mozilla.fenix.ext.metrics
|
import org.mozilla.fenix.ext.metrics
|
||||||
import org.mozilla.fenix.ext.nav
|
import org.mozilla.fenix.ext.nav
|
||||||
import org.mozilla.fenix.share.listadapters.AppShareOption
|
import org.mozilla.fenix.share.listadapters.AppShareOption
|
||||||
|
@ -42,6 +41,10 @@ interface ShareController {
|
||||||
fun handleShareToDevice(device: Device)
|
fun handleShareToDevice(device: Device)
|
||||||
fun handleShareToAllDevices(devices: List<Device>)
|
fun handleShareToAllDevices(devices: List<Device>)
|
||||||
fun handleSignIn()
|
fun handleSignIn()
|
||||||
|
|
||||||
|
enum class Result {
|
||||||
|
DISMISSED, SHARE_ERROR, SUCCESS
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -61,17 +64,17 @@ class DefaultShareController(
|
||||||
private val sendTabUseCases: SendTabUseCases,
|
private val sendTabUseCases: SendTabUseCases,
|
||||||
private val snackbarPresenter: FenixSnackbarPresenter,
|
private val snackbarPresenter: FenixSnackbarPresenter,
|
||||||
private val navController: NavController,
|
private val navController: NavController,
|
||||||
private val dismiss: () -> Unit
|
private val dismiss: (ShareController.Result) -> Unit
|
||||||
) : ShareController {
|
) : ShareController {
|
||||||
|
|
||||||
override fun handleReauth() {
|
override fun handleReauth() {
|
||||||
val directions = ShareFragmentDirections.actionShareFragmentToAccountProblemFragment()
|
val directions = ShareFragmentDirections.actionShareFragmentToAccountProblemFragment()
|
||||||
navController.nav(R.id.shareFragment, directions)
|
navController.nav(R.id.shareFragment, directions)
|
||||||
dismiss()
|
dismiss(ShareController.Result.DISMISSED)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun handleShareClosed() {
|
override fun handleShareClosed() {
|
||||||
dismiss()
|
dismiss(ShareController.Result.DISMISSED)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun handleShareToApp(app: AppShareOption) {
|
override fun handleShareToApp(app: AppShareOption) {
|
||||||
|
@ -82,16 +85,14 @@ class DefaultShareController(
|
||||||
setClassName(app.packageName, app.activityName)
|
setClassName(app.packageName, app.activityName)
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
val result = try {
|
||||||
context.startActivity(intent)
|
context.startActivity(intent)
|
||||||
|
ShareController.Result.SUCCESS
|
||||||
} catch (e: SecurityException) {
|
} catch (e: SecurityException) {
|
||||||
context.getRootView()?.let {
|
snackbarPresenter.present(context.getString(R.string.share_error_snackbar))
|
||||||
FenixSnackbar.make(it, Snackbar.LENGTH_LONG)
|
ShareController.Result.SHARE_ERROR
|
||||||
.setText(context.getString(R.string.share_error_snackbar))
|
|
||||||
.show()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
dismiss()
|
dismiss(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun handleAddNewDevice() {
|
override fun handleAddNewDevice() {
|
||||||
|
@ -112,18 +113,20 @@ class DefaultShareController(
|
||||||
context.metrics.track(Event.SignInToSendTab)
|
context.metrics.track(Event.SignInToSendTab)
|
||||||
val directions = ShareFragmentDirections.actionShareFragmentToTurnOnSyncFragment()
|
val directions = ShareFragmentDirections.actionShareFragmentToTurnOnSyncFragment()
|
||||||
navController.nav(R.id.shareFragment, directions)
|
navController.nav(R.id.shareFragment, directions)
|
||||||
dismiss()
|
dismiss(ShareController.Result.DISMISSED)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun shareToDevicesWithRetry(shareOperation: () -> Deferred<Boolean>) {
|
private fun shareToDevicesWithRetry(shareOperation: () -> Deferred<Boolean>) {
|
||||||
// Use GlobalScope to allow the continuation of this method even if the share fragment is closed.
|
// Use GlobalScope to allow the continuation of this method even if the share fragment is closed.
|
||||||
GlobalScope.launch(Dispatchers.Main) {
|
GlobalScope.launch(Dispatchers.Main) {
|
||||||
if (shareOperation.invoke().await()) {
|
val result = if (shareOperation.invoke().await()) {
|
||||||
showSuccess()
|
showSuccess()
|
||||||
|
ShareController.Result.SUCCESS
|
||||||
} else {
|
} else {
|
||||||
showFailureWithRetryOption { shareToDevicesWithRetry(shareOperation) }
|
showFailureWithRetryOption { shareToDevicesWithRetry(shareOperation) }
|
||||||
|
ShareController.Result.DISMISSED
|
||||||
}
|
}
|
||||||
dismiss()
|
dismiss(result)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -161,7 +164,11 @@ class DefaultShareController(
|
||||||
|
|
||||||
// Navigation between app fragments uses ShareTab as arguments. SendTabUseCases uses TabData.
|
// Navigation between app fragments uses ShareTab as arguments. SendTabUseCases uses TabData.
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
fun List<ShareData>.toTabData() = map { data ->
|
internal fun List<ShareData>.toTabData() = map { data ->
|
||||||
TabData(data.title.orEmpty(), data.url.orEmpty())
|
TabData(title = data.title.orEmpty(), url = data.url ?: data.text?.toDataUri().orEmpty())
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun String.toDataUri(): String {
|
||||||
|
return "data:,${Uri.encode(this)}"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,9 @@ import androidx.lifecycle.observe
|
||||||
import androidx.navigation.fragment.findNavController
|
import androidx.navigation.fragment.findNavController
|
||||||
import androidx.navigation.fragment.navArgs
|
import androidx.navigation.fragment.navArgs
|
||||||
import kotlinx.android.synthetic.main.fragment_share.view.*
|
import kotlinx.android.synthetic.main.fragment_share.view.*
|
||||||
|
import mozilla.components.browser.state.action.ContentAction
|
||||||
|
import mozilla.components.browser.state.selector.findTabOrCustomTab
|
||||||
|
import mozilla.components.concept.engine.prompt.PromptRequest
|
||||||
import mozilla.components.feature.sendtab.SendTabUseCases
|
import mozilla.components.feature.sendtab.SendTabUseCases
|
||||||
import org.mozilla.fenix.R
|
import org.mozilla.fenix.R
|
||||||
import org.mozilla.fenix.components.FenixSnackbarPresenter
|
import org.mozilla.fenix.components.FenixSnackbarPresenter
|
||||||
|
@ -24,6 +27,7 @@ import org.mozilla.fenix.ext.requireComponents
|
||||||
|
|
||||||
class ShareFragment : AppCompatDialogFragment() {
|
class ShareFragment : AppCompatDialogFragment() {
|
||||||
|
|
||||||
|
private val args by navArgs<ShareFragmentArgs>()
|
||||||
private val viewModel: ShareViewModel by viewModels {
|
private val viewModel: ShareViewModel by viewModels {
|
||||||
AndroidViewModelFactory(requireActivity().application)
|
AndroidViewModelFactory(requireActivity().application)
|
||||||
}
|
}
|
||||||
|
@ -37,6 +41,11 @@ class ShareFragment : AppCompatDialogFragment() {
|
||||||
viewModel.loadDevicesAndApps()
|
viewModel.loadDevicesAndApps()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun dismiss() {
|
||||||
|
consumePrompt { onDismiss() }
|
||||||
|
super.dismiss()
|
||||||
|
}
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
setStyle(STYLE_NO_TITLE, R.style.ShareDialogStyle)
|
setStyle(STYLE_NO_TITLE, R.style.ShareDialogStyle)
|
||||||
|
@ -48,7 +57,6 @@ class ShareFragment : AppCompatDialogFragment() {
|
||||||
savedInstanceState: Bundle?
|
savedInstanceState: Bundle?
|
||||||
): View? {
|
): View? {
|
||||||
val view = inflater.inflate(R.layout.fragment_share, container, false)
|
val view = inflater.inflate(R.layout.fragment_share, container, false)
|
||||||
val args by navArgs<ShareFragmentArgs>()
|
|
||||||
val shareData = args.data.toList()
|
val shareData = args.data.toList()
|
||||||
|
|
||||||
val accountManager = requireComponents.backgroundServices.accountManager
|
val accountManager = requireComponents.backgroundServices.accountManager
|
||||||
|
@ -59,9 +67,17 @@ class ShareFragment : AppCompatDialogFragment() {
|
||||||
shareData = shareData,
|
shareData = shareData,
|
||||||
snackbarPresenter = FenixSnackbarPresenter(activity!!.getRootView()!!),
|
snackbarPresenter = FenixSnackbarPresenter(activity!!.getRootView()!!),
|
||||||
navController = findNavController(),
|
navController = findNavController(),
|
||||||
sendTabUseCases = SendTabUseCases(accountManager),
|
sendTabUseCases = SendTabUseCases(accountManager)
|
||||||
dismiss = ::dismiss
|
) { result ->
|
||||||
)
|
consumePrompt {
|
||||||
|
when (result) {
|
||||||
|
ShareController.Result.DISMISSED -> onDismiss()
|
||||||
|
ShareController.Result.SHARE_ERROR -> onFailure()
|
||||||
|
ShareController.Result.SUCCESS -> onSuccess()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
super.dismiss()
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
view.shareWrapper.setOnClickListener { shareInteractor.onShareClosed() }
|
view.shareWrapper.setOnClickListener { shareInteractor.onShareClosed() }
|
||||||
|
@ -94,6 +110,25 @@ class ShareFragment : AppCompatDialogFragment() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If [ShareFragmentArgs.sessionId] is set and the session has a pending Web Share
|
||||||
|
* prompt request, call [consume] then clean up the prompt.
|
||||||
|
*/
|
||||||
|
private fun consumePrompt(
|
||||||
|
consume: PromptRequest.Share.() -> Unit
|
||||||
|
) {
|
||||||
|
val browserStore = requireComponents.core.store
|
||||||
|
args.sessionId
|
||||||
|
?.let { sessionId -> browserStore.state.findTabOrCustomTab(sessionId) }
|
||||||
|
?.let { tab ->
|
||||||
|
val promptRequest = tab.content.promptRequest
|
||||||
|
if (promptRequest is PromptRequest.Share) {
|
||||||
|
consume(promptRequest)
|
||||||
|
browserStore.dispatch(ContentAction.ConsumePromptRequestAction(tab.id))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val SHOW_PAGE_ALPHA = 0.6f
|
const val SHOW_PAGE_ALPHA = 0.6f
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,7 +63,7 @@ class ShareViewModel(application: Application) : AndroidViewModel(application) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load a list of devices and apps into [devicesList] and [appsList].
|
* Load a list of devices and apps into [devicesList] and [appsList].
|
||||||
* Should be called when a fragment is attached so the data can be fetched early.
|
* Should be called when the fragment is attached so the data can be fetched early.
|
||||||
*/
|
*/
|
||||||
fun loadDevicesAndApps() {
|
fun loadDevicesAndApps() {
|
||||||
val networkRequest = NetworkRequest.Builder().build()
|
val networkRequest = NetworkRequest.Builder().build()
|
||||||
|
@ -86,6 +86,9 @@ class ShareViewModel(application: Application) : AndroidViewModel(application) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unregisters the network callback and cleans up.
|
||||||
|
*/
|
||||||
override fun onCleared() {
|
override fun onCleared() {
|
||||||
connectivityManager?.unregisterNetworkCallback(networkCallback)
|
connectivityManager?.unregisterNetworkCallback(networkCallback)
|
||||||
}
|
}
|
||||||
|
|
|
@ -562,6 +562,11 @@
|
||||||
<action
|
<action
|
||||||
android:id="@+id/action_shareFragment_to_addNewDeviceFragment"
|
android:id="@+id/action_shareFragment_to_addNewDeviceFragment"
|
||||||
app:destination="@id/addNewDeviceFragment" />
|
app:destination="@id/addNewDeviceFragment" />
|
||||||
|
<argument
|
||||||
|
android:name="sessionId"
|
||||||
|
app:argType="string"
|
||||||
|
app:nullable="true"
|
||||||
|
android:defaultValue="null" />
|
||||||
</dialog>
|
</dialog>
|
||||||
<dialog
|
<dialog
|
||||||
android:id="@+id/quickSettingsSheetDialogFragment"
|
android:id="@+id/quickSettingsSheetDialogFragment"
|
||||||
|
|
|
@ -63,7 +63,7 @@ class ShareControllerTest {
|
||||||
private val sendTabUseCases = mockk<SendTabUseCases>(relaxed = true)
|
private val sendTabUseCases = mockk<SendTabUseCases>(relaxed = true)
|
||||||
private val snackbarPresenter = mockk<FenixSnackbarPresenter>(relaxed = true)
|
private val snackbarPresenter = mockk<FenixSnackbarPresenter>(relaxed = true)
|
||||||
private val navController = mockk<NavController>(relaxed = true)
|
private val navController = mockk<NavController>(relaxed = true)
|
||||||
private val dismiss = mockk<() -> Unit>(relaxed = true)
|
private val dismiss = mockk<(ShareController.Result) -> Unit>(relaxed = true)
|
||||||
private val controller = DefaultShareController(
|
private val controller = DefaultShareController(
|
||||||
context, shareData, sendTabUseCases, snackbarPresenter, navController, dismiss
|
context, shareData, sendTabUseCases, snackbarPresenter, navController, dismiss
|
||||||
)
|
)
|
||||||
|
@ -77,7 +77,7 @@ class ShareControllerTest {
|
||||||
fun `handleShareClosed should call a passed in delegate to close this`() {
|
fun `handleShareClosed should call a passed in delegate to close this`() {
|
||||||
controller.handleShareClosed()
|
controller.handleShareClosed()
|
||||||
|
|
||||||
verify { dismiss() }
|
verify { dismiss(ShareController.Result.DISMISSED) }
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -95,7 +95,7 @@ class ShareControllerTest {
|
||||||
|
|
||||||
testController.handleShareToApp(appShareOption)
|
testController.handleShareToApp(appShareOption)
|
||||||
|
|
||||||
// Check that the Intent used for querying apps has the expected structre
|
// Check that the Intent used for querying apps has the expected structure
|
||||||
assertAll {
|
assertAll {
|
||||||
assertThat(shareIntent.isCaptured).isTrue()
|
assertThat(shareIntent.isCaptured).isTrue()
|
||||||
assertThat(shareIntent.captured.action).isEqualTo(Intent.ACTION_SEND)
|
assertThat(shareIntent.captured.action).isEqualTo(Intent.ACTION_SEND)
|
||||||
|
@ -107,7 +107,30 @@ class ShareControllerTest {
|
||||||
}
|
}
|
||||||
verifyOrder {
|
verifyOrder {
|
||||||
activityContext.startActivity(shareIntent.captured)
|
activityContext.startActivity(shareIntent.captured)
|
||||||
dismiss()
|
dismiss(ShareController.Result.SUCCESS)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `handleShareToApp should dismiss with an error start when a security exception occurs`() {
|
||||||
|
val appPackageName = "package"
|
||||||
|
val appClassName = "activity"
|
||||||
|
val appShareOption = AppShareOption("app", mockk(), appPackageName, appClassName)
|
||||||
|
val shareIntent = slot<Intent>()
|
||||||
|
// Our share Intent uses `FLAG_ACTIVITY_NEW_TASK` but when resolving the startActivity call
|
||||||
|
// needed for capturing the actual Intent used the `slot` one doesn't have this flag so we
|
||||||
|
// need to use an Activity Context.
|
||||||
|
val activityContext: Context = mockk<Activity>()
|
||||||
|
val testController = DefaultShareController(activityContext, shareData, mockk(), snackbarPresenter, mockk(), dismiss)
|
||||||
|
every { activityContext.startActivity(capture(shareIntent)) } throws SecurityException()
|
||||||
|
every { activityContext.getString(R.string.share_error_snackbar) } returns "Cannot share to this app"
|
||||||
|
|
||||||
|
testController.handleShareToApp(appShareOption)
|
||||||
|
|
||||||
|
verifyOrder {
|
||||||
|
activityContext.startActivity(shareIntent.captured)
|
||||||
|
snackbarPresenter.present("Cannot share to this app")
|
||||||
|
dismiss(ShareController.Result.SHARE_ERROR)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,7 +190,7 @@ class ShareControllerTest {
|
||||||
R.id.shareFragment,
|
R.id.shareFragment,
|
||||||
ShareFragmentDirections.actionShareFragmentToTurnOnSyncFragment()
|
ShareFragmentDirections.actionShareFragmentToTurnOnSyncFragment()
|
||||||
)
|
)
|
||||||
dismiss()
|
dismiss(ShareController.Result.DISMISSED)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -180,7 +203,7 @@ class ShareControllerTest {
|
||||||
R.id.shareFragment,
|
R.id.shareFragment,
|
||||||
ShareFragmentDirections.actionShareFragmentToAccountProblemFragment()
|
ShareFragmentDirections.actionShareFragmentToAccountProblemFragment()
|
||||||
)
|
)
|
||||||
dismiss()
|
dismiss(ShareController.Result.DISMISSED)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -276,4 +299,22 @@ class ShareControllerTest {
|
||||||
|
|
||||||
assertThat(tabData).isEqualTo(tabsData)
|
assertThat(tabData).isEqualTo(tabsData)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `ShareTab#toTabData creates a data url from text if no url is specified`() {
|
||||||
|
var tabData: List<TabData>
|
||||||
|
val expected = listOf(
|
||||||
|
TabData(title = "title0", url = ""),
|
||||||
|
TabData(title = "title1", url = "data:,Hello%2C%20World!")
|
||||||
|
)
|
||||||
|
|
||||||
|
with(controller) {
|
||||||
|
tabData = listOf(
|
||||||
|
ShareData(title = "title0"),
|
||||||
|
ShareData(title = "title1", text = "Hello, World!")
|
||||||
|
).toTabData()
|
||||||
|
}
|
||||||
|
|
||||||
|
assertThat(tabData).isEqualTo(expected)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue