Skip to content
This repository has been archived by the owner on Jun 17, 2024. It is now read-only.

Commit

Permalink
[components] Add MenuStyle support to menu1
Browse files Browse the repository at this point in the history
  • Loading branch information
NotWoods committed Aug 21, 2020
1 parent 51f624a commit 32fc5a2
Show file tree
Hide file tree
Showing 9 changed files with 113 additions and 113 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,15 @@ import android.view.WindowManager
import android.view.accessibility.AccessibilityNodeInfo
import android.widget.PopupWindow
import androidx.annotation.VisibleForTesting
import androidx.cardview.widget.CardView
import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.core.widget.PopupWindowCompat
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import mozilla.components.browser.menu.BrowserMenu.Orientation.DOWN
import mozilla.components.browser.menu.BrowserMenu.Orientation.UP
import mozilla.components.browser.menu.view.DynamicWidthRecyclerView
import mozilla.components.concept.menu.MenuStyle
import mozilla.components.support.ktx.android.view.isRTL
import mozilla.components.support.ktx.android.view.onNextGlobalLayout

Expand All @@ -39,35 +42,43 @@ open class BrowserMenu internal constructor(
/**
* @param anchor the view on which to pin the popup window.
* @param orientation the preferred orientation to show the popup window.
* @param style Custom styling for this menu.
* @param endOfMenuAlwaysVisible when is set to true makes sure the bottom of the menu is always visible otherwise,
* the top of the menu is always visible.
*/
@SuppressLint("InflateParams")
open fun show(
anchor: View,
orientation: Orientation = DOWN,
style: MenuStyle? = null,
endOfMenuAlwaysVisible: Boolean = false,
onDismiss: () -> Unit = {}
): PopupWindow {
val view = LayoutInflater.from(anchor.context).inflate(R.layout.mozac_browser_menu, null)

adapter.menu = this

menuList = view.findViewById<RecyclerView>(R.id.mozac_browser_menu_recyclerView).apply {
menuList = view.findViewById<DynamicWidthRecyclerView>(R.id.mozac_browser_menu_recyclerView).apply {
layoutManager = LinearLayoutManager(anchor.context, RecyclerView.VERTICAL, false).also {
setEndOfMenuAlwaysVisibleCompact(endOfMenuAlwaysVisible, it)
}
adapter = this@BrowserMenu.adapter
minWidth = style?.minWidth ?: resources.getDimensionPixelSize(R.dimen.mozac_browser_menu_width_min)
maxWidth = style?.maxWidth ?: resources.getDimensionPixelSize(R.dimen.mozac_browser_menu_width_max)
}

menuList?.setAccessibilityDelegate(object : View.AccessibilityDelegate() {
view.findViewById<CardView>(R.id.mozac_browser_menu_menuView).apply {
style?.backgroundColor?.let { setCardBackgroundColor(it) }
}

menuList?.accessibilityDelegate = object : View.AccessibilityDelegate() {
override fun onInitializeAccessibilityNodeInfo(host: View?, info: AccessibilityNodeInfo?) {
super.onInitializeAccessibilityNodeInfo(host, info)
info?.collectionInfo = AccessibilityNodeInfo.CollectionInfo.obtain(
adapter.interactiveCount, 0, false
)
}
})
}

return PopupWindow(
view,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import mozilla.components.browser.state.state.SessionState
import mozilla.components.browser.state.state.WebExtensionState
import mozilla.components.browser.state.store.BrowserStore
import mozilla.components.concept.engine.webextension.Action
import mozilla.components.concept.menu.MenuStyle
import mozilla.components.lib.state.ext.flowScoped
import mozilla.components.support.ktx.kotlinx.coroutines.flow.ifChanged

Expand All @@ -33,6 +34,7 @@ class WebExtensionBrowserMenu internal constructor(
override fun show(
anchor: View,
orientation: Orientation,
style: MenuStyle?,
endOfMenuAlwaysVisible: Boolean,
onDismiss: () -> Unit
): PopupWindow {
Expand All @@ -47,6 +49,7 @@ class WebExtensionBrowserMenu internal constructor(
return super.show(
anchor,
orientation,
style,
endOfMenuAlwaysVisible,
onDismiss
).apply {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,28 +7,21 @@ package mozilla.components.browser.menu.view
import android.annotation.SuppressLint
import android.content.Context
import android.util.AttributeSet
import androidx.annotation.Px
import androidx.annotation.VisibleForTesting
import androidx.recyclerview.widget.RecyclerView
import mozilla.components.browser.menu.R
import mozilla.components.support.ktx.android.util.dpToPx

/**
* [RecylerView] with automatically set width between widthMin / widthMax xml attributes.
* [RecyclerView] with automatically set width between widthMin / widthMax xml attributes.
*/
class DynamicWidthRecyclerView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null
) : RecyclerView(context, attrs) {
@VisibleForTesting internal var minWidth: Int = -1
@VisibleForTesting internal var maxWidth: Int = -1

init {
context.obtainStyledAttributes(attrs, R.styleable.DynamicWidthRecyclerView).apply {
minWidth = getDimension(R.styleable.DynamicWidthRecyclerView_minWidth, minWidth.toFloat()).toInt()
maxWidth = getDimension(R.styleable.DynamicWidthRecyclerView_maxWidth, maxWidth.toFloat()).toInt()
recycle()
}
}
@Px var minWidth: Int = -1
@Px var maxWidth: Int = -1

@VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
override fun onMeasure(widthSpec: Int, heightSpec: Int) {
Expand All @@ -44,49 +37,38 @@ class DynamicWidthRecyclerView @JvmOverloads constructor(
}
}

@VisibleForTesting()
@VisibleForTesting
internal fun setReconciledDimensions(
desiredWidth: Int,
desiredHeight: Int
) {
val minimumTapArea = resources.getDimensionPixelSize(R.dimen.mozac_browser_menu_material_min_tap_area)
val minimumItemWidth = resources.getDimensionPixelSize(R.dimen.mozac_browser_menu_material_min_item_width)

val reconciledWidth = desiredWidth
.coerceAtLeast(minWidth)
// Follow material guidelines where the minimum width is 112dp.
.coerceAtLeast(getMaterialMinimumItemWidthInPx())
.coerceAtLeast(minimumItemWidth)
.coerceAtMost(maxWidth)
// Leave at least 48dp as a tappable “exit area” available whenever the menu is open.
.coerceAtMost(getScreenWidth() - getMaterialMinimumTapAreaInPx())
.coerceAtMost(getScreenWidth() - minimumTapArea)

callSetMeasuredDimension(reconciledWidth, desiredHeight)
}

@VisibleForTesting()
@VisibleForTesting
internal fun getScreenWidth(): Int = resources.displayMetrics.widthPixels

@VisibleForTesting()
internal fun getMaterialMinimumTapAreaInPx() =
MATERIAL_MINIMUM_TAP_AREA_DP.dpToPx(resources.displayMetrics)

@VisibleForTesting()
internal fun getMaterialMinimumItemWidthInPx() =
MATERIAL_MINIMUM_ITEM_WIDTH_DP.dpToPx(resources.displayMetrics)

@SuppressLint("WrongCall")
@VisibleForTesting()
@VisibleForTesting
// Used for testing protected super.onMeasure(..) calls will be executed.
internal fun callParentOnMeasure(widthSpec: Int, heightSpec: Int) {
super.onMeasure(widthSpec, heightSpec)
}

@VisibleForTesting()
@VisibleForTesting
// Used for testing final protected setMeasuredDimension(..) calls were executed
internal fun callSetMeasuredDimension(width: Int, height: Int) {
setMeasuredDimension(width, height)
}

@VisibleForTesting()
internal companion object {
const val MATERIAL_MINIMUM_TAP_AREA_DP = 48
const val MATERIAL_MINIMUM_ITEM_WIDTH_DP = 112
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
style="@style/Mozac.Browser.Menu"
android:id="@+id/mozac_browser_menu_menuView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:cardCornerRadius="@dimen/mozac_browser_menu_corner_radius"
Expand All @@ -19,8 +20,6 @@
android:overScrollMode="never"
android:layout_width="@dimen/mozac_browser_menu_width"
android:layout_height="wrap_content"
app:maxWidth="@dimen/mozac_browser_menu_width_max"
app:minWidth="@dimen/mozac_browser_menu_width_min"
tools:listitem="@layout/mozac_browser_menu_item_simple" />

</androidx.cardview.widget.CardView>

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@
<dimen name="mozac_browser_menu_item_container_padding_end">16dp</dimen>
<!--Menu Item -->

<!--DynamicWidthRecyclerView -->
<dimen name="mozac_browser_menu_material_min_tap_area">48dp</dimen>
<dimen name="mozac_browser_menu_material_min_item_width">112dp</dimen>
<!--DynamicWidthRecyclerView -->

<!--BrowserMenuDivider -->
<dimen name="mozac_browser_menu_item_divider_height">1dp</dimen>
<!--BrowserMenuDivider -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,21 @@

package mozilla.components.browser.menu

import android.content.res.ColorStateList
import android.graphics.Color
import android.os.Build
import android.view.Gravity
import android.view.View
import android.widget.Button
import android.widget.PopupWindow
import androidx.cardview.widget.CardView
import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.test.ext.junit.runners.AndroidJUnit4
import mozilla.components.browser.menu.item.SimpleBrowserMenuItem
import mozilla.components.browser.menu.view.DynamicWidthRecyclerView
import mozilla.components.concept.menu.MenuStyle
import mozilla.components.support.test.any
import mozilla.components.support.test.mock
import mozilla.components.support.test.robolectric.testContext
Expand Down Expand Up @@ -70,6 +75,33 @@ class BrowserMenuTest {
assertTrue(menu.isShown)
}

@Test
fun `show assigns width and background color`() {
val items = listOf(SimpleBrowserMenuItem("Hello") {})

val adapter = BrowserMenuAdapter(testContext, items)

val menu = BrowserMenu(adapter)

val anchor = Button(testContext)
val popup = menu.show(anchor, style = MenuStyle(
backgroundColor = Color.RED,
minWidth = 20,
maxWidth = 500
))

assertNotNull(popup)
assertEquals(anchor, menu.currAnchor)
assertTrue(menu.isShown)

val cardView = popup.contentView.findViewById<CardView>(R.id.mozac_browser_menu_menuView)
val recyclerView = popup.contentView.findViewById<DynamicWidthRecyclerView>(R.id.mozac_browser_menu_recyclerView)

assertEquals(ColorStateList.valueOf(Color.RED), cardView.cardBackgroundColor)
assertEquals(20, recyclerView.minWidth)
assertEquals(500, recyclerView.maxWidth)
}

@Test
fun `dismiss sets isShown to false`() {
val items = listOf(
Expand Down
Loading

0 comments on commit 32fc5a2

Please sign in to comment.