wix / react-native-navigation

A complete native navigation solution for React Native
https://wix.github.io/react-native-navigation/
MIT License
13.04k stars 2.67k forks source link

React Native 0.76.x #7915

Open ertugruldogan opened 2 months ago

ertugruldogan commented 2 months ago

7905 previous topic 0.75.x

The Solution for Android 0.76.1

react-native-navigation\lib\android\app\src\main\java\com\reactnativenavigation\utils\ReactTypefaceUtils.java

/*
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

// This file was copied over from react-native
// to provide backwards compatibility < rn 0.62
//
// TODO: Remove me and use com.facebook.react.views.text.ReactTypefaceUtils
// once we drop support for rn < 0.62

package com.reactnativenavigation.utils;

import android.content.res.AssetManager;
import android.graphics.Typeface;
import android.text.TextUtils;
import androidx.annotation.Nullable;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.views.text.ReactFontManager;
import com.facebook.react.common.ReactConstants;
import java.util.ArrayList;
import java.util.List;

public class ReactTypefaceUtils {
  public static final int UNSET = -1;

  public static int parseFontWeight(@Nullable String fontWeightString) {
    int fontWeightNumeric =
        fontWeightString != null ? parseNumericFontWeight(fontWeightString) : UNSET;
    int fontWeight = fontWeightNumeric != UNSET ? fontWeightNumeric : Typeface.NORMAL;

    if (fontWeight == 700 || "bold".equals(fontWeightString)) fontWeight = Typeface.BOLD;
    else if (fontWeight == 400 || "normal".equals(fontWeightString)) fontWeight = Typeface.NORMAL;

    return fontWeight;
  }

  public static int parseFontStyle(@Nullable String fontStyleString) {
    int fontStyle = UNSET;
    if ("italic".equals(fontStyleString)) {
      fontStyle = Typeface.ITALIC;
    } else if ("normal".equals(fontStyleString)) {
      fontStyle = Typeface.NORMAL;
    }

    return fontStyle;
  }

  public static @Nullable String parseFontVariant(@Nullable ReadableArray fontVariantArray) {
    if (fontVariantArray == null || fontVariantArray.size() == 0) {
      return null;
    }

    List<String> features = new ArrayList<>();
    for (int i = 0; i < fontVariantArray.size(); i++) {
      // see https://docs.microsoft.com/en-us/typography/opentype/spec/featurelist
      String fontVariant = fontVariantArray.getString(i);
      if (fontVariant != null) {
        switch (fontVariant) {
          case "small-caps":
            features.add("'smcp'");
            break;
          case "oldstyle-nums":
            features.add("'onum'");
            break;
          case "lining-nums":
            features.add("'lnum'");
            break;
          case "tabular-nums":
            features.add("'tnum'");
            break;
          case "proportional-nums":
            features.add("'pnum'");
            break;
        }
      }
    }

    return TextUtils.join(", ", features);
  }

  public static Typeface applyStyles(
      @Nullable Typeface typeface,
      int style,
      int weight,
      @Nullable String family,
      AssetManager assetManager) {
    int oldStyle;
    if (typeface == null) {
      oldStyle = 0;
    } else {
      oldStyle = typeface.getStyle();
    }

    int want = 0;
    if ((weight == Typeface.BOLD)
        || ((oldStyle & Typeface.BOLD) != 0 && weight == ReactConstants.UNSET)) {
      want |= Typeface.BOLD;
    }

    if ((style == Typeface.ITALIC)
        || ((oldStyle & Typeface.ITALIC) != 0 && style == ReactConstants.UNSET)) {
      want |= Typeface.ITALIC;
    }

    if (family != null) {
      typeface = ReactFontManager.getInstance().getTypeface(family, want, weight, assetManager);
    } else if (typeface != null) {
      // TODO(t9055065): Fix custom fonts getting applied to text children with different style
      typeface = Typeface.create(typeface, want);
    }

    if (typeface != null) {
      return typeface;
    } else {
      return Typeface.defaultFromStyle(want);
    }
  }

  /**
   * Return -1 if the input string is not a valid numeric fontWeight (100, 200, ..., 900), otherwise
   * return the weight.
   */
  private static int parseNumericFontWeight(String fontWeightString) {
    // This should be much faster than using regex to verify input and Integer.parseInt
    return fontWeightString.length() == 3
            && fontWeightString.endsWith("00")
            && fontWeightString.charAt(0) <= '9'
            && fontWeightString.charAt(0) >= '1'
        ? 100 * (fontWeightString.charAt(0) - '0')
        : UNSET;
  }
}

react-native-navigation\lib\android\app\src\main\java\com\reactnativenavigation\utils\ReactViewGroup.kt

package com.reactnativenavigation.utils

import com.facebook.react.views.view.ReactViewBackgroundDrawable
import com.facebook.react.views.view.ReactViewGroup

val ReactViewGroup.borderRadius: Float
    get() =  0f

react-native-navigation\lib\android\app\src\main\java\com\reactnativenavigation\viewcontrollers\viewcontroller\LayoutDirectionApplier.kt

package com.reactnativenavigation.viewcontrollers.viewcontroller

import com.facebook.react.ReactInstanceManager
import com.facebook.react.modules.i18nmanager.I18nUtil
import com.reactnativenavigation.options.Options
import com.facebook.react.bridge.ReactContext

class LayoutDirectionApplier {
    fun apply(root: ViewController<*>, options: Options, instanceManager: ReactInstanceManager) {
        // currentReactContext'in null olup olmadığını kontrol ediyoruz
        val reactContext = instanceManager.currentReactContext as? ReactContext
        if (options.layout.direction.hasValue() && reactContext != null) {
            root.activity.window.decorView.layoutDirection = options.layout.direction.get()
            I18nUtil.getInstance().allowRTL(reactContext, options.layout.direction.isRtl)
            I18nUtil.getInstance().forceRTL(reactContext, options.layout.direction.isRtl)
        }
    }
}

https://github.com/wix/react-native-navigation/issues/7930 Hermes Enabled: libhermes_executor.so Hermes Disabled: libjscexecutor.so troubleshooting your mistakes react-native-navigation\lib\android\app\src\main\java\com\reactnativenavigation\NavigationApplication.java

package com.reactnativenavigation;

import android.app.Application;

import com.facebook.react.ReactApplication;
import com.facebook.react.ReactNativeHost;
import com.facebook.soloader.SoLoader;
import com.facebook.react.soloader.OpenSourceMergedSoMapping;
import com.reactnativenavigation.react.ReactGateway;
import com.reactnativenavigation.viewcontrollers.externalcomponent.ExternalComponentCreator;

import java.util.HashMap;
import java.util.Map;

import androidx.annotation.NonNull;

public abstract class NavigationApplication extends Application implements ReactApplication {

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

    @Override
    public void onCreate() {
        super.onCreate();
        instance = this;
        try {
            SoLoader.init(this, OpenSourceMergedSoMapping.INSTANCE);
        } catch (Exception e) {
            e.printStackTrace();
        }
        reactGateway = createReactGateway();
    }

    /**
     * Subclasses of NavigationApplication may override this method to create the singleton instance
     * of {@link ReactGateway}. For example, subclasses may wish to provide a custom {@link ReactNativeHost}
     * with the ReactGateway. This method will be called exactly once, in the application's {@link #onCreate()} method.
     *
     * Custom {@link ReactNativeHost}s must be sure to include {@link com.reactnativenavigation.react.NavigationPackage}
     *
     * @return a singleton {@link ReactGateway}
     */
    protected ReactGateway createReactGateway() {
        return new ReactGateway(getReactNativeHost());
    }

    public ReactGateway getReactGateway() {
        return reactGateway;
    }

    /**
     * Generally no need to override this; override for custom permission handling.
     */
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {

    }

    /**
     * Register a native View which can be displayed using the given {@code name}
     * @param name Unique name used to register the native view
     * @param creator Used to create the view at runtime
     */
    @SuppressWarnings("unused")
    public void registerExternalComponent(String name, ExternalComponentCreator creator) {
        if (externalComponents.containsKey(name)) {
            throw new RuntimeException("A component has already been registered with this name: " + name);
        }
        externalComponents.put(name, creator);
    }

    public final Map<String, ExternalComponentCreator> getExternalComponents() {
        return externalComponents;
    }
}

react-native-navigation\lib\android\app\src\reactNative71\java\com\reactnativenavigation\react\modal\ModalContentLayout.kt

package com.reactnativenavigation.react.modal

import android.content.Context
import android.view.MotionEvent
import android.view.View
import com.facebook.react.bridge.*
import com.facebook.react.uimanager.*
import com.facebook.react.uimanager.events.EventDispatcher
import com.facebook.react.views.view.ReactViewGroup

class ModalContentLayout(context: Context?) : ReactViewGroup(context), RootView {
    private var hasAdjustedSize = false
    private var viewWidth = 0
    private var viewHeight = 0
    private val mJSTouchDispatcher = JSTouchDispatcher(this)

    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
        super.onSizeChanged(w, h, oldw, oldh)
        viewWidth = w
        viewHeight = h
        this.updateFirstChildView()
    }

    private fun updateFirstChildView() {
        if (this.childCount > 0) {
            hasAdjustedSize = false
            val viewTag = getChildAt(0).id
            val reactContext: ReactContext = this.getReactContext()
            reactContext.runOnNativeModulesQueueThread(object : GuardedRunnable(reactContext) {
                override fun runGuarded() {
                    val uiManager = this@ModalContentLayout.getReactContext().getNativeModule(
                        UIManagerModule::class.java
                    ) as UIManagerModule
                    uiManager.updateNodeSize(
                        viewTag,
                        this@ModalContentLayout.viewWidth,
                        this@ModalContentLayout.viewHeight
                    )
                }
            })
        } else {
            hasAdjustedSize = true
        }
    }

    override fun addView(child: View?, index: Int, params: LayoutParams?) {
        super.addView(child, index, params)
        if (hasAdjustedSize) {
            updateFirstChildView()
        }
    }

    override fun onChildStartedNativeGesture(child: View, androidEvent: MotionEvent?) {
        androidEvent?.let {
            mJSTouchDispatcher.onChildStartedNativeGesture(it, this.getEventDispatcher()!!)
        }
    }

    override fun onChildStartedNativeGesture(androidEvent: MotionEvent?) {
        androidEvent?.let {
            mJSTouchDispatcher.onChildStartedNativeGesture(it, this.getEventDispatcher()!!)
        }
    }

    override fun onChildEndedNativeGesture(child: View, androidEvent: MotionEvent?) {
        androidEvent?.let {
            mJSTouchDispatcher.onChildEndedNativeGesture(it, this.getEventDispatcher()!!)
        }
    }

    override fun requestDisallowInterceptTouchEvent(disallowIntercept: Boolean) {}

    private fun getEventDispatcher(): EventDispatcher? {
        val reactContext: ReactContext = this.getReactContext()
        return reactContext.getNativeModule(UIManagerModule::class.java)?.eventDispatcher
    }

    override fun handleException(t: Throwable?) {
        getReactContext().handleException(RuntimeException(t))
    }

    private fun getReactContext(): ReactContext {
        return this.context as ReactContext
    }

    override fun onInterceptTouchEvent(event: MotionEvent?): Boolean {
        event?.let {
            mJSTouchDispatcher.handleTouchEvent(it, getEventDispatcher()!!)
        }
        return super.onInterceptTouchEvent(event)
    }

    override fun onTouchEvent(event: MotionEvent?): Boolean {
        event?.let {
            mJSTouchDispatcher.handleTouchEvent(it, getEventDispatcher()!!)
        }
        super.onTouchEvent(event)
        return true
    }
}

react-native: 0.76.1 react-native-navigation: 7.40.3 java: 17 node: 22.5.1 gradle: 8.10 buildToolsVersion = "35.0.0" minSdkVersion = 24 (https://github.com/react-native-community/discussions-and-proposals/discussions/802) compileSdkVersion = 35 targetSdkVersion = 35 ndkVersion = "27.0.12077973" kotlinVersion = "2.0.20"

android\gradle.properties newArchEnabled=false RN 0.76.x by default, it comes true. hermesEnabled=true

It has only been tested for Android.

### Tasks
- [ ] https://github.com/wix/react-native-navigation/issues/7905
gusilveiramp commented 1 month ago

+1

gusilveiramp commented 1 month ago

@ertugruldogan any solution?

ertugruldogan commented 1 month ago

RN v0.76.1 or v0.76.2 I can get it resolved. React Native 0.75.x there may be problems, including. It seems as if React-Native-Navigation support is little sought after by the community.

MohamedAbdElNaby commented 4 weeks ago

@ertugruldogan are you solve RN V0.76.0 i upgrade from 0.75.4 to 0.76.0 the app crashed when i run it

ertugruldogan commented 4 weeks ago

@ertugruldogan are you solve RN V0.76.0 i upgrade from 0.75.4 to 0.76.0 the app crashed when i run it

Not only react-native-navigation library but also many other libraries are currently incompatible. Error details are needed. I suggest you wait for 0.76.1 and 0.76.2.

MohamedAbdElNaby commented 4 weeks ago

@ertugruldogan ok thank you

MohamedAbdElNaby commented 2 weeks ago

@ertugruldogan I'm reaching out to check if there have been any updates or changes regarding my issue?!

enahum commented 1 week ago

Any updatrs? And are you looking into enabling the new arch now that is the default?

MohamedAbdElNaby commented 1 week ago

this work with new arch for android but ios dosnt work with me

ertugruldogan commented 1 week ago

The Solution for Android 0.76.1 It has been updated.

MohamedAbdElNaby commented 1 week ago

ertugruldogan any updates for ios ?