Skip to content

Commit

Permalink
Set stack root refactor (#4460)
Browse files Browse the repository at this point in the history
This PR adds support for setting stack root with multiple children, which is to be expected as stack can be initialised with multiple children.
Closes #4441
  • Loading branch information
guyca authored Dec 17, 2018
1 parent 62f6dba commit 2365e02
Show file tree
Hide file tree
Showing 21 changed files with 247 additions and 100 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.WritableMap;
import com.reactnativenavigation.NavigationActivity;
Expand All @@ -27,6 +28,7 @@
import com.reactnativenavigation.viewcontrollers.externalcomponent.ExternalComponentCreator;
import com.reactnativenavigation.viewcontrollers.navigator.Navigator;

import java.util.ArrayList;
import java.util.Map;

public class NavigationModule extends ReactContextBaseJavaModule {
Expand Down Expand Up @@ -89,11 +91,14 @@ public void push(String commandId, String onComponentId, ReadableMap rawLayoutTr
}

@ReactMethod
public void setStackRoot(String commandId, String onComponentId, ReadableMap rawLayoutTree, Promise promise) {
final LayoutNode layoutTree = LayoutNodeParser.parse(JSONParser.parse(rawLayoutTree));
public void setStackRoot(String commandId, String onComponentId, ReadableArray children, Promise promise) {
handle(() -> {
final ViewController viewController = newLayoutFactory().create(layoutTree);
navigator().setStackRoot(onComponentId, viewController, new NativeCommandListener(commandId, promise, eventEmitter, now));
ArrayList<ViewController> _children = new ArrayList();
for (int i = 0; i < children.size(); i++) {
final LayoutNode layoutTree = LayoutNodeParser.parse(JSONParser.parse(children.getMap(i)));
_children.add(newLayoutFactory().create(layoutTree));
}
navigator().setStackRoot(onComponentId, _children, new NativeCommandListener(commandId, promise, eventEmitter, now));
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,14 @@ public static <T> void forEach(@Nullable Collection<T> items, Apply<T> apply) {
return null;
}

public static <T> T last(@Nullable List<T> items) {
return CollectionUtils.isNullOrEmpty(items) ? null : items.get(items.size() - 1);
}

public static <T> T removeLast(@NonNull List<T> items) {
return items.remove(items.size() - 1);
}

private static @NonNull <T> Collection<T> get(@Nullable Collection<T> t) {
return t == null ? Collections.EMPTY_LIST : t;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,33 +4,42 @@

import com.reactnativenavigation.utils.StringUtils;

import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import static com.reactnativenavigation.utils.CollectionUtils.last;
import static com.reactnativenavigation.utils.CollectionUtils.removeLast;

public class IdStack<E> implements Iterable<String> {

private final ArrayDeque<String> deque = new ArrayDeque<>();
private final HashMap<String, E> map = new HashMap<>();
private final ArrayList<String> deque = new ArrayList();
private final Map<String, E> map = new HashMap<>();

public void push(String id, E item) {
deque.push(id);
deque.add(id);
map.put(id, item);
}

public void set(String id, E item, int index) {
deque.add(index, id);
map.put(id, item);
}

public E peek() {
if (isEmpty()) {
return null;
}
return map.get(deque.peek());
return map.get(last(deque));
}

public E pop() {
if (isEmpty()) {
return null;
}
return map.remove(deque.pop());
return map.remove(removeLast(deque));
}

public boolean isEmpty() {
Expand All @@ -42,7 +51,7 @@ public int size() {
}

public String peekId() {
return deque.peek();
return last(deque);
}

public void clear() {
Expand All @@ -54,6 +63,10 @@ public E get(final String id) {
return map.get(id);
}

public E get(final int index) {
return map.get(deque.get(index));
}

public boolean containsId(final String id) {
return deque.contains(id);
}
Expand All @@ -80,4 +93,9 @@ public Iterator<String> iterator() {
public Collection<E> values() {
return map.values();
}

public void remove(Iterator<String> iterator, String id) {
iterator.remove();
map.remove(id);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
import android.widget.FrameLayout;

import com.reactnativenavigation.parse.Options;
import com.reactnativenavigation.presentation.Presenter;
import com.reactnativenavigation.presentation.OverlayManager;
import com.reactnativenavigation.presentation.Presenter;
import com.reactnativenavigation.react.EventEmitter;
import com.reactnativenavigation.utils.CommandListener;
import com.reactnativenavigation.utils.CompatUtils;
Expand All @@ -22,6 +22,7 @@

import java.util.Collection;
import java.util.Collections;
import java.util.List;

public class Navigator extends ParentController {

Expand Down Expand Up @@ -148,8 +149,8 @@ public void push(final String id, final ViewController viewController, CommandLi
applyOnStack(id, listener, stack -> stack.push(viewController, listener));
}

public void setStackRoot(String id, ViewController viewController, CommandListener listener) {
applyOnStack(id, listener, stack -> stack.setRoot(viewController, listener));
public void setStackRoot(String id, List<ViewController> children, CommandListener listener) {
applyOnStack(id, listener, stack -> stack.setRoot(children, listener));
}

public void pop(String id, Options mergeOptions, CommandListener listener) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import com.reactnativenavigation.presentation.Presenter;
import com.reactnativenavigation.presentation.StackPresenter;
import com.reactnativenavigation.react.Constants;
import com.reactnativenavigation.utils.CollectionUtils;
import com.reactnativenavigation.utils.CommandListener;
import com.reactnativenavigation.utils.CommandListenerAdapter;
import com.reactnativenavigation.viewcontrollers.ChildControllersRegistry;
Expand Down Expand Up @@ -183,23 +184,43 @@ private void addChildToStack(ViewController child, View view, Options resolvedOp
getView().addView(view, getView().getChildCount() - 1);
}

public void setRoot(ViewController child, CommandListener listener) {
backButtonHelper.clear(child);
push(child, new CommandListenerAdapter() {
@Override
public void onSuccess(String childId) {
removeChildrenBellowTop();
listener.onSuccess(childId);
}
});
public void setRoot(List<ViewController> children, CommandListener listener) {
if (children.size() == 1) {
backButtonHelper.clear(CollectionUtils.last(children));
push(CollectionUtils.last(children), new CommandListenerAdapter() {
@Override
public void onSuccess(String childId) {
removeChildrenBellowTop();
listener.onSuccess(childId);
}
});
} else {
push(CollectionUtils.last(children), new CommandListenerAdapter() {
@Override
public void onSuccess(String childId) {
removeChildrenBellowTop();
for (int i = 0; i < children.size() - 1; i++) {
stack.set(children.get(i).getId(), children.get(i), i);
children.get(i).setParentController(StackController.this);
if (i == 0) {
backButtonHelper.clear(children.get(i));
} else {
backButtonHelper.addToPushedChild(children.get(i));
}
}
listener.onSuccess(childId);
}
});
}
}

private void removeChildrenBellowTop() {
Iterator<String> iterator = stack.iterator();
while (stack.size() > 1) {
ViewController controller = stack.get(iterator.next());
if (!stack.isTop(controller.getId())) {
removeAndDestroyController(controller);
stack.remove(iterator, controller.getId());
controller.destroy();
}
}
}
Expand Down Expand Up @@ -247,15 +268,17 @@ public void popTo(ViewController viewController, Options mergeOptions, CommandLi
return;
}

Iterator<String> iterator = stack.iterator();
String currentControlId = iterator.next();
while (!viewController.getId().equals(currentControlId)) {
if (stack.isTop(currentControlId)) {
currentControlId = iterator.next();
continue;

String currentControlId;
for (int i = stack.size() - 2; i >= 0; i--) {
currentControlId = stack.get(i).getId();
if (currentControlId.equals(viewController.getId())) {
break;
}
removeAndDestroyController(stack.get(currentControlId));
currentControlId = iterator.next();

ViewController controller = stack.get(currentControlId);
stack.remove(controller.getId());
controller.destroy();
}

pop(mergeOptions, listener);
Expand All @@ -268,10 +291,12 @@ public void popToRoot(Options mergeOptions, CommandListener listener) {
}

Iterator<String> iterator = stack.iterator();
iterator.next();
while (stack.size() > 2) {
ViewController controller = stack.get(iterator.next());
if (!stack.isTop(controller.getId())) {
removeAndDestroyController(controller);
stack.remove(iterator, controller.getId());
controller.destroy();
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,67 +17,67 @@ public void beforeEach() {
}

@Test
public void isEmpty() throws Exception {
public void isEmpty() {
assertThat(uut.isEmpty()).isTrue();
uut.push("123", 123);
assertThat(uut.isEmpty()).isFalse();
}

@Test
public void size() throws Exception {
public void size() {
assertThat(uut.size()).isEqualTo(0);
uut.push("123", 123);
assertThat(uut.size()).isEqualTo(1);
}

@Test
public void peek() throws Exception {
public void peek() {
assertThat(uut.peek()).isNull();
uut.push("123", 123);
uut.push("456", 456);
assertThat(uut.peek()).isEqualTo(456);
}

@Test
public void pop() throws Exception {
public void pop() {
assertThat(uut.pop()).isNull();
uut.push("123", 123);
uut.push("456", 456);
assertThat(uut.pop()).isEqualTo(456);
}

@Test
public void peekId() throws Exception {
public void peekId() {
assertThat(uut.peekId()).isNull();
uut.push("123", 123);
assertThat(uut.peekId()).isEqualTo("123");
}

@Test
public void clear() throws Exception {
public void clear() {
uut.push("123", 123);
uut.push("456", 456);
uut.clear();
assertThat(uut.isEmpty()).isTrue();
}

@Test
public void getById() throws Exception {
public void getById() {
assertThat(uut.get("123")).isNull();
uut.push("123", 123);
uut.push("456", 456);
assertThat(uut.get("123")).isEqualTo(123);
}

@Test
public void containsId() throws Exception {
public void containsId() {
assertThat(uut.containsId("123")).isFalse();
uut.push("123", 123);
assertThat(uut.containsId("123")).isTrue();
}

@Test
public void remove() throws Exception {
public void remove() {
assertThat(uut.remove("123")).isNull();

uut.push("123", 123);
Expand All @@ -87,16 +87,16 @@ public void remove() throws Exception {
}

@Test
public void iterableIds() throws Exception {
public void iterableIds() {
assertThat(uut).isInstanceOf(Iterable.class);
assertThat(uut).isEmpty();
uut.push("123", 123);
uut.push("456", 456);
assertThat(uut).containsExactly("456", "123");
assertThat(uut).containsExactly("123", "456");
}

@Test
public void isTop() throws Exception {
public void isTop() {
assertThat(uut.isTop("123")).isFalse();
uut.push("123", 123);
assertThat(uut.isTop("123")).isTrue();
Expand All @@ -105,7 +105,7 @@ public void isTop() throws Exception {
}

@Test
public void values() throws Exception {
public void values() {
assertThat(uut.values()).isNotNull().isEmpty();
uut.push("123", 123);
uut.push("456", 456);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
import org.robolectric.annotation.Config;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import static org.assertj.core.api.Java6Assertions.assertThat;
Expand Down Expand Up @@ -301,7 +302,7 @@ public void setStackRoot() {

stack.push(child1, new CommandListenerAdapter());
stack.push(child2, new CommandListenerAdapter());
stack.setRoot(child3, new CommandListenerAdapter());
stack.setRoot(Collections.singletonList(child3), new CommandListenerAdapter());

assertThat(stack.getChildControllers()).containsOnly(child3);
}
Expand Down
Loading

0 comments on commit 2365e02

Please sign in to comment.