Skip to content

Topbar v2#2413

Merged
guyca merged 43 commits into
v2from
topbar
Jan 9, 2018
Merged

Topbar v2#2413
guyca merged 43 commits into
v2from
topbar

Conversation

@Cool04ek
Copy link
Copy Markdown
Contributor

No description provided.

@Cool04ek Cool04ek added the v2 label Dec 26, 2017
@Cool04ek Cool04ek requested a review from guyca December 26, 2017 09:08
if (options.hidden == False) {
showTopBar(options.animateHide);
}
if (options.collapse == True) {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This logic isn't a concern of OptionsPresenter. TopBar should have a dedicated class for managing collapse

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, I'll move it out as soon it's ready

@Override
public void addView(View child, int index, ViewGroup.LayoutParams params) {
super.addView(child, index, params);
if (child instanceof ScrollView) {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This means ScrollView must be the root component.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can look for it recursively, but I'm not sure you need to have collapsing Toolbar if ScrollView is not root

if (scrollView != null) {
if (scrollListener != null) {
scrollChangedListener = () -> scrollListener.onScroll(scrollView.getScrollY());
scrollView.getViewTreeObserver().addOnScrollChangedListener(scrollChangedListener);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Last time I checked, this method "skips" scroll events. The events reported are kind of batched or posted, meaning the callback isn't invoked immediately after a scroll. This means that if we need to track finger, this method yields subpar results.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From what I've tested, it produces enough events to track finger. I mean we don't need that much precision.

@Cool04ek Cool04ek changed the title [WIP] Topbar v2 Topbar v2 Jan 5, 2018
ViewGroup.LayoutParams layoutParams = container.getLayoutParams();
layoutParams.height = ViewGroup.LayoutParams.MATCH_PARENT;
container.setLayoutParams(layoutParams);
//TODO: needs refactoring
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Either refactor now, or remove the comment, open an issue detailing what needs to be refactored and assign your self.

@SuppressWarnings("ResourceType")
public class NavigationAnimator {

public interface StackAnimationListener {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rename this interface as well

}

@Override
public void onAnimationCancel(Animator animation) {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Switch to adapter and remove unused methods

AnimatorSet set = new AnimatorSet();
set.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use adapter

set.start();
}

private float getWindowHeight(Context context) {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method doesn't belong here. It should be pulled into some utils class (ViewUtils?)

return metrics.heightPixels;
}

public void animateShowTopBar(final TopBar topBar, final View container) {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like NavigationAnimator has two concerns and should be split into two classes.

  1. Animating screens
  2. Animating TopBar

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I really dislike the word container... we abused it a lot and would love phasing it out.
Please rename to contentView which is also the naming used in NavigationOptions

}

@Override
public void onAnimationCancel(Animator animation) {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adapter

}

@Override
public void onAnimationCancel(Animator animation) {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adapter

options.textFontFamily = typefaceManager.getTypeFace(json.optString("textFontFamily", NO_VALUE));
options.hidden = NavigationOptions.BooleanOptions.parse(json.optString("hidden"));
options.animateHide = NavigationOptions.BooleanOptions.parse(json.optString("animateHide"));
options.collapse = NavigationOptions.BooleanOptions.parse(json.optString("hideOnScroll"));
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider renaming collapse to hideOnScroll? Having the same names across Js and native helps a lot

if (options.hidden == NavigationOptions.BooleanOptions.False) {
showTopBar(options.animateHide);
}
if (options.drawUnder == True) {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OptionsPresenter is bound to become messy real quick. One way of keeping it clean and readable is to avoid having any kind of logic in it. Ideally, it should act as a delegate and invoke the appropriate style methods of the views.
So contentView won't be a simple view, instead it will be a concrete class or an interface declaring drawBehindTopBar() and drawBelowTopBar(). This change will make the code readable and easier to understand since the user won't need see how the two methods are implemented, to understand what they are doing.
Now, the user needs to read both methods to understand what are these rules that we are adding and removing. It also means that OptionsPresenter makes assumptions on the view and knows it's a direct child of a RelativeLayout.

}
}

private void showTopBar(NavigationOptions.BooleanOptions animated) {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

showTopBar is a detail of TopBar.
OptionsPresenter should only call topBar.showAnimated or topBar.show


@SuppressLint("ViewConstructor")
public class ContainerLayout extends LinearLayout implements ReactContainer {
public class ContainerLayout extends RelativeLayout implements ReactContainer {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice 👍

this.reactView = reactView;
public ContainerLayout(Context context, IReactView reactView, EventDispatcher eventDispatcher) {
super(context);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the purpose of this empty line?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Easier to read. I mean, they belong to different views. And you can distinguish what relates to what


this.topBar = new TopBar(context, this, eventDispatcher);
topBar.setId(View.generateViewId());

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the purpose of this empty line?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same

addView(reactView.asView());
}
private void initViews() {
LayoutParams layoutParams = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

import MATCH_PARENT statically

addView(topTabs);
}

public void enableCollapse() {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we pull this logic into TopBarCollapser, then invoke topBarCollapser.enable()?

super(context);
topBar = new TopBar(context, this);
this.tabs = tabs;
topBar = new TopBar(context, this, null);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Avoid passing null, better to overload and pass null internally.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should open an issue to implement collapse in topTabs screen

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes

accelerateInterpolator = new AccelerateInterpolator();
}

public void animateShowTopBar(final TopBar topBar, final View contentView) {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both TopBar and contentView should be params of TopBarAnimator. This way you're end up with a class which exposes public commands that only accept variables that describe the command, like start translation and duration. This makes the code much easier to understand.

topbarAnim.start();
}

public void animateHideTopBar(final TopBar topBar, final View contentView) {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both params should be class members, and the function can be named to hide as we currently only animate the topBar.
topBarAnimator.animateHideTopBar -> topBarAnimator.hide() 👍

animateHideTopBar(topBar, contentView, 0, accelerateInterpolator, DURATION_TOPBAR);
}

public void animateHideTopBar(final TopBar topBar, final View container, float startTranslation, TimeInterpolator interpolator, int duration) {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change to private?

import com.reactnativenavigation.utils.UiThread;
import com.reactnativenavigation.views.TopBar;

public class TopbarCollapsingBehavior {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change tense to present.
TopBarCollapsingBehavior -> TopBarCollapseBehavior

this.animator = new TopBarAnimator();
}

public void enableCollapsing() {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

enableCollapsing -> enableCollapse

showTopBar(options.animateHide);
}
if (options.drawUnder == True) {
reactContainer.drawUnderTopBar();
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to rename under to behind. Apparently under can mean two things (depending on how you look at things) and behind means exactly what we mean - a view behind a view

}
}
private void showTopBar(NavigationOptions.BooleanOptions animated) {
topBar.show(animated, contentView);
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice! 👍


@Override
public void drawUnderTopBar() {
//TODO: implement later
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please avoid leaving TODO comments. Open an issue instead 👍

}

@Override
public void drawUnderTopBar() {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rename to drawBehindTopBar

private static final String TOP_BAR_FONT_FAMILY = "HelveticaNeue-CondensedBold";
private static final Typeface TOP_BAR_TYPEFACE = Typeface.create("HelveticaNeue-CondensedBold", Typeface.BOLD);
private static final NavigationOptions.BooleanOptions TOP_BAR_HIDDEN = True;
private static final NavigationOptions.BooleanOptions TOP_BAR_DRAW_UNDER = True;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rename to behind

guyca
guyca previously approved these changes Jan 9, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants