Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add topBar button animations on iOS #7127

Merged
merged 10 commits into from
May 25, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ public static TopBarOptions parse(Context context, TypefaceLoader typefaceLoader
options.borderHeight = FractionParser.parse(json, "borderHeight");
options.elevation = FractionParser.parse(json, "elevation");
options.topMargin = NumberParser.parse(json, "topMargin");
options.animateLeftButtons = BoolParser.parse(json, "animateLeftButtons");
options.animateRightButtons = BoolParser.parse(json, "animateRightButtons");
options.buttons = TopBarButtons.parse(context, json);

options.rightButtonColor = ColorParser.parse(context, json, "rightButtonColor");
Expand All @@ -68,7 +70,8 @@ public static TopBarOptions parse(Context context, TypefaceLoader typefaceLoader
public Number topMargin = new NullNumber();
public Fraction borderHeight = new NullFraction();
public Colour borderColor = new NullColor();

public Bool animateLeftButtons = new NullBool();
public Bool animateRightButtons = new NullBool();
// Deprecated
public Colour rightButtonColor = new NullColor();
public Colour leftButtonColor = new NullColor();
Expand Down Expand Up @@ -96,6 +99,8 @@ void mergeWith(final TopBarOptions other) {
if (other.borderColor.hasValue()) borderColor = other.borderColor;
if (other.elevation.hasValue()) elevation = other.elevation;
if (other.topMargin.hasValue()) topMargin = other.topMargin;
if (other.animateLeftButtons.hasValue()) animateLeftButtons = other.animateLeftButtons;
if (other.animateRightButtons.hasValue()) animateRightButtons = other.animateRightButtons;

if (other.rightButtonColor.hasValue()) rightButtonColor = other.rightButtonColor;
if (other.leftButtonColor.hasValue()) leftButtonColor = other.leftButtonColor;
Expand All @@ -120,6 +125,8 @@ public TopBarOptions mergeWithDefault(TopBarOptions defaultOptions) {
if (!borderColor.hasValue()) borderColor = defaultOptions.borderColor;
if (!elevation.hasValue()) elevation = defaultOptions.elevation;
if (!topMargin.hasValue()) topMargin = defaultOptions.topMargin;
if (!animateLeftButtons.hasValue()) animateLeftButtons = defaultOptions.animateLeftButtons;
if (!animateRightButtons.hasValue()) animateRightButtons = defaultOptions.animateRightButtons;

if (!rightButtonColor.hasValue()) rightButtonColor = defaultOptions.rightButtonColor;
if (!leftButtonColor.hasValue()) leftButtonColor = defaultOptions.leftButtonColor;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,10 @@ private void applyButtons(TopBarOptions options, ViewController child) {
if (options.buttons.back.visible.isTrue() && !options.buttons.hasLeftButtons()) {
topBar.setBackButton(createButtonController(options.buttons.back));
}

if(options.animateRightButtons.hasValue())
topBar.animateRightButtons(options.animateRightButtons.isTrue());
if(options.animateLeftButtons.hasValue())
topBar.animateLeftButtons(options.animateLeftButtons.isTrue());
topBar.setOverflowButtonColor(options.rightButtonColor.get(Color.BLACK));
}

Expand Down Expand Up @@ -460,7 +463,8 @@ private void mergeTopBarOptions(TopBarOptions resolveOptions, Options options, S

if (topBarOptions.title.height.hasValue()) topBar.setTitleHeight(topBarOptions.title.height.get());
if (topBarOptions.title.topMargin.hasValue()) topBar.setTitleTopMargin(topBarOptions.title.topMargin.get());

if (topBarOptions.animateLeftButtons.hasValue()) topBar.animateLeftButtons(topBarOptions.animateLeftButtons.isTrue());
if (topBarOptions.animateRightButtons.hasValue()) topBar.animateRightButtons(topBarOptions.animateRightButtons.isTrue());
if (topBarOptions.title.component.hasValue()) {
TitleBarReactViewController controller = findTitleComponent(topBarOptions.title.component);
if (controller == null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,13 @@ public void setSubtitleFontSize(double size) {
titleAndButtonsContainer.setSubtitleFontSize((float) size);
}

public void animateRightButtons(boolean animate){
titleAndButtonsContainer.animateRightButtons(animate);
}

public void animateLeftButtons(boolean animate){
titleAndButtonsContainer.animateLeftButtons(animate);
}
public void setSubtitleAlignment(Alignment alignment) {
titleAndButtonsContainer.setSubTitleTextAlignment(alignment);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import android.content.Context
import android.graphics.PorterDuff
import android.graphics.PorterDuffColorFilter
import android.text.SpannableString
import android.transition.AutoTransition
import android.transition.TransitionManager
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
Expand All @@ -14,6 +16,8 @@ import com.reactnativenavigation.utils.ViewUtils
import com.reactnativenavigation.viewcontrollers.stack.topbar.button.ButtonController

open class ButtonBar internal constructor(context: Context) : Toolbar(context) {
var shouldAnimate: Boolean=false

init {
super.setContentInsetsAbsolute(0, 0)
this.contentInsetStartWithNavigation = 0
Expand All @@ -35,17 +39,27 @@ open class ButtonBar internal constructor(context: Context) : Toolbar(context) {
super.setLayoutDirection(layoutDirection)
}

val buttonCount: Int
get() = menu.size()

fun addButton(menuItem: Int, intId: Int, order: Int, styledText: SpannableString): MenuItem? {
if(shouldAnimate)
TransitionManager.beginDelayedTransition(this,AutoTransition())
return this.menu?.add(menuItem,
intId,
order,
styledText)
}

val buttonCount: Int
get() = menu.size()
fun removeButton(buttonId: Int) {
if(shouldAnimate)
TransitionManager.beginDelayedTransition(this,AutoTransition())
menu.removeItem(buttonId)
}

open fun clearButtons() {
if(shouldAnimate)
TransitionManager.beginDelayedTransition(this,AutoTransition())
clearBackButton()
if (menu.size() > 0) menu.clear()
}
Expand All @@ -58,10 +72,6 @@ open class ButtonBar internal constructor(context: Context) : Toolbar(context) {
return menuItem != null && menu.findItem(menuItem.itemId) != null && menuItem.order == order
}

fun removeButton(buttonId: Int) {
menu.removeItem(buttonId)
}

fun setBackButton(button: ButtonController) {
button.applyNavigationIcon(this)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,13 @@ class TitleAndButtonsContainer(context: Context) : ViewGroup(context) {
}
}

fun animateLeftButtons(animate:Boolean) {
leftButtonBar.shouldAnimate = animate
}
fun animateRightButtons(animate:Boolean) {
rightButtonBar.shouldAnimate = animate
}

private var titleSubTitleBar = TitleSubTitleLayout(context)
var leftButtonBar = ButtonBar(context)
private set
Expand Down Expand Up @@ -64,7 +71,7 @@ class TitleAndButtonsContainer(context: Context) : ViewGroup(context) {
component?.layoutDirection = layoutDirection
titleSubTitleBar.layoutDirection = layoutDirection
rightButtonBar.layoutDirection = layoutDirection
leftButtonBar.layoutDirection = layoutDirection
leftButtonBar.layoutDirection = if(isRTL()) View.LAYOUT_DIRECTION_LTR else View.LAYOUT_DIRECTION_RTL
}

fun setSubTitleTextAlignment(alignment: Alignment) = titleSubTitleBar.setSubTitleAlignment(alignment)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,30 @@ class StackPresenterTest : BaseTest() {
verify(topBar, never()).clearLeftButtons()
}

@Test
fun mergeChildOptions_mergeAnimateLeftRightButtons(){
val options = Options().apply {
topBar.animateLeftButtons = Bool(false)
}
uut.mergeChildOptions(options, EMPTY_OPTIONS, parent, child)
verify(topBar).animateLeftButtons(false)
verify(topBar, never()).animateRightButtons(any())

options.apply {
topBar.animateRightButtons = Bool(true)
}
uut.mergeChildOptions(options, EMPTY_OPTIONS, parent, child)
verify(topBar).animateRightButtons(true)


options.apply {
topBar.animateRightButtons = Bool(false)
topBar.animateLeftButtons = Bool(true)
}
uut.mergeChildOptions(options, EMPTY_OPTIONS, parent, child)
verify(topBar).animateRightButtons(false)
verify(topBar).animateLeftButtons(true)
}
@Test
fun mergeTopBarOptions() {
val options = Options()
Expand Down Expand Up @@ -796,6 +820,32 @@ class StackPresenterTest : BaseTest() {
buttons.forEach { assertThat(it.isDestroyed).isFalse() }
}

@Test
fun applyChildOptions_shouldNotPassAnimateLeftRightButtonBarWhenNoValue() {
val options = Options().apply {
topBar.buttons.right = ArrayList(listOf(componentBtn1))
topBar.buttons.left = ArrayList(listOf(componentBtn2))

}
uut.applyChildOptions(options, parent, child)
verify(topBar, never()).animateLeftButtons(any())
verify(topBar, never()).animateLeftButtons(any())
}

@Test
fun applyChildOptions_shouldPassAnimateLeftRightButtonBar() {
val options = Options().apply {
topBar.buttons.right = ArrayList(listOf(componentBtn1))
topBar.buttons.left = ArrayList(listOf(componentBtn2))
topBar.animateLeftButtons= Bool(false);
topBar.animateRightButtons= Bool(true);
}

uut.applyChildOptions(options, parent, child)
verify(topBar).animateRightButtons(true)
verify(topBar).animateLeftButtons(false)
}

@Test
fun onChildDestroyed_destroyedButtons() {
val options = Options()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,17 @@ import org.junit.Test
import org.mockito.Mockito
import org.mockito.Mockito.times
import kotlin.math.roundToInt
import kotlin.test.assertFalse

private const val UUT_WIDTH = 1000
private const val UUT_HEIGHT = 100

class TitleAndButtonsContainerTest : BaseTest() {
lateinit var uut: TitleAndButtonsContainer
private lateinit var activity: Activity
private lateinit var mockLeftBar: ButtonBar;
private lateinit var mockRightBar: ButtonBar;
private lateinit var mockComponent: View;
private lateinit var mockLeftBar: ButtonBar
private lateinit var mockRightBar: ButtonBar
private lateinit var mockComponent: View
override fun beforeEach() {
super.beforeEach()
setup()
Expand Down Expand Up @@ -79,6 +80,28 @@ class TitleAndButtonsContainerTest : BaseTest() {
idleMainLooper()
}

@Test
fun `animateLeftRightButtons - should be false as default`(){
assertFalse(mockLeftBar.shouldAnimate)
assertFalse(mockRightBar.shouldAnimate)
}
@Test
fun `animateLeftRightButtons - should change corresponding button bar`(){
setup(rightBarWidth = 10,leftBarWidth = 20)

uut.animateLeftButtons(true)
verify(mockLeftBar).shouldAnimate=true

uut.animateLeftButtons(false)
verify(mockLeftBar).shouldAnimate=false

uut.animateRightButtons(true)
verify(mockRightBar).shouldAnimate=true

uut.animateRightButtons(false)
verify(mockRightBar).shouldAnimate=false
}

@Test
fun `setComponent - should not change component id`() {
val component = View(activity).apply { id = 19 }
Expand Down
6 changes: 4 additions & 2 deletions lib/ios/RNNButtonsPresenter.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,13 @@

- (void)applyLeftButtons:(NSArray<RNNButtonOptions *> *)leftButtons
defaultColor:(Color *)defaultColor
defaultDisabledColor:(Color *)defaultDisabledColor;
defaultDisabledColor:(Color *)defaultDisabledColor
animated:(BOOL)animated;

- (void)applyRightButtons:(NSArray<RNNButtonOptions *> *)rightButtons
defaultColor:(Color *)defaultColor
defaultDisabledColor:(Color *)defaultDisabledColor;
defaultDisabledColor:(Color *)defaultDisabledColor
animated:(BOOL)animated;

- (void)applyLeftButtonsColor:(UIColor *)color;

Expand Down
10 changes: 6 additions & 4 deletions lib/ios/RNNButtonsPresenter.m
Original file line number Diff line number Diff line change
Expand Up @@ -27,20 +27,22 @@ - (void)bindViewController:(UIViewController<RNNLayoutProtocol> *)viewController

- (void)applyLeftButtons:(NSArray<RNNButtonOptions *> *)leftButtons
defaultColor:(Color *)defaultColor
defaultDisabledColor:(Color *)defaultDisabledColor {
defaultDisabledColor:(Color *)defaultDisabledColor
animated:(BOOL)animated {
[self setButtons:leftButtons
side:@"left"
animated:NO
animated:animated
defaultColor:defaultColor
defaultDisabledColor:defaultDisabledColor];
}

- (void)applyRightButtons:(NSArray<RNNButtonOptions *> *)rightButtons
defaultColor:(Color *)defaultColor
defaultDisabledColor:(Color *)defaultDisabledColor {
defaultDisabledColor:(Color *)defaultDisabledColor
animated:(BOOL)animated {
[self setButtons:rightButtons
side:@"right"
animated:NO
animated:animated
defaultColor:defaultColor
defaultDisabledColor:defaultDisabledColor];
}
Expand Down
12 changes: 8 additions & 4 deletions lib/ios/RNNComponentPresenter.m
Original file line number Diff line number Diff line change
Expand Up @@ -91,13 +91,15 @@ - (void)applyOptions:(RNNNavigationOptions *)options {
if (withDefault.topBar.leftButtons) {
[_buttonsPresenter applyLeftButtons:withDefault.topBar.leftButtons
defaultColor:withDefault.topBar.leftButtonColor
defaultDisabledColor:withDefault.topBar.leftButtonDisabledColor];
defaultDisabledColor:withDefault.topBar.leftButtonDisabledColor
animated:withDefault.topBar.animateLeftButtons];
}

if (withDefault.topBar.rightButtons) {
[_buttonsPresenter applyRightButtons:withDefault.topBar.rightButtons
defaultColor:withDefault.topBar.rightButtonColor
defaultDisabledColor:withDefault.topBar.rightButtonDisabledColor];
defaultDisabledColor:withDefault.topBar.rightButtonDisabledColor
animated:withDefault.topBar.animateRightButtons];
}
}

Expand Down Expand Up @@ -193,13 +195,15 @@ - (void)mergeOptions:(RNNNavigationOptions *)mergeOptions
if (mergeOptions.topBar.leftButtons) {
[_buttonsPresenter applyLeftButtons:mergeOptions.topBar.leftButtons
defaultColor:withDefault.topBar.leftButtonColor
defaultDisabledColor:withDefault.topBar.leftButtonDisabledColor];
defaultDisabledColor:withDefault.topBar.leftButtonDisabledColor
animated:withDefault.topBar.animateLeftButtons];
}

if (mergeOptions.topBar.rightButtons) {
[_buttonsPresenter applyRightButtons:mergeOptions.topBar.rightButtons
defaultColor:withDefault.topBar.rightButtonColor
defaultDisabledColor:withDefault.topBar.rightButtonDisabledColor];
defaultDisabledColor:withDefault.topBar.rightButtonDisabledColor
animated:withDefault.topBar.animateRightButtons];
}

if (mergeOptions.topBar.leftButtonColor.hasValue) {
Expand Down
2 changes: 2 additions & 0 deletions lib/ios/RNNTopBarOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
@property(nonatomic, strong) Bool *noBorder;
@property(nonatomic, strong) Color *borderColor;
@property(nonatomic, strong) Bool *animate;
@property(nonatomic, strong) Bool *animateLeftButtons;
@property(nonatomic, strong) Bool *animateRightButtons;
@property(nonatomic, strong) RNNSearchBarOptions *searchBar;
@property(nonatomic, strong) Bool *searchBarHiddenWhenScrolling;
@property(nonatomic, strong) Bool *hideNavBarOnFocusSearchBar;
Expand Down
6 changes: 6 additions & 0 deletions lib/ios/RNNTopBarOptions.m
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ - (instancetype)initWithDict:(NSDictionary *)dict {
self.noBorder = [BoolParser parse:dict key:@"noBorder"];
self.borderColor = [ColorParser parse:dict key:@"borderColor"];
self.animate = [BoolParser parse:dict key:@"animate"];
self.animateLeftButtons = [BoolParser parse:dict key:@"animateLeftButtons"];
self.animateRightButtons = [BoolParser parse:dict key:@"animateRightButtons"];
self.searchBarHiddenWhenScrolling = [BoolParser parse:dict key:@"searchBarHiddenWhenScrolling"];
self.hideNavBarOnFocusSearchBar = [BoolParser parse:dict key:@"hideNavBarOnFocusSearchBar"];
self.testID = [TextParser parse:dict key:@"testID"];
Expand Down Expand Up @@ -69,6 +71,10 @@ - (void)mergeOptions:(RNNTopBarOptions *)options {
self.borderColor = options.borderColor;
if (options.animate.hasValue)
self.animate = options.animate;
if (options.animateLeftButtons.hasValue)
self.animateLeftButtons = options.animateLeftButtons;
if (options.animateRightButtons.hasValue)
self.animateRightButtons = options.animateRightButtons;
if (options.searchBarHiddenWhenScrolling.hasValue)
self.searchBarHiddenWhenScrolling = options.searchBarHiddenWhenScrolling;
if (options.hideNavBarOnFocusSearchBar.hasValue)
Expand Down
10 changes: 10 additions & 0 deletions lib/src/interfaces/Options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -712,6 +712,16 @@ export interface OptionsTopBar {
* #### (Android specific)
*/
topMargin?: number;

/**
* Toggles animation on left buttons bar upon changes
*/
animateLeftButtons?: boolean;

/**
* Toggles animation on right buttons bar upon changes
*/
animateRightButtons?: boolean;
}

export interface SharedElementTransition {
Expand Down
Loading