Skip to content
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
@@ -0,0 +1,60 @@
package com.reactnativenavigation

import androidx.annotation.VisibleForTesting

enum class RNNToggles {
TOP_BAR_COLOR_ANIMATION,
}

private val ToggleDefaults = mapOf(
RNNToggles.TOP_BAR_COLOR_ANIMATION to false
)

object RNNFeatureToggles {
private var init = false
private var toggles = mutableMapOf<RNNToggles, Boolean>()

@JvmStatic
fun init() {
assertNotInitialized()

init = true
toggles = ToggleDefaults.toMutableMap()
}

@JvmStatic
fun init(overrides: Map<RNNToggles, Boolean>) {
init()
this.toggles.putAll(overrides)
}

@JvmStatic
fun init(vararg overrides: Pair<RNNToggles, Boolean>) {
init(mapOf(*overrides))
}

@JvmStatic
fun isEnabled(toggleName: RNNToggles): Boolean {
assertInitialized()
return toggles.getOrElse(toggleName) { false }
}

@VisibleForTesting
@JvmStatic
fun clear() {
init = false
toggles.clear()
}

private fun assertNotInitialized() {
if (init) {
throw IllegalStateException("FeatureToggles already initialized")
}
}

private fun assertInitialized() {
if (!init) {
throw IllegalStateException("FeatureToggles not initialized")
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import com.reactnativenavigation.react.ReactGateway;
import com.reactnativenavigation.viewcontrollers.externalcomponent.ExternalComponentCreator;

import java.util.Collections;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
Expand All @@ -17,14 +18,23 @@

public abstract class NavigationApplication extends Application implements ReactApplication {

private ReactGateway reactGateway;
public static NavigationApplication instance;
final Map<String, ExternalComponentCreator> externalComponents = new HashMap<>();

private final Map<String, ExternalComponentCreator> externalComponents = new HashMap<>();
private ReactGateway reactGateway;

public NavigationApplication() {
this(Collections.emptyMap());
}

public NavigationApplication(Map<RNNToggles, Boolean> featureToggleOverrides) {
instance = this;
RNNFeatureToggles.init(featureToggleOverrides);
}

@Override
public void onCreate() {
super.onCreate();
instance = this;
try {
SoLoader.init(this, OpenSourceMergedSoMapping.INSTANCE);
} catch (IOException e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,9 @@ class ValueAnimationOptions {
to += this.to[animationValueAccessor!!(view)]
}
val animator = ObjectAnimator.ofFloat(view,
animProp,
from,
to
animProp,
from,
to
)
animator.interpolator = interpolator
if (duration.hasValue()) animator.duration = duration.get().toLong()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.reactnativenavigation.utils

import android.animation.Animator

open class StubAnimationListener: Animator.AnimatorListener {
override fun onAnimationStart(animation: Animator) {}
override fun onAnimationEnd(animation: Animator) {}
override fun onAnimationCancel(animation: Animator) {}
override fun onAnimationRepeat(animation: Animator) {}

companion object {
@JvmStatic
fun onAnimatorEnd(onEnd: (animation: Animator) -> Unit) = object: StubAnimationListener() {
override fun onAnimationEnd(animation: Animator) {
onEnd(animation)
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -121,19 +121,25 @@ object SystemUiUtils {
@ColorInt color: Int,
translucent: Boolean
) {
val opaqueColor = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
Color.BLACK
}else{
val colorAlpha = Color.alpha(color)
val alpha = if (translucent && colorAlpha == 255) STATUS_BAR_HEIGHT_TRANSLUCENCY else colorAlpha/255.0f
val red: Int = Color.red(color)
val green: Int = Color.green(color)
val blue: Int = Color.blue(color)
Color.argb(ceil(alpha * 255).toInt(), red, green, blue)
}
val opaqueColor =
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
Color.BLACK
} else {
val colorAlpha = Color.alpha(color)
val alpha = if (translucent && colorAlpha == 255) STATUS_BAR_HEIGHT_TRANSLUCENCY else colorAlpha/255.0f
val red: Int = Color.red(color)
val green: Int = Color.green(color)
val blue: Int = Color.blue(color)
Color.argb(ceil(alpha * 255).toInt(), red, green, blue)
}
window?.statusBarColor = opaqueColor
}

@JvmStatic
fun getStatusBarColor(window: Window?): Int? {
return window?.statusBarColor
}

@JvmStatic
fun hideStatusBar(window: Window?, view: View) {
window?.let {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package com.reactnativenavigation.viewcontrollers.bottomtabs

import com.reactnativenavigation.views.animations.BaseViewAnimator
import com.reactnativenavigation.views.animations.BaseViewAppearanceAnimator
import com.reactnativenavigation.views.bottomtabs.BottomTabs

class BottomTabsAnimator(view: BottomTabs? = null) : BaseViewAnimator<BottomTabs>(HideDirection.Down, view) {
class BottomTabsAnimator(view: BottomTabs? = null) : BaseViewAppearanceAnimator<BottomTabs>(HideDirection.Down, view) {
override fun onShowAnimationEnd() {
view.restoreBottomNavigation(false)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,23 @@

import android.app.Activity;
import android.content.res.Configuration;
import android.os.Build;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowInsets;

import androidx.annotation.CallSuper;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;

import com.reactnativenavigation.options.Options;
import com.reactnativenavigation.utils.LogKt;
import com.reactnativenavigation.viewcontrollers.parent.ParentController;
import com.reactnativenavigation.viewcontrollers.viewcontroller.Presenter;
import com.reactnativenavigation.viewcontrollers.viewcontroller.NoOpYellowBoxDelegate;
import com.reactnativenavigation.viewcontrollers.navigator.Navigator;
import com.reactnativenavigation.viewcontrollers.viewcontroller.NoOpYellowBoxDelegate;
import com.reactnativenavigation.viewcontrollers.viewcontroller.Presenter;
import com.reactnativenavigation.viewcontrollers.viewcontroller.ViewController;
import com.reactnativenavigation.viewcontrollers.viewcontroller.overlay.ViewControllerOverlay;
import com.reactnativenavigation.views.component.Component;

import androidx.annotation.CallSuper;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowCompat;
import androidx.core.view.WindowInsetsCompat;

public abstract class ChildController<T extends ViewGroup> extends ViewController<T> {
private final Presenter presenter;
protected final Presenter presenter;
private final ChildControllersRegistry childRegistry;

public ChildControllersRegistry getChildRegistry() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,28 +1,29 @@
package com.reactnativenavigation.viewcontrollers.component;

import static com.reactnativenavigation.utils.ObjectUtils.perform;

import android.animation.Animator;
import android.app.Activity;
import android.content.res.Configuration;
import android.view.View;

import com.reactnativenavigation.utils.LogKt;
import com.reactnativenavigation.viewcontrollers.viewcontroller.ScrollEventListener;
import com.reactnativenavigation.options.Options;
import com.reactnativenavigation.viewcontrollers.viewcontroller.Presenter;
import com.reactnativenavigation.utils.SystemUiUtils;
import com.reactnativenavigation.viewcontrollers.viewcontroller.ReactViewCreator;
import com.reactnativenavigation.viewcontrollers.child.ChildController;
import com.reactnativenavigation.viewcontrollers.child.ChildControllersRegistry;
import com.reactnativenavigation.viewcontrollers.viewcontroller.ViewController;
import com.reactnativenavigation.views.component.ComponentLayout;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;

import static com.reactnativenavigation.utils.ObjectUtils.perform;
import com.reactnativenavigation.options.Options;
import com.reactnativenavigation.utils.SystemUiUtils;
import com.reactnativenavigation.viewcontrollers.child.ChildController;
import com.reactnativenavigation.viewcontrollers.child.ChildControllersRegistry;
import com.reactnativenavigation.viewcontrollers.stack.statusbar.StatusBarController;
import com.reactnativenavigation.viewcontrollers.viewcontroller.Presenter;
import com.reactnativenavigation.viewcontrollers.viewcontroller.ReactViewCreator;
import com.reactnativenavigation.viewcontrollers.viewcontroller.ScrollEventListener;
import com.reactnativenavigation.views.component.ComponentLayout;

public class ComponentViewController extends ChildController<ComponentLayout> {
public class ComponentViewController extends ChildController<ComponentLayout> implements StatusBarController {
private final String componentName;
private final ComponentPresenter presenter;
private final ReactViewCreator viewCreator;
Expand Down Expand Up @@ -64,6 +65,29 @@ public void setDefaultOptions(Options defaultOptions) {
presenter.setDefaultOptions(defaultOptions);
}

@Override
public StatusBarController getStatusBarController() {
return this;
}

@Nullable
@Override
public Animator getStatusBarPushAnimation(@NonNull Options appearingOptions) {
if (super.presenter != null) {
return super.presenter.getStatusBarPushAnimation(appearingOptions);
}
return null;
}

@Nullable
@Override
public Animator getStatusBarPopAnimation(@NonNull Options appearingOptions, @NonNull Options disappearingOptions) {
if (super.presenter != null) {
return super.presenter.getStatusBarPopAnimation(appearingOptions, disappearingOptions);
}
return null;
}

@Override
public ScrollEventListener getScrollEventListener() {
return perform(view, null, ComponentLayout::getScrollEventListener);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -159,16 +159,19 @@ public void push(ViewController<?> child, CommandListener listener) {
listener.onError("A stack can't contain two children with the same id: " + child.getId());
return;
}
final ViewController<?> toRemove = stack.peek();
if (size() > 0) backButtonHelper.addToPushedChild(child);
child.setParentController(this);
stack.push(child.getId(), child);
if (!isViewCreated()) return;

final ViewController<?> toRemove = pushChildToStack(child);

if (!isViewCreated()) {
return;
}

Options resolvedOptions = resolveCurrentOptions(presenter.getDefaultOptions());
addChildToStack(child, resolvedOptions);
updateChildLayout(child, resolvedOptions);

if (toRemove != null) {
StackAnimationOptions animation = resolvedOptions.animations.push;
if (animation.enabled.isTrueOrUndefined()) {
StackAnimationOptions animOptions = resolvedOptions.animations.push;
if (animOptions.enabled.isTrueOrUndefined()) {
animator.push(
child,
toRemove,
Expand All @@ -195,7 +198,17 @@ private void onPushAnimationComplete(ViewController<?> toAdd, ViewController<?>
listener.onSuccess(toAdd.getId());
}

private void addChildToStack(ViewController<?> child, Options resolvedOptions) {
private ViewController<?> pushChildToStack(ViewController<?> child) {
final ViewController<?> toRemove = stack.peek();

if (size() > 0) backButtonHelper.addToPushedChild(child);

child.setParentController(this);
stack.push(child.getId(), child);
return toRemove;
}

private void updateChildLayout(ViewController<?> child, Options resolvedOptions) {
child.setWaitForRender(resolvedOptions.animations.push.waitForRender);
if (size() == 1) presenter.applyInitialChildLayoutOptions(resolvedOptions);
getView().addView(child.getView(), getView().getChildCount() - 1, matchParentWithBehaviour(new StackBehaviour(this)));
Expand All @@ -222,7 +235,7 @@ public void setRoot(@Size(min = 1) List<ViewController<?>> children, CommandList
child.setParentController(this);
stack.push(child.getId(), child);
Options resolvedOptions = resolveCurrentOptions(presenter.getDefaultOptions());
addChildToStack(child, resolvedOptions);
updateChildLayout(child, resolvedOptions);

CommandListener listenerAdapter = new CommandListenerAdapter() {
@Override
Expand Down Expand Up @@ -316,7 +329,7 @@ public void pop(Options mergeOptions, CommandListener listener) {
appearing,
disappearing,
disappearingOptions,
presenter.getAdditionalPopAnimations(appearingOptions, disappearingOptions),
presenter.getAdditionalPopAnimations(appearingOptions, disappearingOptions, appearing),
() -> finishPopping(appearing, disappearing, listener)
);
} else {
Expand Down
Loading