* For #2754 Add tab cards to share sheet * For #2754: Fix background near rounded corners and ShareButtonAppearanceTest * Add license to share_tab_itemmaster
parent
ac2611d744
commit
de93b05cac
|
@ -58,7 +58,7 @@ class ShareButtonTest {
|
||||||
}.openThreeDotMenu {
|
}.openThreeDotMenu {
|
||||||
verifyShareButton()
|
verifyShareButton()
|
||||||
clickShareButton()
|
clickShareButton()
|
||||||
verifyShareDialogTitle()
|
verifyShareScrim()
|
||||||
verifySendToDeviceTitle()
|
verifySendToDeviceTitle()
|
||||||
verifyShareALinkTitle()
|
verifyShareALinkTitle()
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ import org.hamcrest.Matchers.allOf
|
||||||
import org.mozilla.fenix.R
|
import org.mozilla.fenix.R
|
||||||
import org.mozilla.fenix.helpers.TestAssetHelper.waitingTime
|
import org.mozilla.fenix.helpers.TestAssetHelper.waitingTime
|
||||||
import org.mozilla.fenix.helpers.click
|
import org.mozilla.fenix.helpers.click
|
||||||
|
import org.mozilla.fenix.share.ShareFragment
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implementation of Robot Pattern for the three dot (main) menu.
|
* Implementation of Robot Pattern for the three dot (main) menu.
|
||||||
|
@ -39,10 +40,11 @@ class ThreeDotMenuRobot {
|
||||||
shareButton().click()
|
shareButton().click()
|
||||||
mDevice.wait(Until.findObject(By.text("SHARE A LINK")), waitingTime)
|
mDevice.wait(Until.findObject(By.text("SHARE A LINK")), waitingTime)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun verifyShareTabButton() = assertShareTabButton()
|
fun verifyShareTabButton() = assertShareTabButton()
|
||||||
fun verifySaveCollection() = assertSaveCollectionButton()
|
fun verifySaveCollection() = assertSaveCollectionButton()
|
||||||
fun verifyFindInPageButton() = assertFindInPageButton()
|
fun verifyFindInPageButton() = assertFindInPageButton()
|
||||||
fun verifyShareDialogTitle() = assertShareDialogTitle()
|
fun verifyShareScrim() = assertShareScrim()
|
||||||
fun verifySendToDeviceTitle() = assertSendToDeviceTitle()
|
fun verifySendToDeviceTitle() = assertSendToDeviceTitle()
|
||||||
fun verifyShareALinkTitle() = assertShareALinkTitle()
|
fun verifyShareALinkTitle() = assertShareALinkTitle()
|
||||||
fun verifyWhatsNewButton() = assertWhatsNewButton()
|
fun verifyWhatsNewButton() = assertWhatsNewButton()
|
||||||
|
@ -128,6 +130,7 @@ class ThreeDotMenuRobot {
|
||||||
private fun threeDotMenuRecyclerViewExists() {
|
private fun threeDotMenuRecyclerViewExists() {
|
||||||
onView(withId(R.id.mozac_browser_menu_recyclerView)).check(matches(isDisplayed()))
|
onView(withId(R.id.mozac_browser_menu_recyclerView)).check(matches(isDisplayed()))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun settingsButton() = onView(allOf(withText(R.string.settings)))
|
private fun settingsButton() = onView(allOf(withText(R.string.settings)))
|
||||||
private fun assertSettingsButton() = settingsButton()
|
private fun assertSettingsButton() = settingsButton()
|
||||||
.check(matches(ViewMatchers.withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))
|
.check(matches(ViewMatchers.withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))
|
||||||
|
@ -159,6 +162,7 @@ private fun assertCloseAllTabsButton() = closeAllTabsButton()
|
||||||
private fun shareTabButton() = onView(allOf(withText("Share tabs")))
|
private fun shareTabButton() = onView(allOf(withText("Share tabs")))
|
||||||
private fun assertShareTabButton() = shareTabButton()
|
private fun assertShareTabButton() = shareTabButton()
|
||||||
.check(matches(ViewMatchers.withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))
|
.check(matches(ViewMatchers.withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))
|
||||||
|
|
||||||
private fun shareButton() = onView(allOf(withText("Share")))
|
private fun shareButton() = onView(allOf(withText("Share")))
|
||||||
private fun assertShareButton() = shareButton()
|
private fun assertShareButton() = shareButton()
|
||||||
.check(matches(ViewMatchers.withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))
|
.check(matches(ViewMatchers.withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))
|
||||||
|
@ -169,15 +173,20 @@ private fun assertSaveCollectionButton() = saveCollectionButton()
|
||||||
|
|
||||||
private fun findInPageButton() = onView(allOf(withText("Find in page")))
|
private fun findInPageButton() = onView(allOf(withText("Find in page")))
|
||||||
private fun assertFindInPageButton() = findInPageButton()
|
private fun assertFindInPageButton() = findInPageButton()
|
||||||
private fun ShareDialogTitle() = onView(allOf(withText("Send and Share"), withResourceName("closeButton")))
|
|
||||||
private fun assertShareDialogTitle() = ShareDialogTitle()
|
|
||||||
.check(matches(ViewMatchers.withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))
|
|
||||||
|
|
||||||
private fun SendToDeviceTitle() = onView(allOf(withText("SEND TO DEVICE"), withResourceName("accountHeaderText")))
|
private fun shareScrim() = onView(withResourceName("closeSharingScrim"))
|
||||||
|
private fun assertShareScrim() =
|
||||||
|
shareScrim().check(matches(ViewMatchers.withAlpha(ShareFragment.SHOW_PAGE_ALPHA)))
|
||||||
|
|
||||||
|
private fun SendToDeviceTitle() =
|
||||||
|
onView(allOf(withText("SEND TO DEVICE"), withResourceName("accountHeaderText")))
|
||||||
|
|
||||||
private fun assertSendToDeviceTitle() = SendToDeviceTitle()
|
private fun assertSendToDeviceTitle() = SendToDeviceTitle()
|
||||||
.check(matches(ViewMatchers.withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))
|
.check(matches(ViewMatchers.withEffectiveVisibility(ViewMatchers.Visibility.VISIBLE)))
|
||||||
|
|
||||||
private fun ShareALinkTitle() = onView(allOf(withText("SHARE A LINK"), withResourceName("link_header")))
|
private fun ShareALinkTitle() =
|
||||||
|
onView(allOf(withText("SHARE A LINK"), withResourceName("link_header")))
|
||||||
|
|
||||||
private fun assertShareALinkTitle() = ShareALinkTitle()
|
private fun assertShareALinkTitle() = ShareALinkTitle()
|
||||||
|
|
||||||
private fun whatsNewButton() = onView(allOf(withText("What's New")))
|
private fun whatsNewButton() = onView(allOf(withText("What's New")))
|
||||||
|
|
|
@ -21,6 +21,7 @@ import org.mozilla.fenix.components.Services
|
||||||
import org.mozilla.fenix.components.metrics.Event
|
import org.mozilla.fenix.components.metrics.Event
|
||||||
import org.mozilla.fenix.ext.components
|
import org.mozilla.fenix.ext.components
|
||||||
import org.mozilla.fenix.ext.nav
|
import org.mozilla.fenix.ext.nav
|
||||||
|
import org.mozilla.fenix.share.ShareTab
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* [BookmarkFragment] controller.
|
* [BookmarkFragment] controller.
|
||||||
|
@ -84,7 +85,8 @@ class DefaultBookmarkController(
|
||||||
navigate(
|
navigate(
|
||||||
BookmarkFragmentDirections.actionBookmarkFragmentToShareFragment(
|
BookmarkFragmentDirections.actionBookmarkFragmentToShareFragment(
|
||||||
url = item.url!!,
|
url = item.url!!,
|
||||||
title = item.title
|
title = item.title,
|
||||||
|
tabs = arrayOf(ShareTab(item.url!!, item.title!!))
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -154,11 +154,15 @@ class HistoryFragment : LibraryPageFragment<HistoryItem>(), BackHandler {
|
||||||
override fun onOptionsItemSelected(item: MenuItem): Boolean = when (item.itemId) {
|
override fun onOptionsItemSelected(item: MenuItem): Boolean = when (item.itemId) {
|
||||||
R.id.share_history_multi_select -> {
|
R.id.share_history_multi_select -> {
|
||||||
val selectedHistory = historyStore.state.mode.selectedItems
|
val selectedHistory = historyStore.state.mode.selectedItems
|
||||||
|
val shareTabs = selectedHistory.map { ShareTab(it.url, it.title) }
|
||||||
when {
|
when {
|
||||||
selectedHistory.size == 1 ->
|
selectedHistory.size == 1 ->
|
||||||
share(url = selectedHistory.first().url)
|
share(
|
||||||
|
url = selectedHistory.first().url,
|
||||||
|
title = selectedHistory.first().title,
|
||||||
|
tabs = shareTabs
|
||||||
|
)
|
||||||
selectedHistory.size > 1 -> {
|
selectedHistory.size > 1 -> {
|
||||||
val shareTabs = selectedHistory.map { ShareTab(it.url, it.title) }
|
|
||||||
share(tabs = shareTabs)
|
share(tabs = shareTabs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -256,11 +260,12 @@ class HistoryFragment : LibraryPageFragment<HistoryItem>(), BackHandler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun share(url: String? = null, tabs: List<ShareTab>? = null) {
|
private fun share(url: String? = null, title: String? = null, tabs: List<ShareTab>? = null) {
|
||||||
requireComponents.analytics.metrics.track(Event.HistoryItemShared)
|
requireComponents.analytics.metrics.track(Event.HistoryItemShared)
|
||||||
val directions =
|
val directions =
|
||||||
HistoryFragmentDirections.actionHistoryFragmentToShareFragment(
|
HistoryFragmentDirections.actionHistoryFragmentToShareFragment(
|
||||||
url = url,
|
url = url,
|
||||||
|
title = title,
|
||||||
tabs = tabs?.toTypedArray()
|
tabs = tabs?.toTypedArray()
|
||||||
)
|
)
|
||||||
nav(R.id.historyFragment, directions)
|
nav(R.id.historyFragment, directions)
|
||||||
|
|
|
@ -6,9 +6,11 @@ package org.mozilla.fenix.share
|
||||||
|
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import kotlinx.android.extensions.LayoutContainer
|
import kotlinx.android.extensions.LayoutContainer
|
||||||
import kotlinx.android.synthetic.main.share_close.*
|
import kotlinx.android.synthetic.main.share_close.*
|
||||||
import org.mozilla.fenix.R
|
import org.mozilla.fenix.R
|
||||||
|
import org.mozilla.fenix.share.listadapters.ShareTabsAdapter
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callbacks for possible user interactions on the [ShareCloseView]
|
* Callbacks for possible user interactions on the [ShareCloseView]
|
||||||
|
@ -21,10 +23,19 @@ class ShareCloseView(
|
||||||
override val containerView: ViewGroup,
|
override val containerView: ViewGroup,
|
||||||
private val interactor: ShareCloseInteractor
|
private val interactor: ShareCloseInteractor
|
||||||
) : LayoutContainer {
|
) : LayoutContainer {
|
||||||
|
val adapter = ShareTabsAdapter()
|
||||||
|
|
||||||
init {
|
init {
|
||||||
LayoutInflater.from(containerView.context)
|
LayoutInflater.from(containerView.context)
|
||||||
.inflate(R.layout.share_close, containerView, true)
|
.inflate(R.layout.share_close, containerView, true)
|
||||||
|
|
||||||
closeButton.setOnClickListener { interactor.onShareClosed() }
|
closeButton.setOnClickListener { interactor.onShareClosed() }
|
||||||
|
|
||||||
|
shared_site_list.layoutManager = LinearLayoutManager(containerView.context)
|
||||||
|
shared_site_list.adapter = adapter
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setTabs(tabs: List<ShareTab>) {
|
||||||
|
adapter.setTabs(tabs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -113,9 +113,7 @@ class ShareFragment : AppCompatDialogFragment() {
|
||||||
): View? {
|
): View? {
|
||||||
val view = inflater.inflate(R.layout.fragment_share, container, false)
|
val view = inflater.inflate(R.layout.fragment_share, container, false)
|
||||||
val args = ShareFragmentArgs.fromBundle(arguments!!)
|
val args = ShareFragmentArgs.fromBundle(arguments!!)
|
||||||
if (args.url == null && args.tabs.isNullOrEmpty()) {
|
check(!(args.url == null && args.tabs.isNullOrEmpty())) { "URL and tabs cannot both be null." }
|
||||||
throw IllegalStateException("URL and tabs cannot both be null.")
|
|
||||||
}
|
|
||||||
|
|
||||||
val tabs = args.tabs?.toList() ?: listOf(ShareTab(args.url!!, args.title.orEmpty()))
|
val tabs = args.tabs?.toList() ?: listOf(ShareTab(args.url!!, args.title.orEmpty()))
|
||||||
val accountManager = requireComponents.backgroundServices.accountManager
|
val accountManager = requireComponents.backgroundServices.accountManager
|
||||||
|
@ -134,7 +132,19 @@ class ShareFragment : AppCompatDialogFragment() {
|
||||||
view.shareWrapper.setOnClickListener { shareInteractor.onShareClosed() }
|
view.shareWrapper.setOnClickListener { shareInteractor.onShareClosed() }
|
||||||
shareToAccountDevicesView =
|
shareToAccountDevicesView =
|
||||||
ShareToAccountDevicesView(view.devicesShareLayout, shareInteractor)
|
ShareToAccountDevicesView(view.devicesShareLayout, shareInteractor)
|
||||||
shareCloseView = ShareCloseView(view.closeSharingLayout, shareInteractor)
|
|
||||||
|
if (args.url != null && args.tabs == null) {
|
||||||
|
// If sharing one tab from the browser fragment, show it.
|
||||||
|
// If URL is set and tabs is null, we assume the browser is visible, since navigation
|
||||||
|
// does not tell us the back stack state.
|
||||||
|
view.closeSharingScrim.alpha = SHOW_PAGE_ALPHA
|
||||||
|
view.shareWrapper.setOnClickListener { shareInteractor.onShareClosed() }
|
||||||
|
} else {
|
||||||
|
// Otherwise, show a list of tabs to share.
|
||||||
|
view.closeSharingScrim.alpha = 1.0f
|
||||||
|
shareCloseView = ShareCloseView(view.closeSharingContent, shareInteractor)
|
||||||
|
shareCloseView.setTabs(tabs)
|
||||||
|
}
|
||||||
shareToAppsView = ShareToAppsView(view.appsShareLayout, shareInteractor)
|
shareToAppsView = ShareToAppsView(view.appsShareLayout, shareInteractor)
|
||||||
|
|
||||||
return view
|
return view
|
||||||
|
@ -212,6 +222,10 @@ class ShareFragment : AppCompatDialogFragment() {
|
||||||
}
|
}
|
||||||
return list
|
return list
|
||||||
}
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val SHOW_PAGE_ALPHA = 0.6f
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Parcelize
|
@Parcelize
|
||||||
|
|
|
@ -0,0 +1,60 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
package org.mozilla.fenix.share.listadapters
|
||||||
|
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.recyclerview.widget.DiffUtil
|
||||||
|
import androidx.recyclerview.widget.ListAdapter
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import kotlinx.android.synthetic.main.share_tab_item.view.*
|
||||||
|
import org.mozilla.fenix.R
|
||||||
|
import org.mozilla.fenix.ext.components
|
||||||
|
import org.mozilla.fenix.ext.loadIntoView
|
||||||
|
import org.mozilla.fenix.share.ShareTab
|
||||||
|
|
||||||
|
class ShareTabsAdapter :
|
||||||
|
ListAdapter<ShareTab, ShareTabsAdapter.ShareTabViewHolder>(ShareTabDiffCallback()) {
|
||||||
|
|
||||||
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ShareTabViewHolder(
|
||||||
|
LayoutInflater.from(parent.context)
|
||||||
|
.inflate(R.layout.share_tab_item, parent, false)
|
||||||
|
)
|
||||||
|
|
||||||
|
override fun onBindViewHolder(holder: ShareTabViewHolder, position: Int) =
|
||||||
|
holder.bind(getItem(position))
|
||||||
|
|
||||||
|
fun setTabs(tabs: List<ShareTab>) {
|
||||||
|
submitList(tabs.toMutableList())
|
||||||
|
}
|
||||||
|
|
||||||
|
inner class ShareTabViewHolder(
|
||||||
|
itemView: View
|
||||||
|
) : RecyclerView.ViewHolder(itemView) {
|
||||||
|
|
||||||
|
fun bind(item: ShareTab) = with(itemView) {
|
||||||
|
context.components.core.icons.loadIntoView(itemView.share_tab_favicon, item.url)
|
||||||
|
itemView.share_tab_title.text = item.title
|
||||||
|
itemView.share_tab_url.text = item.url
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ShareTabDiffCallback : DiffUtil.ItemCallback<ShareTab>() {
|
||||||
|
override fun areItemsTheSame(
|
||||||
|
oldItem: ShareTab,
|
||||||
|
newItem: ShareTab
|
||||||
|
): Boolean {
|
||||||
|
return oldItem.url == newItem.url
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun areContentsTheSame(
|
||||||
|
oldItem: ShareTab,
|
||||||
|
newItem: ShareTab
|
||||||
|
): Boolean {
|
||||||
|
return oldItem.url == newItem.url && oldItem.title == newItem.title
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,6 +4,5 @@
|
||||||
<corners
|
<corners
|
||||||
android:topLeftRadius="@dimen/bottom_sheet_corner_radius"
|
android:topLeftRadius="@dimen/bottom_sheet_corner_radius"
|
||||||
android:topRightRadius="@dimen/bottom_sheet_corner_radius" />
|
android:topRightRadius="@dimen/bottom_sheet_corner_radius" />
|
||||||
<padding android:top="@dimen/bottom_sheet_top_padding" />
|
<solid android:color="?above" />
|
||||||
<solid android:color="?colorPrimary" />
|
|
||||||
</shape>
|
</shape>
|
|
@ -10,22 +10,28 @@
|
||||||
android:id="@+id/shareWrapper"
|
android:id="@+id/shareWrapper"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:background="@drawable/scrim_background"
|
|
||||||
android:clipToPadding="false"
|
android:clipToPadding="false"
|
||||||
android:fitsSystemWindows="true"
|
android:fitsSystemWindows="true"
|
||||||
tools:context="org.mozilla.fenix.share.ShareFragment">
|
tools:context="org.mozilla.fenix.share.ShareFragment">
|
||||||
|
|
||||||
<FrameLayout
|
<FrameLayout
|
||||||
android:id="@+id/closeSharingLayout"
|
android:id="@+id/closeSharingScrim"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="match_parent"
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
android:background="@drawable/scrim_background"/>
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/closeSharingContent"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintBottom_toTopOf="@id/sharingLayout"/>
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:id="@+id/sharingLayout"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:background="@drawable/bottom_sheet_dialog_fragment_background"
|
android:background="@drawable/bottom_sheet_dialog_fragment_background"
|
||||||
android:backgroundTint="?above"
|
|
||||||
app:layout_constraintBottom_toBottomOf="parent">
|
app:layout_constraintBottom_toBottomOf="parent">
|
||||||
|
|
||||||
<FrameLayout
|
<FrameLayout
|
||||||
|
|
|
@ -3,22 +3,33 @@
|
||||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<LinearLayout
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:id="@+id/closeButton"
|
android:layout_width="match_parent"
|
||||||
style="@style/Widget.MaterialComponents.Button.TextButton"
|
android:layout_height="match_parent"
|
||||||
android:layout_width="wrap_content"
|
android:orientation="vertical">
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_margin="16dp"
|
<com.google.android.material.button.MaterialButton
|
||||||
android:text="@string/share_header"
|
android:id="@+id/closeButton"
|
||||||
android:textAppearance="@style/HeaderTextStyle"
|
style="@style/Widget.MaterialComponents.Button.TextButton"
|
||||||
android:textColor="@color/neutral_text"
|
android:layout_width="wrap_content"
|
||||||
android:textSize="20sp"
|
android:layout_height="wrap_content"
|
||||||
app:icon="@drawable/mozac_ic_close"
|
android:layout_margin="16dp"
|
||||||
app:iconPadding="8dp"
|
android:text="@string/share_header_2"
|
||||||
app:iconTint="@color/neutral_text"
|
android:textAppearance="@style/HeaderTextStyle"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
android:textColor="@color/neutral_text"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
android:textSize="20sp"
|
||||||
tools:backgroundTint="#000" />
|
app:icon="@drawable/mozac_ic_close"
|
||||||
|
app:iconPadding="8dp"
|
||||||
|
app:iconTint="@color/neutral_text"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
tools:backgroundTint="#000" />
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/shared_site_list"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content" />
|
||||||
|
</LinearLayout>
|
|
@ -0,0 +1,51 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_margin="8dp">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/share_tab_favicon"
|
||||||
|
android:layout_width="40dp"
|
||||||
|
android:layout_height="40dp"
|
||||||
|
android:padding="8dp"
|
||||||
|
android:background="@drawable/favicon_background"
|
||||||
|
android:backgroundTint="?above"
|
||||||
|
android:importantForAccessibility="no"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/share_tab_title"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:textSize="20sp"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:textColor="?contrastText"
|
||||||
|
tools:text="Download Firefox - Free Web Browser"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/share_tab_favicon"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/share_tab_url"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textSize="12sp"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:textColor="?secondaryText"
|
||||||
|
tools:text="https://www.mozilla.org/en-US/firefox/new/"
|
||||||
|
app:layout_constraintStart_toStartOf="@id/share_tab_title"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/share_tab_title"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"/>
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -586,6 +586,8 @@
|
||||||
<!-- Share -->
|
<!-- Share -->
|
||||||
<!-- Share screen header -->
|
<!-- Share screen header -->
|
||||||
<string name="share_header">Send and Share</string>
|
<string name="share_header">Send and Share</string>
|
||||||
|
<!-- Share screen header -->
|
||||||
|
<string name="share_header_2">Share</string>
|
||||||
<!-- Content description (not visible, for screen readers etc.):
|
<!-- Content description (not visible, for screen readers etc.):
|
||||||
"Share" button. Opens the share menu when pressed. -->
|
"Share" button. Opens the share menu when pressed. -->
|
||||||
<string name="share_button_content_description">Share</string>
|
<string name="share_button_content_description">Share</string>
|
||||||
|
|
|
@ -10,9 +10,13 @@ import android.content.Context
|
||||||
import androidx.core.content.getSystemService
|
import androidx.core.content.getSystemService
|
||||||
import androidx.navigation.NavController
|
import androidx.navigation.NavController
|
||||||
import androidx.navigation.NavDestination
|
import androidx.navigation.NavDestination
|
||||||
|
import androidx.navigation.NavDirections
|
||||||
|
import io.mockk.Runs
|
||||||
import io.mockk.every
|
import io.mockk.every
|
||||||
|
import io.mockk.just
|
||||||
import io.mockk.mockk
|
import io.mockk.mockk
|
||||||
import io.mockk.mockkStatic
|
import io.mockk.mockkStatic
|
||||||
|
import io.mockk.slot
|
||||||
import io.mockk.verify
|
import io.mockk.verify
|
||||||
import io.mockk.verifyOrder
|
import io.mockk.verifyOrder
|
||||||
import mozilla.appservices.places.BookmarkRoot
|
import mozilla.appservices.places.BookmarkRoot
|
||||||
|
@ -21,9 +25,9 @@ import mozilla.components.concept.storage.BookmarkNodeType
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.mozilla.fenix.BrowserDirection
|
import org.mozilla.fenix.BrowserDirection
|
||||||
import org.mozilla.fenix.browser.browsingmode.BrowsingMode
|
|
||||||
import org.mozilla.fenix.HomeActivity
|
import org.mozilla.fenix.HomeActivity
|
||||||
import org.mozilla.fenix.R
|
import org.mozilla.fenix.R
|
||||||
|
import org.mozilla.fenix.browser.browsingmode.BrowsingMode
|
||||||
import org.mozilla.fenix.components.FenixSnackbarPresenter
|
import org.mozilla.fenix.components.FenixSnackbarPresenter
|
||||||
import org.mozilla.fenix.components.Services
|
import org.mozilla.fenix.components.Services
|
||||||
import org.mozilla.fenix.components.metrics.Event
|
import org.mozilla.fenix.components.metrics.Event
|
||||||
|
@ -43,13 +47,27 @@ class BookmarkControllerTest {
|
||||||
private val homeActivity: HomeActivity = mockk(relaxed = true)
|
private val homeActivity: HomeActivity = mockk(relaxed = true)
|
||||||
private val services: Services = mockk(relaxed = true)
|
private val services: Services = mockk(relaxed = true)
|
||||||
|
|
||||||
private val item = BookmarkNode(BookmarkNodeType.ITEM, "456", "123", 0, "Mozilla", "http://mozilla.org", null)
|
private val item =
|
||||||
private val subfolder = BookmarkNode(BookmarkNodeType.FOLDER, "987", "123", 0, "Subfolder", null, listOf())
|
BookmarkNode(BookmarkNodeType.ITEM, "456", "123", 0, "Mozilla", "http://mozilla.org", null)
|
||||||
|
private val subfolder =
|
||||||
|
BookmarkNode(BookmarkNodeType.FOLDER, "987", "123", 0, "Subfolder", null, listOf())
|
||||||
private val childItem = BookmarkNode(
|
private val childItem = BookmarkNode(
|
||||||
BookmarkNodeType.ITEM, "987", "123", 2, "Firefox", "https://www.mozilla.org/en-US/firefox/", null
|
BookmarkNodeType.ITEM,
|
||||||
|
"987",
|
||||||
|
"123",
|
||||||
|
2,
|
||||||
|
"Firefox",
|
||||||
|
"https://www.mozilla.org/en-US/firefox/",
|
||||||
|
null
|
||||||
)
|
)
|
||||||
private val tree = BookmarkNode(
|
private val tree = BookmarkNode(
|
||||||
BookmarkNodeType.FOLDER, "123", null, 0, "Mobile", null, listOf(item, item, childItem, subfolder)
|
BookmarkNodeType.FOLDER,
|
||||||
|
"123",
|
||||||
|
null,
|
||||||
|
0,
|
||||||
|
"Mobile",
|
||||||
|
null,
|
||||||
|
listOf(item, item, childItem, subfolder)
|
||||||
)
|
)
|
||||||
private val root = BookmarkNode(
|
private val root = BookmarkNode(
|
||||||
BookmarkNodeType.FOLDER, BookmarkRoot.Root.id, null, 0, BookmarkRoot.Root.name, null, null
|
BookmarkNodeType.FOLDER, BookmarkRoot.Root.id, null, 0, BookmarkRoot.Root.name, null, null
|
||||||
|
@ -113,7 +131,11 @@ class BookmarkControllerTest {
|
||||||
|
|
||||||
verify {
|
verify {
|
||||||
invokePendingDeletion.invoke()
|
invokePendingDeletion.invoke()
|
||||||
navController.navigate(BookmarkFragmentDirections.actionBookmarkFragmentToBookmarkEditFragment(item.guid))
|
navController.navigate(
|
||||||
|
BookmarkFragmentDirections.actionBookmarkFragmentToBookmarkEditFragment(
|
||||||
|
item.guid
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -145,16 +167,13 @@ class BookmarkControllerTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `handleBookmarkSharing should navigate to the 'Share' fragment`() {
|
fun `handleBookmarkSharing should navigate to the 'Share' fragment`() {
|
||||||
|
val navDirectionsSlot = slot<NavDirections>()
|
||||||
|
every { navController.navigate(capture(navDirectionsSlot)) } just Runs
|
||||||
|
|
||||||
controller.handleBookmarkSharing(item)
|
controller.handleBookmarkSharing(item)
|
||||||
|
|
||||||
verify {
|
verify {
|
||||||
invokePendingDeletion.invoke()
|
navController.navigate(navDirectionsSlot.captured)
|
||||||
navController.navigate(
|
|
||||||
BookmarkFragmentDirections.actionBookmarkFragmentToShareFragment(
|
|
||||||
item.url,
|
|
||||||
item.title
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue