This repository has been archived by the owner on Jun 17, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 331
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[components] For mozilla-mobile/android-components#7833: Generate con…
…cept-menu items for addons
- Loading branch information
1 parent
a626122
commit f506f74
Showing
19 changed files
with
584 additions
and
40 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
56 changes: 56 additions & 0 deletions
56
...concept/engine/src/test/java/mozilla/components/concept/engine/webextension/ActionTest.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
/* 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 mozilla.components.concept.engine.webextension | ||
|
||
import android.graphics.Color | ||
import org.junit.Assert.assertEquals | ||
import org.junit.Test | ||
|
||
class ActionTest { | ||
|
||
private val onClick: () -> Unit = {} | ||
private val baseAction = Action( | ||
title = "title", | ||
enabled = false, | ||
loadIcon = null, | ||
badgeText = "badge", | ||
badgeTextColor = Color.BLACK, | ||
badgeBackgroundColor = Color.BLUE, | ||
onClick = onClick | ||
) | ||
|
||
@Test | ||
fun `override using non-null attributes`() { | ||
val overridden = baseAction.copyWithOverride(Action( | ||
title = "other", | ||
enabled = null, | ||
loadIcon = null, | ||
badgeText = null, | ||
badgeTextColor = Color.WHITE, | ||
badgeBackgroundColor = null, | ||
onClick = onClick | ||
)) | ||
|
||
assertEquals( | ||
Action( | ||
title = "other", | ||
enabled = false, | ||
loadIcon = null, | ||
badgeText = "badge", | ||
badgeTextColor = Color.WHITE, | ||
badgeBackgroundColor = Color.BLUE, | ||
onClick = onClick | ||
), | ||
overridden | ||
) | ||
} | ||
|
||
@Test | ||
fun `override using null action`() { | ||
val overridden = baseAction.copyWithOverride(null) | ||
|
||
assertEquals(baseAction, overridden) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
54 changes: 54 additions & 0 deletions
54
...s/src/main/java/mozilla/components/feature/addons/menu/WebExtensionActionMenuCandidate.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
/* 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 mozilla.components.feature.addons.menu | ||
|
||
import android.content.Context | ||
import androidx.appcompat.content.res.AppCompatResources.getDrawable | ||
import androidx.core.graphics.drawable.toDrawable | ||
import mozilla.components.concept.engine.webextension.Action | ||
import mozilla.components.concept.menu.candidate.AsyncDrawableMenuIcon | ||
import mozilla.components.concept.menu.candidate.ContainerStyle | ||
import mozilla.components.concept.menu.candidate.TextMenuCandidate | ||
import mozilla.components.concept.menu.candidate.TextMenuIcon | ||
import mozilla.components.concept.menu.candidate.TextStyle | ||
import mozilla.components.feature.addons.R | ||
|
||
/** | ||
* Create a browser menu item for displaying a web extension action. | ||
* | ||
* @param onClick a callback to be invoked when this menu item is clicked. | ||
*/ | ||
fun Action.createMenuCandidate( | ||
context: Context, | ||
onClick: () -> Unit = this.onClick | ||
): TextMenuCandidate { | ||
return TextMenuCandidate( | ||
title.orEmpty(), | ||
start = loadIcon?.let { loadIcon -> | ||
val defaultIcon = getDrawable(context, R.drawable.mozac_ic_web_extension_default_icon) | ||
AsyncDrawableMenuIcon( | ||
loadDrawable = { _, height -> | ||
loadIcon(height)?.toDrawable(context.resources) | ||
}, | ||
loadingDrawable = defaultIcon, | ||
fallbackDrawable = defaultIcon | ||
) | ||
}, | ||
end = badgeText?.let { badgeText -> | ||
TextMenuIcon( | ||
badgeText, | ||
backgroundTint = badgeBackgroundColor, | ||
textStyle = TextStyle( | ||
color = badgeTextColor | ||
) | ||
) | ||
}, | ||
containerStyle = ContainerStyle( | ||
isVisible = true, | ||
isEnabled = enabled ?: false | ||
), | ||
onClick = onClick | ||
) | ||
} |
148 changes: 148 additions & 0 deletions
148
...s/src/main/java/mozilla/components/feature/addons/menu/WebExtensionNestedMenuCandidate.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,148 @@ | ||
/* 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 mozilla.components.feature.addons.menu | ||
|
||
import android.content.Context | ||
import androidx.annotation.ColorInt | ||
import mozilla.components.browser.state.selector.findTabOrCustomTabOrSelectedTab | ||
import mozilla.components.browser.state.state.BrowserState | ||
import mozilla.components.browser.state.state.SessionState | ||
import mozilla.components.browser.state.state.WebExtensionState | ||
import mozilla.components.concept.menu.Side | ||
import mozilla.components.concept.menu.candidate.DividerMenuCandidate | ||
import mozilla.components.concept.menu.candidate.DrawableMenuIcon | ||
import mozilla.components.concept.menu.candidate.MenuCandidate | ||
import mozilla.components.concept.menu.candidate.NestedMenuCandidate | ||
import mozilla.components.concept.menu.candidate.TextMenuCandidate | ||
import mozilla.components.feature.addons.R | ||
|
||
private fun createBackMenuItem( | ||
context: Context, | ||
@ColorInt webExtIconTintColor: Int? | ||
) = NestedMenuCandidate( | ||
id = R.drawable.mozac_ic_back, | ||
text = context.getString(R.string.mozac_feature_addons_addons), | ||
start = DrawableMenuIcon( | ||
context, | ||
R.drawable.mozac_ic_back, | ||
tint = webExtIconTintColor | ||
), | ||
subMenuItems = null | ||
) | ||
|
||
private fun createAddonsManagerItem( | ||
context: Context, | ||
@ColorInt webExtIconTintColor: Int?, | ||
onAddonsManagerTapped: () -> Unit | ||
) = TextMenuCandidate( | ||
text = context.getString(R.string.mozac_feature_addons_addons_manager), | ||
start = DrawableMenuIcon( | ||
context, | ||
R.drawable.mozac_ic_extensions, | ||
tint = webExtIconTintColor | ||
), | ||
onClick = onAddonsManagerTapped | ||
) | ||
|
||
private fun createWebExtensionSubMenuItems( | ||
context: Context, | ||
extensions: Collection<WebExtensionState>, | ||
tab: SessionState?, | ||
onAddonsItemTapped: (String) -> Unit | ||
): List<MenuCandidate> { | ||
val menuItems = mutableListOf<MenuCandidate>() | ||
|
||
extensions | ||
.filter { it.enabled } | ||
.filterNot { !it.allowedInPrivateBrowsing && tab?.content?.private == true } | ||
.sortedBy { it.name } | ||
.forEach { extension -> | ||
val tabExtensionState = tab?.extensionState?.get(extension.id) | ||
extension.browserAction?.let { browserAction -> | ||
menuItems.add( | ||
browserAction.copyWithOverride(tabExtensionState?.browserAction).createMenuCandidate( | ||
context | ||
) { | ||
onAddonsItemTapped(extension.id) | ||
browserAction.onClick() | ||
} | ||
) | ||
} | ||
|
||
extension.pageAction?.let { pageAction -> | ||
menuItems.add( | ||
pageAction.copyWithOverride(tabExtensionState?.pageAction).createMenuCandidate( | ||
context | ||
) { | ||
onAddonsItemTapped(extension.id) | ||
pageAction.onClick() | ||
} | ||
) | ||
} | ||
} | ||
|
||
return menuItems | ||
} | ||
|
||
/** | ||
* Create a browser menu item for displaying a list of web extensions. | ||
* | ||
* @param tabId ID of tab used to load tab-specific extension state. | ||
* @param webExtIconTintColor Optional color used to tint the icons of back and add-ons manager menu items. | ||
* @param appendExtensionSubMenuAt If web extension sub menu should appear at the top (start) of | ||
* the menu, or if web extensions should appear at the bottom of the menu (end). | ||
* @param onAddonsItemTapped Callback to be invoked when a web extension action item is selected. | ||
* Can be used to emit telemetry. | ||
* @param onAddonsManagerTapped Callback to be invoked when add-ons manager menu item is selected. | ||
*/ | ||
@Suppress("LongParameterList") | ||
fun BrowserState.createWebExtensionMenuCandidate( | ||
context: Context, | ||
tabId: String? = null, | ||
@ColorInt webExtIconTintColor: Int? = null, | ||
appendExtensionSubMenuAt: Side = Side.END, | ||
onAddonsItemTapped: (String) -> Unit = {}, | ||
onAddonsManagerTapped: () -> Unit = {} | ||
): MenuCandidate { | ||
val items = createWebExtensionSubMenuItems( | ||
context, | ||
extensions = extensions.values, | ||
tab = findTabOrCustomTabOrSelectedTab(tabId), | ||
onAddonsItemTapped = onAddonsItemTapped | ||
) | ||
|
||
val addonsManagerItem = createAddonsManagerItem( | ||
context, | ||
webExtIconTintColor = webExtIconTintColor, | ||
onAddonsManagerTapped = onAddonsManagerTapped | ||
) | ||
|
||
return if (items.isNotEmpty()) { | ||
val firstItem: MenuCandidate | ||
val lastItem: MenuCandidate | ||
when (appendExtensionSubMenuAt) { | ||
Side.START -> { | ||
firstItem = createBackMenuItem(context, webExtIconTintColor) | ||
lastItem = addonsManagerItem | ||
} | ||
Side.END -> { | ||
firstItem = addonsManagerItem | ||
lastItem = createBackMenuItem(context, webExtIconTintColor) | ||
} | ||
} | ||
|
||
NestedMenuCandidate( | ||
id = R.string.mozac_feature_addons_addons, | ||
text = context.getString(R.string.mozac_feature_addons_addons), | ||
start = addonsManagerItem.start, | ||
subMenuItems = listOf(firstItem, DividerMenuCandidate()) + | ||
items + listOf(DividerMenuCandidate(), lastItem) | ||
) | ||
} else { | ||
addonsManagerItem.copy( | ||
text = context.getString(R.string.mozac_feature_addons_addons) | ||
) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
Oops, something went wrong.