diff --git a/README.md b/README.md index 8546fd05..e8528643 100644 --- a/README.md +++ b/README.md @@ -9,105 +9,51 @@ # MagicScript Components ReactNative +## Prerequisites -### Create a project - -The instruction assumes that you have the following tools installed and you have set environment variables properly: -- npm or yarn -- react-native-cli - -**Steps:** - -1. Create a new project: -`react-native init AwesomeProject --version 0.60.5` -2. Go to the project directory -3. Add Magic Script Components ReactNative library to the project: - `yarn add magic-script-components-react-native` -4. Add Magic Script Components library to the project: - `yarn add magic-script-components` -5. Execute `react-native link` in order to link the libraries, -6. In the main project directory add `proxy_mobile` folder from [https://github.com/magic-script/magic-script-components-catalog](https://github.com/magic-script/magic-script-components-catalog/tree/master/) - - -### Pre-configuration for Android - -The instruction assumes that you have the following tools installed and you have set environment variables properly: -- npm or yarn -- react-native-cli -- Android Studio (or a standalone Android SDK) -- Java JDK - -**Steps:** - -1. In the `./android/build.gradle` file set `minSdkVersion` to 24 -2. Open `android/app/src/main/AndroidManifest.xml` file and add the following **between** the `` tags: - - - ``` - - ``` - - Add the permission to use the Camera: - `` - - And optionally this **above** the `` tag: - `` - - *This tag indicates that this application requires ARCore. This results in the application -only being visible in the Google Play Store on devices that support ARCore) - - You can compare your AndroidManifest file with [this one](https://github.com/magic-script/magic-script-components-catalog/blob/master/android/app/src/main/AndroidManifest.xml) - -### Pre-configuration for iOS - -The instruction assumes that you have the following tools installed and you have set environment variables properly: -- npm or yarn -- react-native-cli -- XCode version > 10 -- CocoaPods version > 1.7.5 - -1. Create Empty.swift file inside project and `Create bridging header file` -2. In Podfile file update `platform :ios, ‘9.0’` to `platform :ios, ‘12.0’` -3. Declare `Privacy - Camera Usage Description` in Info.plist -4. Declare `Privacy - Location When In Use Usage Description` in Info.plist -5. Open terminal, navigate to `./ios` directory and execute `pod install` in order to install necessary Pods - -### General pre-configuration & project building - -**Steps** -1. Run `yarn` or `npm install` to install the dependencies -2. Replace App.js content with the following: - ``` - import React from 'react'; - import { View, Text } from 'magic-script-components'; - - class MyApp extends React.Component { - render() { - return ( - - Welcome in AR! - - ); - } - } - export default MyApp - - ``` -3. Replace `index.js` content with the following: - ``` - import React from 'react'; - import { MagicScript } from './proxy_mobile'; - import MyApp from './App'; - - MagicScript.registerApp('AwesomeProject', , false); - - ``` -4. In order to build & install the application on Android or iOS device, execute one of the following in root directory: - - `react-native run-android` - or - `react-native run-ios` +Make sure you have: + +- properly set up an environment for **React Native** (see [React Native CLI Quickstart](https://reactnative.dev/docs/environment-setup) for iOS|Android), + +- installed either [yarn](https://classic.yarnpkg.com/en/docs/install/) or [npm](https://www.npmjs.com/get-npm), + +- installed [MagicScript Command Line Toolkit](https://github.com/magic-script/magic-script-cli): + +``` +npm install -g magic-script-cli +``` + +

 

+ +## Create a react native project + +To create a sample project, type the command below and follow instructions in the wizard. +``` +magic-script init +```` + +Remember to select: +- **Components** app, +- **Landscape** app type, +- **iOS** or **Android** platform. + + + +## Build and run the project + +1. Move to the root directory of the project + +``` +cd AwesomeProject +``` + +2. To build and run the project, type: +``` +magic-script build ios +``` +or +``` +magic-script build android +``` + +This will build the app for the specified platform and will try to run in on a local emulator. diff --git a/ios/RNMagicScript.xcodeproj/project.pbxproj b/ios/RNMagicScript.xcodeproj/project.pbxproj index 8e563e14..112e16ec 100644 --- a/ios/RNMagicScript.xcodeproj/project.pbxproj +++ b/ios/RNMagicScript.xcodeproj/project.pbxproj @@ -2048,7 +2048,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 1030; - LastUpgradeCheck = 1020; + LastUpgradeCheck = 1210; ORGANIZATIONNAME = MagicLeap; TargetAttributes = { 44318E8E22CB4E0C0060575D = { @@ -3068,6 +3068,7 @@ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; @@ -3127,6 +3128,7 @@ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; diff --git a/ios/RNMagicScript.xcodeproj/xcshareddata/xcschemes/RNMagicScript.xcscheme b/ios/RNMagicScript.xcodeproj/xcshareddata/xcschemes/RNMagicScript.xcscheme index 39fdc2a7..994e3c0c 100644 --- a/ios/RNMagicScript.xcodeproj/xcshareddata/xcschemes/RNMagicScript.xcscheme +++ b/ios/RNMagicScript.xcodeproj/xcshareddata/xcschemes/RNMagicScript.xcscheme @@ -1,6 +1,6 @@ - - - - + + - - - - - - ARSCNView { - let view = ARSCNView() + + var options: [String : Any] = [:] + #if targetEnvironment(simulator) + options[SCNView.Option.preferredRenderingAPI.rawValue] = NSNumber(value: SCNRenderingAPI.openGLES2.rawValue) + #endif + + let view = ARSCNView(frame: CGRect.zero, options: options) + #if targetEnvironment(simulator) + view.scene = SCNScene() + #endif view.autoenablesDefaultLighting = true view.automaticallyUpdatesLighting = true view.backgroundColor = UIColor(white: 55.0 / 255.0, alpha: 1.0) diff --git a/ios/RNMagicScript/components/BaseNodes/Prism/PrismContextMenu.swift b/ios/RNMagicScript/components/BaseNodes/Prism/PrismContextMenu.swift index 18a8e540..9f9cf0fd 100644 --- a/ios/RNMagicScript/components/BaseNodes/Prism/PrismContextMenu.swift +++ b/ios/RNMagicScript/components/BaseNodes/Prism/PrismContextMenu.swift @@ -28,10 +28,12 @@ struct PrismContextMenuBuilder { class PrismContextMenu: UiNode { var text: String = "" { didSet { - titleNode.text = text - titleNode.layoutIfNeeded() - setNeedsLayout() - updateLayout() + if titleNode.text != text { + titleNode.text = text + titleNode.layoutIfNeeded() + setNeedsLayout() + updateLayout() + } } } diff --git a/ios/RNMagicScript/components/Utils/Extensions/UIFont+Lomino.swift b/ios/RNMagicScript/components/Utils/Extensions/UIFont+Lomino.swift index 0dbb7b1e..48b0cd60 100644 --- a/ios/RNMagicScript/components/Utils/Extensions/UIFont+Lomino.swift +++ b/ios/RNMagicScript/components/Utils/Extensions/UIFont+Lomino.swift @@ -19,29 +19,29 @@ import UIKit extension UIFont { public static func font(with style: FontStyle, weight: FontWeight, size: CGFloat) -> UIFont { - let name: String = UIFont.fontName(from: style, weight: weight) - guard let font = UIFont(name: name, size: size) else { - // return system font in case Lomino font not installed - let systemFont = UIFont.systemFont(ofSize: size, weight: UIFont.UIFontWeight(from: weight)) - if style == .italic { - return systemFont.with(traits: .traitItalic) - } - - return systemFont + // Check Lomino font first + let name: String = UIFont.lominoFontName(from: style, weight: weight) + if let font = UIFont(name: name, size: size) { + return font } - return font - } - - public func with(traits: UIFontDescriptor.SymbolicTraits) -> UIFont { - guard let descriptor = fontDescriptor.withSymbolicTraits(traits) else { - return self + // Perform extra check for iOS 14 as there is an issue with system font + // (more info: https://stackoverflow.com/questions/64448087/missing-characters-in-scntext-ios-14) + if #available(iOS 14.0, *) { + let systemFontName: String = UIFont.avenirNextFontName(from: style, weight: weight) + return UIFont(name: systemFontName, size: size)! } - - return UIFont(descriptor: descriptor, size: 0) + + // Then use system font + let systemFont: UIFont = UIFont.systemFont(ofSize: size, weight: UIFont.UIFontWeight(from: weight)) + if style == .italic { + return systemFont.with(traits: .traitItalic) + } + + return systemFont } - fileprivate static func fontName(from style: FontStyle, weight: FontWeight) -> String { + fileprivate static func lominoFontName(from style: FontStyle, weight: FontWeight) -> String { switch weight { case .extraLight: return (style == .normal) ? "LominoUIApp-Light" : "LominoUIApp-LightItalic" @@ -57,6 +57,23 @@ extension UIFont { return (style == .normal) ? "LominoUIApp-ExtraBold" : "LominoUIApp-ExtraBoldItalic" } } + + fileprivate static func avenirNextFontName(from style: FontStyle, weight: FontWeight) -> String { + switch weight { + case .extraLight: + return (style == .normal) ? "AvenirNext-UltraLight" : "AvenirNext-UltraLightItalic" + case .light: + return (style == .normal) ? "AvenirNext-UltraLight" : "AvenirNext-UltraLightItalic" + case .regular: + return (style == .normal) ? "AvenirNext-Regular" : "AvenirNext-Italic" + case .medium: + return (style == .normal) ? "AvenirNext-Medium" : "AvenirNext-MediumItalic" + case .bold: + return (style == .normal) ? "AvenirNext-Bold" : "AvenirNext-BoldItalic" + case .extraBold: + return (style == .normal) ? "AvenirNext-Heavy" : "AvenirNext-HeavyItalic" + } + } public static func UIFontWeight(from weight: FontWeight) -> UIFont.Weight { switch weight { @@ -75,3 +92,14 @@ extension UIFont { } } } + +// MARK: - Traits +extension UIFont { + public func with(traits: UIFontDescriptor.SymbolicTraits) -> UIFont { + guard let descriptor = fontDescriptor.withSymbolicTraits(traits) else { + return self + } + + return UIFont(descriptor: descriptor, size: 0) + } +} diff --git a/ios/RNMagicScriptHostApplication/sources/ViewController.swift b/ios/RNMagicScriptHostApplication/sources/ViewController.swift index 82f4552d..f47d3a64 100644 --- a/ios/RNMagicScriptHostApplication/sources/ViewController.swift +++ b/ios/RNMagicScriptHostApplication/sources/ViewController.swift @@ -34,9 +34,10 @@ class ViewController: UIViewController { super.viewDidLoad() setupScene() - // setupPrismWithModels() - // setupPrismForHitTest() - setupPrismForDialog() +// setupPrismWithModels() +// setupPrismForHitTest() +// setupPrismForDialog() + setupPrismForFontTest() setupARView() arView.register(self) @@ -106,7 +107,6 @@ class ViewController: UIViewController { NodesManager.instance.updateLayout() } - fileprivate func setupPrismForHitTest() { let prismId = "prism_hit_test" let prism: Prism = Prism() @@ -235,6 +235,35 @@ class ViewController: UIViewController { NodesManager.instance.updateLayout() } + fileprivate func setupPrismForFontTest() { + let prismId = "prism_hit_test" + let prism: Prism = Prism() + prism.size = SCNVector3(1.0, 1.0, 1.0) + prism.debug = true + + NodesManager.instance.registerPrism(prism, prismId: prismId) + NodesManager.instance.addNode(prismId, toParent: sceneId) + + let styles: [FontStyle] = [.normal, .italic] + let weights: [FontWeight] = [.extraLight, .light, .regular, .medium, .bold, .extraBold] + + for style in styles { + let y: Float = (style == .normal) ? 0.3 : -0.1 + for (index, weight) in weights.enumerated() { + let text : UiTextNode = createComponent([ + "text": "\(weight.rawValue): abcdefghijklmnopqrstuwvxyz", + "textSize": 0.04, + "localPosition": [-0.3, y - Float(index) * 0.05, 0], + ], nodeId: "text_\(weight.rawValue)", parentId: prismId) + text.style = style + text.weight = weight + text.updateLayout() + } + } + + NodesManager.instance.updateLayout() + } + fileprivate func loadModel(_ filePath: String, index: Int, parentId: String) { let columns: Int = 2 let x: CGFloat = -0.3 + CGFloat(index % columns) * 0.3 diff --git a/ios/RNMagicScriptTests/sources/specs/UiNodes/Group/GroupContainerSpec.swift b/ios/RNMagicScriptTests/sources/specs/UiNodes/Group/GroupContainerSpec.swift index f146cdfe..ecb7457d 100644 --- a/ios/RNMagicScriptTests/sources/specs/UiNodes/Group/GroupContainerSpec.swift +++ b/ios/RNMagicScriptTests/sources/specs/UiNodes/Group/GroupContainerSpec.swift @@ -116,7 +116,7 @@ class GroupContainerSpec: QuickSpec { let items = self.prepareSampleTransformNodes() items.forEach { group.addItem($0) } let targetBounds = CGRect(x: 0.3, y: -0.5, width: 2.63, height: 1.45) - expect(group.getBounds()).to(beCloseTo(targetBounds)) + expect(group.getBounds()).to(beCloseTo(targetBounds, epsilon: 0.002)) } it("should return size") { diff --git a/ios/RNMagicScriptTests/sources/specs/UiNodes/UiTextNodeSpec.swift b/ios/RNMagicScriptTests/sources/specs/UiNodes/UiTextNodeSpec.swift index 0c95cc0c..4efdbf4b 100644 --- a/ios/RNMagicScriptTests/sources/specs/UiNodes/UiTextNodeSpec.swift +++ b/ios/RNMagicScriptTests/sources/specs/UiNodes/UiTextNodeSpec.swift @@ -246,8 +246,8 @@ class UiTextNodeSpec: QuickSpec { context("when wrap disabled") { let referenceBoundsSize = CGSize.zero - let shortTextRefereneceSizeForBounds = CGSize(width: 0.0426, height: 0.0144) - let veryLongTextRefereneceSizeForBounds = CGSize(width: 0.4986, height: 0.0144) + let shortTextRefereneceSizeForBounds: CGSize = is_iOS14() ? CGSize(width: 0.0444, height: 0.0168) : CGSize(width: 0.0426, height: 0.0144) + let veryLongTextRefereneceSizeForBounds: CGSize = is_iOS14() ? CGSize(width: 0.5202, height: 0.0168) : CGSize(width: 0.4986, height: 0.0144) it("should change bounds when text length increases") { node.update(["boundsSize" : ["wrap": false]]) @@ -290,8 +290,8 @@ class UiTextNodeSpec: QuickSpec { context("when boundsSize.height not set") { let referenceBoundsSize = CGSize(width: 0.1, height: 0) - let refereneceBoundsSizeWhenWrapDisabled = CGSize(width: 0.1, height: 0.0144) - let refereneceBoundsSizeWhenWrapEnabled = CGSize(width: 0.1, height: 0.072) + let refereneceBoundsSizeWhenWrapDisabled = is_iOS14() ? CGSize(width: 0.1, height: 0.0168) : CGSize(width: 0.1, height: 0.0144) + let refereneceBoundsSizeWhenWrapEnabled = is_iOS14() ? CGSize(width: 0.1, height: 0.1152) : CGSize(width: 0.1, height: 0.072) it("should change bounds when wrap changes") { node.update(["boundsSize" : ["boundsSize": referenceBoundsSize.toArrayOfFloat, "wrap": false]]) @@ -324,4 +324,12 @@ class UiTextNodeSpec: QuickSpec { } } } + + private func is_iOS14() -> Bool { + if #available(iOS 14.0, *) { + return true + } else { + return false + } + } } diff --git a/ios/RNMagicScriptTests/sources/specs/Utils/Maths/PlaneSpec.swift b/ios/RNMagicScriptTests/sources/specs/Utils/Maths/PlaneSpec.swift index 06fbafb5..7c75f8e5 100644 --- a/ios/RNMagicScriptTests/sources/specs/Utils/Maths/PlaneSpec.swift +++ b/ios/RNMagicScriptTests/sources/specs/Utils/Maths/PlaneSpec.swift @@ -58,7 +58,7 @@ class PlaneSpec: QuickSpec { it("should invoke assert for wrong vec4") { let referenceVector = SCNVector4(0, 0, 0, 2.0) - expect { _ = Plane(vector: referenceVector) }.to(throwAssertion()) + expect(_ = Plane(vector: referenceVector)).to(throwAssertion()) } } diff --git a/package.json b/package.json index e74b8112..e4cd0143 100644 --- a/package.json +++ b/package.json @@ -2,6 +2,11 @@ "name": "magic-script-components-react-native", "version": "2.1.0", "description": "Magic Script Components package for React Native.", + "homepage": "https://components.magicscript.org", + "repository": { + "type" : "git", + "url" : "https://github.com/magic-script/magic-script-components-react-native" + }, "main": "index.js", "scripts": { "test": "jest -i --coverage --json --outputFile=coverage/coverage.json"