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

Added popToTop functionality #450

Closed
wants to merge 1 commit into from
Closed
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
1 change: 1 addition & 0 deletions src/Actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export const PUSH_ACTION = "push";
export const REPLACE_ACTION = "replace";
export const POP_ACTION2 = "back";
export const POP_ACTION = "BackAction";
export const POP_TO_TOP = 'popToTop';
export const REFRESH_ACTION = "refresh";
export const RESET_ACTION = "reset";
export const INIT_ACTION = "init";
Expand Down
8 changes: 7 additions & 1 deletion src/Reducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
*
*/

import {PUSH_ACTION, POP_ACTION2, FOCUS_ACTION, JUMP_ACTION, INIT_ACTION, REPLACE_ACTION, RESET_ACTION, POP_ACTION, REFRESH_ACTION} from "./Actions";
import {PUSH_ACTION, POP_ACTION2, POP_TO_TOP, FOCUS_ACTION, JUMP_ACTION, INIT_ACTION, REPLACE_ACTION, RESET_ACTION, POP_ACTION, REFRESH_ACTION} from "./Actions";
import assert from "assert";
import Immutable from "immutable";
import {getInitialState} from "./State";
Expand Down Expand Up @@ -48,6 +48,11 @@ function inject(state, action, props, scenes) {
case POP_ACTION:
assert(!state.tabs, "pop() operation cannot be run on tab bar (tabs=true)")
return {...state, index:state.index-1, children:state.children.slice(0, -1) };
case POP_TO_TOP:
assert(state.tabs, "Parent="+state.key+" is not tab bar, popToTop action is not valid");
let child = state.children[state.index];
let newChild = {...child, ...{children: [child.children[0]], index:0}};
return {...state, ...{children:[...state.children.slice(0,state.index), newChild, ...state.children.slice(state.index+1)]}};
Copy link
Owner

Choose a reason for hiding this comment

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

state.index should always be last element for children, right? Why you don't return just newChild there?

Copy link
Author

Choose a reason for hiding this comment

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

Because the tabBar disappears when I do that. I've tested it with 3.2.5. The state that is provided to the method is that of the tabBar.

Copy link
Owner

Choose a reason for hiding this comment

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

But popToTop should not be called for TabBar, i believe (like pop, it doesn't have any sense)

Copy link
Author

Choose a reason for hiding this comment

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

In my case I need it for the tab bar. The behaviour is based off the apple app store. Tapping the tab on which you already are is back to root of the tab. Is there a cleaner way to implement this? I could put it in the reducer of course but I thought it was a nice addition to the actions.

Copy link
Owner

Choose a reason for hiding this comment

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

Oh, i see now. Does it work for stack too?

Copy link
Author

Choose a reason for hiding this comment

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

Wouldnt that mean I'd have to hardcode it for each of my tabs? I have not named my tabs as in the example, seemed arbitrary? Is the naming convention important here?

This is my router code with a small set of views in there.

 return <Router createReducer={reducerCreate} store={store}>
      <Scene key="tabBar" tabs={true} tabBarStyle={{backgroundColor:colors.menuBackground.h}}>
        <Scene key="overview" title="Overview" icon={TabIcon} iconString="ios-color-filter-outline" navigationBarStyle={{backgroundColor:colors.menuBackground.h}} titleStyle={{color:'white'}} renderBackButton={backButtonFunction}>
          <Scene key="groupOverview" component={GroupOverview} title="Group Overview" />
          <Scene key="roomOverview"  component={RoomOverview} onRight={onRightFunctionEdit} rightTitle="Edit" rightButtonTextStyle={{color:'white'}} />
          <Scene key="roomEdit"      component={RoomEdit} title="Edit Room" />
          <Scene key="deviceEdit"    component={DeviceEdit} title="Edit Device" />
        </Scene>
        <Scene key="settings" title="Settings" icon={TabIcon} iconString="ios-gear-outline" navigationBarStyle={{backgroundColor:colors.menuBackground.h}} titleStyle={{color:'white'}} renderBackButton={backButtonFunction}>
          <Scene key="Settings" component={SettingsOverview} title="Settings"/>
        </Scene>
      </Scene>
    </Router>;

Whenever I refer to specific scenes inside the tabs, the tabbar disappears.

If I have to hardcode the action key in the reducer for each of my tabs it seems a bit more sloppy than using the index of the state?

Copy link
Owner

Choose a reason for hiding this comment

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

So if you set type='reset' for groupOverview and then call Actions.groupOverview() when user clicked on tab, will it work?

Copy link
Author

Choose a reason for hiding this comment

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

It works dynamically if I change the reducer like this:

const reducerCreate = params=> {
  const defaultReducer = Reducer(params);
  return (state, action)=>{
    if (state) {
      let currentTabIndex = state.index;
      if (state.children[currentTabIndex].name === action.key && action.type === 'jump') {
        return defaultReducer(state, {key: state.children[currentTabIndex].children[0].name, type:'reset'})
      }
    }
    return defaultReducer(state, action);
  }
};

I guess thats less code than my proposal :)

EDIT: fixed small bug

Copy link
Owner

Choose a reason for hiding this comment

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

Maybe you could propose PR based on it? For cases when first child has type 'reset'...

Copy link
Author

Choose a reason for hiding this comment

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

I'm not sure how that would look for a general case.. I have no type reset on the child, its being forced into the reducer at the moment. It could be the default behaviour of the tabs since it's also done that way in iOS while Android doesnt use tabs..

case REFRESH_ACTION:
return {...state, ...props};
case PUSH_ACTION:
Expand Down Expand Up @@ -152,6 +157,7 @@ function reducer({initialState, scenes}){
switch (action.type) {
case POP_ACTION2:
case POP_ACTION:
case POP_TO_TOP:
case REFRESH_ACTION:
case PUSH_ACTION:
case JUMP_ACTION:
Expand Down