Skip to content

Commit 42a6a4c

Browse files
jonalmeidapocmo
authored andcommitted
Closes mozilla-mobile#1127: Expose ReloadPageButton through BrowserToolbar
This code already exists in our sample app, and was moved to make it available to apps as well. Renamed ReloadPageAction -> TwoStateButton. Updates changelog doc with this and the parent issue.
1 parent f3e8295 commit 42a6a4c

File tree

5 files changed

+124
-53
lines changed

5 files changed

+124
-53
lines changed

components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import android.util.AttributeSet
1313
import android.view.View
1414
import android.view.View.OnFocusChangeListener
1515
import android.view.ViewGroup
16+
import android.widget.ImageButton
1617
import mozilla.components.browser.menu.BrowserMenuBuilder
1718
import mozilla.components.browser.toolbar.display.DisplayToolbar
1819
import mozilla.components.browser.toolbar.edit.EditToolbar
@@ -433,6 +434,50 @@ class BrowserToolbar @JvmOverloads constructor(
433434
}
434435
}
435436

437+
/**
438+
* An action that either shows an active button or an inactive button based on the provided
439+
* <code>isEnabled</code> lambda.
440+
*
441+
* @param enabledImage The drawable to be show if the button is in the enabled stated.
442+
* @param enabledContentDescription The content description to use if the button is in the enabled state.
443+
* @param disabledImage The drawable to be show if the button is in the disabled stated.
444+
* @param disabledContentDescription The content description to use if the button is in the enabled state.
445+
* @param isEnabled Lambda that returns true of false to indicate whether this button should be enabled/disabled.
446+
* @param background A custom (stateful) background drawable resource to be used.
447+
* @param listener Callback that will be invoked whenever the checked state changes.
448+
*/
449+
open class TwoStateButton(
450+
private val enabledImage: Drawable,
451+
private val enabledContentDescription: String,
452+
private val disabledImage: Drawable,
453+
private val disabledContentDescription: String,
454+
private val isEnabled: () -> Boolean = { true },
455+
background: Int = 0,
456+
listener: () -> Unit
457+
) : BrowserToolbar.Button(
458+
enabledImage,
459+
enabledContentDescription,
460+
listener = listener,
461+
background = background
462+
) {
463+
var enabled: Boolean = false
464+
private set
465+
466+
override fun bind(view: View) {
467+
enabled = isEnabled.invoke()
468+
469+
val button = view as ImageButton
470+
471+
if (enabled) {
472+
button.setImageDrawable(disabledImage)
473+
button.contentDescription = disabledContentDescription
474+
} else {
475+
button.setImageDrawable(enabledImage)
476+
button.contentDescription = enabledContentDescription
477+
}
478+
}
479+
}
480+
436481
companion object {
437482
private const val DEFAULT_TOOLBAR_HEIGHT_DP = 56
438483
internal const val ACTION_PADDING_DP = 16

components/browser/toolbar/src/test/java/mozilla/components/browser/toolbar/BrowserToolbarTest.kt

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@ package mozilla.components.browser.toolbar
66

77
import android.graphics.Color
88
import android.graphics.Typeface
9+
import android.graphics.drawable.Drawable
910
import android.util.AttributeSet
1011
import android.view.View
12+
import android.widget.ImageButton
1113
import android.widget.LinearLayout
1214
import mozilla.components.browser.menu.BrowserMenuBuilder
1315
import mozilla.components.browser.toolbar.BrowserToolbar.Companion.ACTION_PADDING_DP
@@ -718,4 +720,21 @@ class BrowserToolbarTest {
718720

719721
assertEquals(false, button.visible())
720722
}
723+
724+
@Test
725+
fun `ReloadPageAction visibility changes update image`() {
726+
val reloadImage: Drawable = mock()
727+
val stopImage: Drawable = mock()
728+
val view: ImageButton = mock()
729+
var reloadPageAction = BrowserToolbar.TwoStateButton(reloadImage, "reload", stopImage, "stop") {}
730+
assertFalse(reloadPageAction.enabled)
731+
reloadPageAction.bind(view)
732+
verify(view).setImageDrawable(stopImage)
733+
verify(view).contentDescription = "stop"
734+
735+
reloadPageAction = BrowserToolbar.TwoStateButton(reloadImage, "reload", stopImage, "stop", { false }) {}
736+
reloadPageAction.bind(view)
737+
verify(view).setImageDrawable(stopImage)
738+
verify(view).contentDescription = "reload"
739+
}
721740
}

docs/changelog.md

Lines changed: 54 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -30,25 +30,25 @@ permalink: /changelog/
3030

3131
```kotlin
3232
// Before
33-
Config.custom(CONFIG_URL).then { config: Config ->
33+
Config.custom(CONFIG_URL).then { config: Config ->
3434
account = FirefoxAccount(config, CLIENT_ID, REDIRECT_URL)
3535
}
3636

37-
// Now
37+
// Now
3838
val account = async {
3939
Config.custom(CONFIG_URL).await().use { config ->
4040
FirefoxAccount(config, CLIENT_ID, REDIRECT_URL)
41-
}
42-
}
41+
}
42+
}
4343
```
4444
In case error handling is needed, the new API will also become easier to work with:
45-
```kotlin
45+
```kotlin
4646
// Before
4747
account.beginOAuthFlow(scopes, wantsKeys).then({ url ->
4848
showLoginScreen(url)
4949
}, { exception ->
5050
handleException(exception)
51-
}
51+
})
5252

5353
// Now
5454
async {
@@ -63,14 +63,60 @@ permalink: /changelog/
6363
* **browser-engine-system, browser-engine-gecko, browser-engine-gecko-beta and browser-engine-gecko-nightly**:
6464
Adding support for using `SystemEngineView` and `GeckoEngineView` in a `CoordinatorLayout`.
6565
This allows to create nice transitions like hiding the toolbar when scrolls.
66+
* **browser-session**
67+
* Fixed an issue where a custom tab `Session?` could get selected after removing the currently selected `Session`.
68+
* **browser-toolbar**:
69+
* Added TwoStateButton that will change drawables based on the `isEnabled` listener. This is particularly useful for
70+
having a reload/cancel button.
71+
```kotlin
72+
var isLoading: Boolean // updated by some state change.
73+
BrowserToolbar.TwoStateButton(
74+
reloadDrawable,
75+
"reload button",
76+
cancelDrawable,
77+
"cancel button",
78+
{ isLoading }
79+
) { /* On-click listener */ }
80+
```
81+
* BrowserToolbar APIs for Button and ToggleButton have also been updated to accept `Drawable` instead of resource IDs:
82+
```kotlin
83+
// Before
84+
BrowserToolbar.Button(R.drawable.image, "image description") {
85+
// perform an action on click.
86+
}
87+
88+
// Now
89+
val imageDrawable: Drawable = Drawable()
90+
BrowserToolbar.Button(imageDrawable, "image description") {
91+
// perform an action on click.
92+
}
93+
94+
// Before
95+
BrowserToolbar.ToggleButton(
96+
R.drawable.image,
97+
R.drawable.image_selected,
98+
"image description",
99+
"image selected description") {
100+
// perform an action on click.
101+
}
102+
103+
// Now
104+
val imageDrawable: Drawable = Drawable()
105+
val imageSelectedDrawable: Drawable = Drawable()
106+
BrowserToolbar.ToggleButton(
107+
imageDrawable,
108+
imageSelectedDrawable,
109+
"image description",
110+
"image selected description") {
111+
// perform an action on click.
112+
}
113+
```
66114
* **concept-awesomebar**
67115
* 🆕 New component: An abstract definition of an awesome bar component.
68116
* **browser-awesomebar**
69117
* 🆕 New component: A customizable [Awesome Bar](https://support.mozilla.org/en-US/kb/awesome-bar-search-firefox-bookmarks-history-tabs) implementation for browsers.A
70118
* **feature-awesomebar**
71119
* 🆕 New component: A component that connects a [concept-awesomebar](https://github.com/mozilla-mobile/android-components/components/concept/awesomebar/README.md) implementation to a [concept-toolbar](https://github.com/mozilla-mobile/android-components/components/concept/toolbar/README.md) implementation and provides implementations of various suggestion providers.
72-
* **browser-session**
73-
* Fixed an issue where a custom tab `Session? could get selected after removing the currently selected `Session`.
74120

75121
# 0.29.0
76122

samples/toolbar/src/main/java/org/mozilla/samples/toolbar/SampleToolbarHelpers.kt

Lines changed: 0 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,15 @@ import android.content.Context
55
import android.content.Intent
66
import android.graphics.Canvas
77
import android.graphics.drawable.ClipDrawable
8-
import android.graphics.drawable.Drawable
98
import android.support.v7.widget.RecyclerView
109
import android.view.Gravity
1110
import android.view.LayoutInflater
1211
import android.view.View
1312
import android.view.ViewGroup
14-
import android.widget.ImageButton
1513
import android.widget.TextView
1614
import kotlinx.coroutines.experimental.android.UI
1715
import kotlinx.coroutines.experimental.delay
1816
import kotlinx.coroutines.experimental.launch
19-
import mozilla.components.browser.toolbar.BrowserToolbar
2017

2118
// Code needed for assembling the sample application - but not needed to actually explain the toolbar
2219

@@ -129,39 +126,3 @@ class UrlBoxProgressView(
129126
progressDrawable.draw(canvas)
130127
}
131128
}
132-
133-
/**
134-
* A custom page action that either shows a reload button or a stop button based on the provided
135-
* <code>isLoading</code> lambda.
136-
*/
137-
class ReloadPageAction(
138-
private val reloadImage: Drawable,
139-
private val reloadContentDescription: String,
140-
private val stopImage: Drawable,
141-
private val stopContentDescription: String,
142-
private val isLoading: () -> Boolean,
143-
background: Int = 0,
144-
listener: () -> Unit
145-
) : BrowserToolbar.Button(
146-
reloadImage,
147-
reloadContentDescription,
148-
listener = listener,
149-
background = background
150-
) {
151-
var loading: Boolean = false
152-
private set
153-
154-
override fun bind(view: View) {
155-
loading = isLoading.invoke()
156-
157-
val button = view as ImageButton
158-
159-
if (loading) {
160-
button.setImageDrawable(stopImage)
161-
button.contentDescription = stopContentDescription
162-
} else {
163-
button.setImageDrawable(reloadImage)
164-
button.contentDescription = reloadContentDescription
165-
}
166-
}
167-
}

samples/toolbar/src/main/java/org/mozilla/samples/toolbar/ToolbarActivity.kt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -290,12 +290,12 @@ class ToolbarActivity : AppCompatActivity() {
290290
// Add a custom page action for reload and two browser actions
291291
// //////////////////////////////////////////////////////////////////////////////////////////
292292

293-
val reload = ReloadPageAction(
294-
reloadImage = resources.getThemedDrawable(mozilla.components.ui.icons.R.drawable.mozac_ic_refresh),
295-
reloadContentDescription = "Reload",
296-
stopImage = resources.getThemedDrawable(mozilla.components.ui.icons.R.drawable.mozac_ic_stop),
297-
stopContentDescription = "Stop",
298-
isLoading = { loading },
293+
val reload = BrowserToolbar.TwoStateButton(
294+
enabledImage = resources.getThemedDrawable(mozilla.components.ui.icons.R.drawable.mozac_ic_refresh),
295+
enabledContentDescription = "Reload",
296+
disabledImage = resources.getThemedDrawable(mozilla.components.ui.icons.R.drawable.mozac_ic_stop),
297+
disabledContentDescription = "Stop",
298+
isEnabled = { loading },
299299
background = R.drawable.pageaction_background
300300
) {
301301
if (loading) {

0 commit comments

Comments
 (0)