This commit is contained in:
lucadruda 2021-03-15 16:09:53 +01:00
Коммит 843b99815e
128 изменённых файлов: 18032 добавлений и 0 удалений

6
.buckconfig Normal file
Просмотреть файл

@ -0,0 +1,6 @@
[android]
target = Google Inc.:Google APIs:23
[maven_repositories]
central = https://repo1.maven.org/maven2

17
.eslintrc.json Normal file
Просмотреть файл

@ -0,0 +1,17 @@
{
"parser": "@typescript-eslint/parser",
"parserOptions": {
"jsx": true,
"useJSXTextNode": true,
"ecmaVersion": 6,
"sourceType": "module",
"ecmaFeatures": {
"jsx": true
}
},
"plugins": ["react-hooks"],
"rules": {
"react-hooks/rules-of-hooks": "error",
"react-hooks/exhaustive-deps": "error"
}
}

66
.flowconfig Normal file
Просмотреть файл

@ -0,0 +1,66 @@
[ignore]
; We fork some components by platform
.*/*[.]android.js
; Ignore "BUCK" generated dirs
<PROJECT_ROOT>/\.buckd/
; Ignore polyfills
node_modules/react-native/Libraries/polyfills/.*
; Flow doesn't support platforms
.*/Libraries/Utilities/LoadingView.js
[untyped]
.*/node_modules/@react-native-community/cli/.*/.*
[include]
[libs]
node_modules/react-native/interface.js
node_modules/react-native/flow/
[options]
emoji=true
esproposal.optional_chaining=enable
esproposal.nullish_coalescing=enable
exact_by_default=true
module.file_ext=.js
module.file_ext=.json
module.file_ext=.ios.js
munge_underscores=true
module.name_mapper='^react-native/\(.*\)$' -> '<PROJECT_ROOT>/node_modules/react-native/\1'
module.name_mapper='^@?[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> '<PROJECT_ROOT>/node_modules/react-native/Libraries/Image/RelativeImageStub'
suppress_type=$FlowIssue
suppress_type=$FlowFixMe
suppress_type=$FlowFixMeProps
suppress_type=$FlowFixMeState
[lints]
sketchy-null-number=warn
sketchy-null-mixed=warn
sketchy-number=warn
untyped-type-import=warn
nonstrict-import=warn
deprecated-type=warn
unsafe-getters-setters=warn
unnecessary-invariant=warn
signature-verification-failure=warn
[strict]
deprecated-type
nonstrict-import
sketchy-null
unclear-type
unsafe-getters-setters
untyped-import
untyped-type-import
[version]
^0.137.0

3
.gitattributes поставляемый Normal file
Просмотреть файл

@ -0,0 +1,3 @@
# Windows files should use crlf line endings
# https://help.github.com/articles/dealing-with-line-endings/
*.bat text eol=crlf

63
.gitignore поставляемый Normal file
Просмотреть файл

@ -0,0 +1,63 @@
# OSX
#
.DS_Store
# Xcode
#
build/
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3
xcuserdata
*.xccheckout
*.moved-aside
DerivedData
*.hmap
*.ipa
*.xcuserstate
# Android/IntelliJ
#
build/
.idea
.gradle
local.properties
*.iml
# node.js
#
node_modules/
npm-debug.log
yarn-error.log
# BUCK
buck-out/
\.buckd/
*.keystore
!debug.keystore
# fastlane
#
# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
# screenshots whenever they are needed.
# For more information about the recommended setup visit:
# https://docs.fastlane.tools/best-practices/source-control/
*/fastlane/report.xml
*/fastlane/Preview.html
*/fastlane/screenshots
# Bundle artifact
*.jsbundle
# CocoaPods
/ios/Pods/
# vscode
.vscode
icons.json

7
.prettierrc.js Normal file
Просмотреть файл

@ -0,0 +1,7 @@
module.exports = {
bracketSpacing: false,
jsxBracketSameLine: true,
singleQuote: true,
trailingComma: 'all',
arrowParens: 'avoid',
};

5
.svgrrc Normal file
Просмотреть файл

@ -0,0 +1,5 @@
{
"replaceAttrValues": {
"#000": "{props.fill}"
}
}

1
.watchmanconfig Normal file
Просмотреть файл

@ -0,0 +1 @@
{}

51
README.md Normal file
Просмотреть файл

@ -0,0 +1,51 @@
# Azure IoT Central PaaD
A Phone-as-a-Device solution to easily connect with Azure IoT Central by using a smartphone or tablet as an IoT device.
**Android**
develop: [![Build status](https://build.appcenter.ms/v0.1/apps/82ba91a2-c68c-4b4b-949e-2b0c581eb0af/branches/develop/badge)](https://appcenter.ms)
## What is this?
An useful tool to start playing with Azure IoT Central without using a real IoT device. The smartphone or tablet can send telemetry data from its embedded sensors (accelerometer, gyroscope...) and registered health platforms (Apple Health Kit, Google Fit). It can also receive properties and commands to demonstrate basic functionalities.
## Features
The main features of the app are:
- Telemetry data from real embedded sensors and health platform records.
- Real-time charts.
- Sample properties (readonly and writeable).
- Commands handling to enable/disable telemetry items and set their sending interval.
- Commands logs to trace data in app.
## Build and Run
The application is available for both Android and iOS.
It can be run on simulator as well (Android Studio or Xcode required). In this case, sensor data is randomly generated.
### Required tools
See [React Native Getting Started](https://reactnative.dev/docs/getting-started)
and click on React Native CLI Quickstart for more detailed instructions.
"Installing dependencies" is the section that explains
developer setup. If you are developing on Windows for Android you will need:
1. Node.JS (10+)
1. Java SE Development Kit (JDK 8+)
1. Python 2.7+/3.7+
1. Android Studio
1. React Native command line interface
1. Npm or Yarn
To set up a real device for development, follow the instructions for device setup [here.](https://reactnative.dev/docs/running-on-device)
## Installation
```shell
git clone https://github.com/lucadruda/cpm-poc
cd cpm-poc
yarn install ( or 'npm install' if using npm)
```

14
__tests__/App-test.js Normal file
Просмотреть файл

@ -0,0 +1,14 @@
/**
* @format
*/
import 'react-native';
import React from 'react';
import App from '../App';
// Note: test renderer must be required after react-native.
import renderer from 'react-test-renderer';
it('renders correctly', () => {
renderer.create(<App />);
});

3
_editorconfig Normal file
Просмотреть файл

@ -0,0 +1,3 @@
# Windows files
[*.bat]
end_of_line = crlf

55
android/app/_BUCK Normal file
Просмотреть файл

@ -0,0 +1,55 @@
# To learn about Buck see [Docs](https://buckbuild.com/).
# To run your application with Buck:
# - install Buck
# - `npm start` - to start the packager
# - `cd android`
# - `keytool -genkey -v -keystore keystores/debug.keystore -storepass android -alias androiddebugkey -keypass android -dname "CN=Android Debug,O=Android,C=US"`
# - `./gradlew :app:copyDownloadableDepsToLibs` - make all Gradle compile dependencies available to Buck
# - `buck install -r android/app` - compile, install and run application
#
load(":build_defs.bzl", "create_aar_targets", "create_jar_targets")
lib_deps = []
create_aar_targets(glob(["libs/*.aar"]))
create_jar_targets(glob(["libs/*.jar"]))
android_library(
name = "all-libs",
exported_deps = lib_deps,
)
android_library(
name = "app-code",
srcs = glob([
"src/main/java/**/*.java",
]),
deps = [
":all-libs",
":build_config",
":res",
],
)
android_build_config(
name = "build_config",
package = "com.my_first_pnp_device",
)
android_resource(
name = "res",
package = "com.my_first_pnp_device",
res = "src/main/res",
)
android_binary(
name = "app",
keystore = "//android/keystores:debug",
manifest = "src/main/AndroidManifest.xml",
package_type = "debug",
deps = [
":app-code",
],
)

224
android/app/build.gradle Normal file
Просмотреть файл

@ -0,0 +1,224 @@
apply plugin: "com.android.application"
import com.android.build.OutputFile
/**
* The react.gradle file registers a task for each build variant (e.g. bundleDebugJsAndAssets
* and bundleReleaseJsAndAssets).
* These basically call `react-native bundle` with the correct arguments during the Android build
* cycle. By default, bundleDebugJsAndAssets is skipped, as in debug/dev mode we prefer to load the
* bundle directly from the development server. Below you can see all the possible configurations
* and their defaults. If you decide to add a configuration block, make sure to add it before the
* `apply from: "../../node_modules/react-native/react.gradle"` line.
*
* project.ext.react = [
* // the name of the generated asset file containing your JS bundle
* bundleAssetName: "index.android.bundle",
*
* // the entry file for bundle generation. If none specified and
* // "index.android.js" exists, it will be used. Otherwise "index.js" is
* // default. Can be overridden with ENTRY_FILE environment variable.
* entryFile: "index.android.js",
*
* // https://reactnative.dev/docs/performance#enable-the-ram-format
* bundleCommand: "ram-bundle",
*
* // whether to bundle JS and assets in debug mode
* bundleInDebug: false,
*
* // whether to bundle JS and assets in release mode
* bundleInRelease: true,
*
* // whether to bundle JS and assets in another build variant (if configured).
* // See http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Variants
* // The configuration property can be in the following formats
* // 'bundleIn${productFlavor}${buildType}'
* // 'bundleIn${buildType}'
* // bundleInFreeDebug: true,
* // bundleInPaidRelease: true,
* // bundleInBeta: true,
*
* // whether to disable dev mode in custom build variants (by default only disabled in release)
* // for example: to disable dev mode in the staging build type (if configured)
* devDisabledInStaging: true,
* // The configuration property can be in the following formats
* // 'devDisabledIn${productFlavor}${buildType}'
* // 'devDisabledIn${buildType}'
*
* // the root of your project, i.e. where "package.json" lives
* root: "../../",
*
* // where to put the JS bundle asset in debug mode
* jsBundleDirDebug: "$buildDir/intermediates/assets/debug",
*
* // where to put the JS bundle asset in release mode
* jsBundleDirRelease: "$buildDir/intermediates/assets/release",
*
* // where to put drawable resources / React Native assets, e.g. the ones you use via
* // require('./image.png')), in debug mode
* resourcesDirDebug: "$buildDir/intermediates/res/merged/debug",
*
* // where to put drawable resources / React Native assets, e.g. the ones you use via
* // require('./image.png')), in release mode
* resourcesDirRelease: "$buildDir/intermediates/res/merged/release",
*
* // by default the gradle tasks are skipped if none of the JS files or assets change; this means
* // that we don't look at files in android/ or ios/ to determine whether the tasks are up to
* // date; if you have any other folders that you want to ignore for performance reasons (gradle
* // indexes the entire tree), add them here. Alternatively, if you have JS files in android/
* // for example, you might want to remove it from here.
* inputExcludes: ["android/**", "ios/**"],
*
* // override which node gets called and with what additional arguments
* nodeExecutableAndArgs: ["node"],
*
* // supply additional arguments to the packager
* extraPackagerArgs: []
* ]
*/
project.ext.react = [
enableHermes: false, // clean and rebuild if changing
]
apply from: "../../node_modules/react-native/react.gradle"
/**
* Set this to true to create two separate APKs instead of one:
* - An APK that only works on ARM devices
* - An APK that only works on x86 devices
* The advantage is the size of the APK is reduced by about 4MB.
* Upload all the APKs to the Play Store and people will download
* the correct one based on the CPU architecture of their device.
*/
def enableSeparateBuildPerCPUArchitecture = false
/**
* Run Proguard to shrink the Java bytecode in release builds.
*/
def enableProguardInReleaseBuilds = false
/**
* The preferred build flavor of JavaScriptCore.
*
* For example, to use the international variant, you can use:
* `def jscFlavor = 'org.webkit:android-jsc-intl:+'`
*
* The international variant includes ICU i18n library and necessary data
* allowing to use e.g. `Date.toLocaleString` and `String.localeCompare` that
* give correct results when using with locales other than en-US. Note that
* this variant is about 6MiB larger per architecture than default.
*/
def jscFlavor = 'org.webkit:android-jsc:+'
/**
* Whether to enable the Hermes VM.
*
* This should be set on project.ext.react and mirrored here. If it is not set
* on project.ext.react, JavaScript will not be compiled to Hermes Bytecode
* and the benefits of using Hermes will therefore be sharply reduced.
*/
def enableHermes = project.ext.react.get("enableHermes", false);
android {
ndkVersion rootProject.ext.ndkVersion
compileSdkVersion rootProject.ext.compileSdkVersion
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
defaultConfig {
applicationId "com.my_first_pnp_device"
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
missingDimensionStrategy 'react-native-camera', 'general'
versionCode 1
versionName "1.0"
}
splits {
abi {
reset()
enable enableSeparateBuildPerCPUArchitecture
universalApk false // If true, also generate a universal APK
include "armeabi-v7a", "x86", "arm64-v8a", "x86_64"
}
}
signingConfigs {
debug {
storeFile file('debug.keystore')
storePassword 'android'
keyAlias 'androiddebugkey'
keyPassword 'android'
}
}
buildTypes {
debug {
signingConfig signingConfigs.debug
}
release {
// Caution! In production, you need to generate your own keystore file.
// see https://reactnative.dev/docs/signed-apk-android.
signingConfig signingConfigs.debug
minifyEnabled enableProguardInReleaseBuilds
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
}
}
// applicationVariants are e.g. debug, release
applicationVariants.all { variant ->
variant.outputs.each { output ->
// For each separate APK per architecture, set a unique version code as described here:
// https://developer.android.com/studio/build/configure-apk-splits.html
// Example: versionCode 1 will generate 1001 for armeabi-v7a, 1002 for x86, etc.
def versionCodes = ["armeabi-v7a": 1, "x86": 2, "arm64-v8a": 3, "x86_64": 4]
def abi = output.getFilter(OutputFile.ABI)
if (abi != null) { // null for the universal-debug, universal-release variants
output.versionCodeOverride =
defaultConfig.versionCode * 1000 + versionCodes.get(abi)
}
}
}
}
dependencies {
implementation fileTree(dir: "libs", include: ["*.jar"])
//noinspection GradleDynamicVersion
implementation "com.facebook.react:react-native:+" // From node_modules
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.0.0"
debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}") {
exclude group:'com.facebook.fbjni'
}
debugImplementation("com.facebook.flipper:flipper-network-plugin:${FLIPPER_VERSION}") {
exclude group:'com.facebook.flipper'
exclude group:'com.squareup.okhttp3', module:'okhttp'
}
debugImplementation("com.facebook.flipper:flipper-fresco-plugin:${FLIPPER_VERSION}") {
exclude group:'com.facebook.flipper'
}
if (enableHermes) {
def hermesPath = "../../node_modules/hermes-engine/android/";
debugImplementation files(hermesPath + "hermes-debug.aar")
releaseImplementation files(hermesPath + "hermes-release.aar")
} else {
implementation jscFlavor
}
}
// Run this once to be able to run the application with BUCK
// puts all compile dependencies into folder libs for BUCK to use
task copyDownloadableDepsToLibs(type: Copy) {
from configurations.compile
into 'libs'
}
apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project)
apply from: "../../node_modules/react-native-vector-icons/fonts.gradle"

Просмотреть файл

@ -0,0 +1,19 @@
"""Helper definitions to glob .aar and .jar targets"""
def create_aar_targets(aarfiles):
for aarfile in aarfiles:
name = "aars__" + aarfile[aarfile.rindex("/") + 1:aarfile.rindex(".aar")]
lib_deps.append(":" + name)
android_prebuilt_aar(
name = name,
aar = aarfile,
)
def create_jar_targets(jarfiles):
for jarfile in jarfiles:
name = "jars__" + jarfile[jarfile.rindex("/") + 1:jarfile.rindex(".jar")]
lib_deps.append(":" + name)
prebuilt_jar(
name = name,
binary_jar = jarfile,
)

Двоичные данные
android/app/debug.keystore Normal file

Двоичный файл не отображается.

10
android/app/proguard-rules.pro поставляемый Normal file
Просмотреть файл

@ -0,0 +1,10 @@
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in /usr/local/Cellar/android-sdk/24.3.3/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:

Просмотреть файл

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<application
android:usesCleartextTraffic="true"
tools:targetApi="28"
tools:ignore="GoogleAppIndexingWarning">
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />
</application>
</manifest>

Просмотреть файл

@ -0,0 +1,72 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* <p>This source code is licensed under the MIT license found in the LICENSE file in the root
* directory of this source tree.
*/
package com.my_first_pnp_device;
import android.content.Context;
import com.facebook.flipper.android.AndroidFlipperClient;
import com.facebook.flipper.android.utils.FlipperUtils;
import com.facebook.flipper.core.FlipperClient;
import com.facebook.flipper.plugins.crashreporter.CrashReporterPlugin;
import com.facebook.flipper.plugins.databases.DatabasesFlipperPlugin;
import com.facebook.flipper.plugins.fresco.FrescoFlipperPlugin;
import com.facebook.flipper.plugins.inspector.DescriptorMapping;
import com.facebook.flipper.plugins.inspector.InspectorFlipperPlugin;
import com.facebook.flipper.plugins.network.FlipperOkhttpInterceptor;
import com.facebook.flipper.plugins.network.NetworkFlipperPlugin;
import com.facebook.flipper.plugins.react.ReactFlipperPlugin;
import com.facebook.flipper.plugins.sharedpreferences.SharedPreferencesFlipperPlugin;
import com.facebook.react.ReactInstanceManager;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.modules.network.NetworkingModule;
import okhttp3.OkHttpClient;
public class ReactNativeFlipper {
public static void initializeFlipper(Context context, ReactInstanceManager reactInstanceManager) {
if (FlipperUtils.shouldEnableFlipper(context)) {
final FlipperClient client = AndroidFlipperClient.getInstance(context);
client.addPlugin(new InspectorFlipperPlugin(context, DescriptorMapping.withDefaults()));
client.addPlugin(new ReactFlipperPlugin());
client.addPlugin(new DatabasesFlipperPlugin(context));
client.addPlugin(new SharedPreferencesFlipperPlugin(context));
client.addPlugin(CrashReporterPlugin.getInstance());
NetworkFlipperPlugin networkFlipperPlugin = new NetworkFlipperPlugin();
NetworkingModule.setCustomClientBuilder(
new NetworkingModule.CustomClientBuilder() {
@Override
public void apply(OkHttpClient.Builder builder) {
builder.addNetworkInterceptor(new FlipperOkhttpInterceptor(networkFlipperPlugin));
}
});
client.addPlugin(networkFlipperPlugin);
client.start();
// Fresco Plugin needs to ensure that ImagePipelineFactory is initialized
// Hence we run if after all native modules have been initialized
ReactContext reactContext = reactInstanceManager.getCurrentReactContext();
if (reactContext == null) {
reactInstanceManager.addReactInstanceEventListener(
new ReactInstanceManager.ReactInstanceEventListener() {
@Override
public void onReactContextInitialized(ReactContext reactContext) {
reactInstanceManager.removeReactInstanceEventListener(this);
reactContext.runOnNativeModulesQueueThread(
new Runnable() {
@Override
public void run() {
client.addPlugin(new FrescoFlipperPlugin());
}
});
}
});
} else {
client.addPlugin(new FrescoFlipperPlugin());
}
}
}
}

Просмотреть файл

@ -0,0 +1,19 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.my_first_pnp_device">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.VIBRATE"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-feature android:name="android.hardware.camera" android:required="false" />
<uses-feature android:name="android.hardware.camera.front" android:required="false" />
<application android:name=".MainApplication" android:label="@string/app_name" android:icon="@mipmap/ic_launcher" android:roundIcon="@mipmap/ic_launcher_round" android:allowBackup="false" android:theme="@style/AppTheme">
<activity android:name=".MainActivity" android:label="@string/app_name" android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode" android:launchMode="singleTask" android:windowSoftInputMode="adjustResize">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>

Просмотреть файл

@ -0,0 +1,15 @@
package com.my_first_pnp_device;
import com.facebook.react.ReactActivity;
public class MainActivity extends ReactActivity {
/**
* Returns the name of the main component registered from JavaScript. This is used to schedule
* rendering of the component.
*/
@Override
protected String getMainComponentName() {
return "my_first_pnp_device";
}
}

Просмотреть файл

@ -0,0 +1,80 @@
package com.my_first_pnp_device;
import android.app.Application;
import android.content.Context;
import com.facebook.react.PackageList;
import com.facebook.react.ReactApplication;
import com.facebook.react.ReactInstanceManager;
import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactPackage;
import com.facebook.soloader.SoLoader;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
public class MainApplication extends Application implements ReactApplication {
private final ReactNativeHost mReactNativeHost =
new ReactNativeHost(this) {
@Override
public boolean getUseDeveloperSupport() {
return BuildConfig.DEBUG;
}
@Override
protected List<ReactPackage> getPackages() {
@SuppressWarnings("UnnecessaryLocalVariable")
List<ReactPackage> packages = new PackageList(this).getPackages();
// Packages that cannot be autolinked yet can be added manually here, for example:
// packages.add(new MyReactNativePackage());
return packages;
}
@Override
protected String getJSMainModuleName() {
return "index";
}
};
@Override
public ReactNativeHost getReactNativeHost() {
return mReactNativeHost;
}
@Override
public void onCreate() {
super.onCreate();
SoLoader.init(this, /* native exopackage */ false);
initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
}
/**
* Loads Flipper in React Native templates. Call this in the onCreate method with something like
* initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
*
* @param context
* @param reactInstanceManager
*/
private static void initializeFlipper(
Context context, ReactInstanceManager reactInstanceManager) {
if (BuildConfig.DEBUG) {
try {
/*
We use reflection here to pick up the class that initializes Flipper,
since Flipper library is not available in release mode
*/
Class<?> aClass = Class.forName("com.my_first_pnp_device.ReactNativeFlipper");
aClass
.getMethod("initializeFlipper", Context.class, ReactInstanceManager.class)
.invoke(null, context, reactInstanceManager);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
}

Двоичные данные
android/app/src/main/res/mipmap-hdpi/ic_launcher.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 3.0 KiB

Двоичные данные
android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 4.9 KiB

Двоичные данные
android/app/src/main/res/mipmap-mdpi/ic_launcher.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 2.0 KiB

Двоичные данные
android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 2.8 KiB

Двоичные данные
android/app/src/main/res/mipmap-xhdpi/ic_launcher.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 4.5 KiB

Двоичные данные
android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 6.9 KiB

Двоичные данные
android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 6.3 KiB

Двоичные данные
android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 10 KiB

Двоичные данные
android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 9.0 KiB

Двоичные данные
android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 15 KiB

Просмотреть файл

@ -0,0 +1,3 @@
<resources>
<string name="app_name">my_first_pnp_device</string>
</resources>

Просмотреть файл

@ -0,0 +1,9 @@
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.DayNight.NoActionBar">
<!-- Customize your theme here. -->
<item name="android:textColor">#000000</item>
</style>
</resources>

38
android/build.gradle Normal file
Просмотреть файл

@ -0,0 +1,38 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
ext {
buildToolsVersion = "29.0.3"
minSdkVersion = 21
compileSdkVersion = 29
targetSdkVersion = 29
ndkVersion = "20.1.5948944"
}
repositories {
google()
jcenter()
}
dependencies {
classpath("com.android.tools.build:gradle:4.1.0")
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
mavenLocal()
maven {
// All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
url("$rootDir/../node_modules/react-native/android")
}
maven {
// Android JSC is installed from npm
url("$rootDir/../node_modules/jsc-android/dist")
}
google()
jcenter()
maven { url 'https://www.jitpack.io' }
}
}

28
android/gradle.properties Normal file
Просмотреть файл

@ -0,0 +1,28 @@
# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
# Default value: -Xmx10248m -XX:MaxPermSize=256m
# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
# AndroidX package structure to make it clearer which packages are bundled with the
# Android operating system, and which are packaged with your app's APK
# https://developer.android.com/topic/libraries/support-library/androidx-rn
android.useAndroidX=true
# Automatically convert third-party libraries to use AndroidX
android.enableJetifier=true
# Version of flipper SDK to use with React Native
FLIPPER_VERSION=0.75.1

Двоичные данные
android/gradle/wrapper/gradle-wrapper.jar поставляемый Normal file

Двоичный файл не отображается.

5
android/gradle/wrapper/gradle-wrapper.properties поставляемый Normal file
Просмотреть файл

@ -0,0 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

185
android/gradlew поставляемый Executable file
Просмотреть файл

@ -0,0 +1,185 @@
#!/usr/bin/env sh
#
# Copyright 2015 the original author or authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn () {
echo "$*"
}
die () {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=`expr $i + 1`
done
case $i in
0) set -- ;;
1) set -- "$args0" ;;
2) set -- "$args0" "$args1" ;;
3) set -- "$args0" "$args1" "$args2" ;;
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=`save "$@"`
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
exec "$JAVACMD" "$@"

89
android/gradlew.bat поставляемый Normal file
Просмотреть файл

@ -0,0 +1,89 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

3
android/settings.gradle Normal file
Просмотреть файл

@ -0,0 +1,3 @@
rootProject.name = 'my_first_pnp_device'
apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings)
include ':app'

4
app.json Normal file
Просмотреть файл

@ -0,0 +1,4 @@
{
"name": "my_first_pnp_device",
"displayName": "my_first_pnp_device"
}

27
babel.config.js Normal file
Просмотреть файл

@ -0,0 +1,27 @@
module.exports = {
presets: ['module:metro-react-native-babel-preset'],
plugins: [
["module-resolver", {
"root": ["./src"],
"extensions": [
'.ios.ts',
'.android.ts',
'.ts',
'.ios.tsx',
'.android.tsx',
'.tsx',
'.jsx',
'.js',
'.json',
],
"alias": {
"tools": "./src/tools",
"hooks": "./src/hooks",
"properties": "./src/properties",
"contexts": "./src/contexts",
"sensors": "./src/sensors",
"types":"./src/types"
}
}]
]
};

9
index.js Normal file
Просмотреть файл

@ -0,0 +1,9 @@
/**
* @format
*/
import {AppRegistry} from 'react-native';
import App from './src/App';
import {name as appName} from './app.json';
AppRegistry.registerComponent(appName, () => App);

8
ios/Charts.swift Normal file
Просмотреть файл

@ -0,0 +1,8 @@
//
// Charts.swift
// my_first_pnp_device
//
// Created by Luca Druda on 15/03/2021.
//
import Foundation

31
ios/Podfile Normal file
Просмотреть файл

@ -0,0 +1,31 @@
require_relative '../node_modules/react-native/scripts/react_native_pods'
require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules'
platform :ios, '10.0'
permissions_path = '../node_modules/react-native-permissions/ios'
pod 'Permission-Camera', :path => "#{permissions_path}/Camera"
target 'my_first_pnp_device' do
config = use_native_modules!
use_react_native!(
:path => config[:reactNativePath],
# to enable hermes on iOS, change `false` to `true` and then install pods
:hermes_enabled => false
)
target 'my_first_pnp_deviceTests' do
inherit! :complete
# Pods for testing
end
# Enables Flipper.
#
# Note that if you have use_frameworks! enabled, Flipper will not work and
# you should disable the next line.
use_flipper!()
post_install do |installer|
react_native_post_install(installer)
end
end

632
ios/Podfile.lock Normal file
Просмотреть файл

@ -0,0 +1,632 @@
PODS:
- boost-for-react-native (1.63.0)
- BVLinearGradient (2.5.6):
- React
- CocoaAsyncSocket (7.6.5)
- DoubleConversion (1.1.6)
- FBLazyVector (0.64.0)
- FBReactNativeSpec (0.64.0):
- RCT-Folly (= 2020.01.13.00)
- RCTRequired (= 0.64.0)
- RCTTypeSafety (= 0.64.0)
- React-Core (= 0.64.0)
- React-jsi (= 0.64.0)
- ReactCommon/turbomodule/core (= 0.64.0)
- Flipper (0.75.1):
- Flipper-Folly (~> 2.5)
- Flipper-RSocket (~> 1.3)
- Flipper-DoubleConversion (1.1.7)
- Flipper-Folly (2.5.1):
- boost-for-react-native
- Flipper-DoubleConversion
- Flipper-Glog
- libevent (~> 2.1.12)
- OpenSSL-Universal (= 1.1.180)
- Flipper-Glog (0.3.6)
- Flipper-PeerTalk (0.0.4)
- Flipper-RSocket (1.3.0):
- Flipper-Folly (~> 2.5)
- FlipperKit (0.75.1):
- FlipperKit/Core (= 0.75.1)
- FlipperKit/Core (0.75.1):
- Flipper (~> 0.75.1)
- FlipperKit/CppBridge
- FlipperKit/FBCxxFollyDynamicConvert
- FlipperKit/FBDefines
- FlipperKit/FKPortForwarding
- FlipperKit/CppBridge (0.75.1):
- Flipper (~> 0.75.1)
- FlipperKit/FBCxxFollyDynamicConvert (0.75.1):
- Flipper-Folly (~> 2.5)
- FlipperKit/FBDefines (0.75.1)
- FlipperKit/FKPortForwarding (0.75.1):
- CocoaAsyncSocket (~> 7.6)
- Flipper-PeerTalk (~> 0.0.4)
- FlipperKit/FlipperKitHighlightOverlay (0.75.1)
- FlipperKit/FlipperKitLayoutPlugin (0.75.1):
- FlipperKit/Core
- FlipperKit/FlipperKitHighlightOverlay
- FlipperKit/FlipperKitLayoutTextSearchable
- YogaKit (~> 1.18)
- FlipperKit/FlipperKitLayoutTextSearchable (0.75.1)
- FlipperKit/FlipperKitNetworkPlugin (0.75.1):
- FlipperKit/Core
- FlipperKit/FlipperKitReactPlugin (0.75.1):
- FlipperKit/Core
- FlipperKit/FlipperKitUserDefaultsPlugin (0.75.1):
- FlipperKit/Core
- FlipperKit/SKIOSNetworkPlugin (0.75.1):
- FlipperKit/Core
- FlipperKit/FlipperKitNetworkPlugin
- glog (0.3.5)
- libevent (2.1.12)
- OpenSSL-Universal (1.1.180)
- Permission-Camera (3.0.1):
- RNPermissions
- RCT-Folly (2020.01.13.00):
- boost-for-react-native
- DoubleConversion
- glog
- RCT-Folly/Default (= 2020.01.13.00)
- RCT-Folly/Default (2020.01.13.00):
- boost-for-react-native
- DoubleConversion
- glog
- RCTRequired (0.64.0)
- RCTTypeSafety (0.64.0):
- FBLazyVector (= 0.64.0)
- RCT-Folly (= 2020.01.13.00)
- RCTRequired (= 0.64.0)
- React-Core (= 0.64.0)
- React (0.64.0):
- React-Core (= 0.64.0)
- React-Core/DevSupport (= 0.64.0)
- React-Core/RCTWebSocket (= 0.64.0)
- React-RCTActionSheet (= 0.64.0)
- React-RCTAnimation (= 0.64.0)
- React-RCTBlob (= 0.64.0)
- React-RCTImage (= 0.64.0)
- React-RCTLinking (= 0.64.0)
- React-RCTNetwork (= 0.64.0)
- React-RCTSettings (= 0.64.0)
- React-RCTText (= 0.64.0)
- React-RCTVibration (= 0.64.0)
- React-callinvoker (0.64.0)
- React-Core (0.64.0):
- glog
- RCT-Folly (= 2020.01.13.00)
- React-Core/Default (= 0.64.0)
- React-cxxreact (= 0.64.0)
- React-jsi (= 0.64.0)
- React-jsiexecutor (= 0.64.0)
- React-perflogger (= 0.64.0)
- Yoga
- React-Core/CoreModulesHeaders (0.64.0):
- glog
- RCT-Folly (= 2020.01.13.00)
- React-Core/Default
- React-cxxreact (= 0.64.0)
- React-jsi (= 0.64.0)
- React-jsiexecutor (= 0.64.0)
- React-perflogger (= 0.64.0)
- Yoga
- React-Core/Default (0.64.0):
- glog
- RCT-Folly (= 2020.01.13.00)
- React-cxxreact (= 0.64.0)
- React-jsi (= 0.64.0)
- React-jsiexecutor (= 0.64.0)
- React-perflogger (= 0.64.0)
- Yoga
- React-Core/DevSupport (0.64.0):
- glog
- RCT-Folly (= 2020.01.13.00)
- React-Core/Default (= 0.64.0)
- React-Core/RCTWebSocket (= 0.64.0)
- React-cxxreact (= 0.64.0)
- React-jsi (= 0.64.0)
- React-jsiexecutor (= 0.64.0)
- React-jsinspector (= 0.64.0)
- React-perflogger (= 0.64.0)
- Yoga
- React-Core/RCTActionSheetHeaders (0.64.0):
- glog
- RCT-Folly (= 2020.01.13.00)
- React-Core/Default
- React-cxxreact (= 0.64.0)
- React-jsi (= 0.64.0)
- React-jsiexecutor (= 0.64.0)
- React-perflogger (= 0.64.0)
- Yoga
- React-Core/RCTAnimationHeaders (0.64.0):
- glog
- RCT-Folly (= 2020.01.13.00)
- React-Core/Default
- React-cxxreact (= 0.64.0)
- React-jsi (= 0.64.0)
- React-jsiexecutor (= 0.64.0)
- React-perflogger (= 0.64.0)
- Yoga
- React-Core/RCTBlobHeaders (0.64.0):
- glog
- RCT-Folly (= 2020.01.13.00)
- React-Core/Default
- React-cxxreact (= 0.64.0)
- React-jsi (= 0.64.0)
- React-jsiexecutor (= 0.64.0)
- React-perflogger (= 0.64.0)
- Yoga
- React-Core/RCTImageHeaders (0.64.0):
- glog
- RCT-Folly (= 2020.01.13.00)
- React-Core/Default
- React-cxxreact (= 0.64.0)
- React-jsi (= 0.64.0)
- React-jsiexecutor (= 0.64.0)
- React-perflogger (= 0.64.0)
- Yoga
- React-Core/RCTLinkingHeaders (0.64.0):
- glog
- RCT-Folly (= 2020.01.13.00)
- React-Core/Default
- React-cxxreact (= 0.64.0)
- React-jsi (= 0.64.0)
- React-jsiexecutor (= 0.64.0)
- React-perflogger (= 0.64.0)
- Yoga
- React-Core/RCTNetworkHeaders (0.64.0):
- glog
- RCT-Folly (= 2020.01.13.00)
- React-Core/Default
- React-cxxreact (= 0.64.0)
- React-jsi (= 0.64.0)
- React-jsiexecutor (= 0.64.0)
- React-perflogger (= 0.64.0)
- Yoga
- React-Core/RCTSettingsHeaders (0.64.0):
- glog
- RCT-Folly (= 2020.01.13.00)
- React-Core/Default
- React-cxxreact (= 0.64.0)
- React-jsi (= 0.64.0)
- React-jsiexecutor (= 0.64.0)
- React-perflogger (= 0.64.0)
- Yoga
- React-Core/RCTTextHeaders (0.64.0):
- glog
- RCT-Folly (= 2020.01.13.00)
- React-Core/Default
- React-cxxreact (= 0.64.0)
- React-jsi (= 0.64.0)
- React-jsiexecutor (= 0.64.0)
- React-perflogger (= 0.64.0)
- Yoga
- React-Core/RCTVibrationHeaders (0.64.0):
- glog
- RCT-Folly (= 2020.01.13.00)
- React-Core/Default
- React-cxxreact (= 0.64.0)
- React-jsi (= 0.64.0)
- React-jsiexecutor (= 0.64.0)
- React-perflogger (= 0.64.0)
- Yoga
- React-Core/RCTWebSocket (0.64.0):
- glog
- RCT-Folly (= 2020.01.13.00)
- React-Core/Default (= 0.64.0)
- React-cxxreact (= 0.64.0)
- React-jsi (= 0.64.0)
- React-jsiexecutor (= 0.64.0)
- React-perflogger (= 0.64.0)
- Yoga
- React-CoreModules (0.64.0):
- FBReactNativeSpec (= 0.64.0)
- RCT-Folly (= 2020.01.13.00)
- RCTTypeSafety (= 0.64.0)
- React-Core/CoreModulesHeaders (= 0.64.0)
- React-jsi (= 0.64.0)
- React-RCTImage (= 0.64.0)
- ReactCommon/turbomodule/core (= 0.64.0)
- React-cxxreact (0.64.0):
- boost-for-react-native (= 1.63.0)
- DoubleConversion
- glog
- RCT-Folly (= 2020.01.13.00)
- React-callinvoker (= 0.64.0)
- React-jsi (= 0.64.0)
- React-jsinspector (= 0.64.0)
- React-perflogger (= 0.64.0)
- React-runtimeexecutor (= 0.64.0)
- React-jsi (0.64.0):
- boost-for-react-native (= 1.63.0)
- DoubleConversion
- glog
- RCT-Folly (= 2020.01.13.00)
- React-jsi/Default (= 0.64.0)
- React-jsi/Default (0.64.0):
- boost-for-react-native (= 1.63.0)
- DoubleConversion
- glog
- RCT-Folly (= 2020.01.13.00)
- React-jsiexecutor (0.64.0):
- DoubleConversion
- glog
- RCT-Folly (= 2020.01.13.00)
- React-cxxreact (= 0.64.0)
- React-jsi (= 0.64.0)
- React-perflogger (= 0.64.0)
- React-jsinspector (0.64.0)
- react-native-camera (3.43.0):
- React-Core
- react-native-camera/RCT (= 3.43.0)
- react-native-camera/RN (= 3.43.0)
- react-native-camera/RCT (3.43.0):
- React-Core
- react-native-camera/RN (3.43.0):
- React-Core
- react-native-geolocation (2.0.2):
- React
- react-native-get-random-values (1.6.0):
- React-Core
- react-native-image-picker (3.3.2):
- React-Core
- react-native-maps (0.27.1):
- React
- react-native-safe-area-context (3.2.0):
- React-Core
- React-perflogger (0.64.0)
- React-RCTActionSheet (0.64.0):
- React-Core/RCTActionSheetHeaders (= 0.64.0)
- React-RCTAnimation (0.64.0):
- FBReactNativeSpec (= 0.64.0)
- RCT-Folly (= 2020.01.13.00)
- RCTTypeSafety (= 0.64.0)
- React-Core/RCTAnimationHeaders (= 0.64.0)
- React-jsi (= 0.64.0)
- ReactCommon/turbomodule/core (= 0.64.0)
- React-RCTBlob (0.64.0):
- FBReactNativeSpec (= 0.64.0)
- RCT-Folly (= 2020.01.13.00)
- React-Core/RCTBlobHeaders (= 0.64.0)
- React-Core/RCTWebSocket (= 0.64.0)
- React-jsi (= 0.64.0)
- React-RCTNetwork (= 0.64.0)
- ReactCommon/turbomodule/core (= 0.64.0)
- React-RCTImage (0.64.0):
- FBReactNativeSpec (= 0.64.0)
- RCT-Folly (= 2020.01.13.00)
- RCTTypeSafety (= 0.64.0)
- React-Core/RCTImageHeaders (= 0.64.0)
- React-jsi (= 0.64.0)
- React-RCTNetwork (= 0.64.0)
- ReactCommon/turbomodule/core (= 0.64.0)
- React-RCTLinking (0.64.0):
- FBReactNativeSpec (= 0.64.0)
- React-Core/RCTLinkingHeaders (= 0.64.0)
- React-jsi (= 0.64.0)
- ReactCommon/turbomodule/core (= 0.64.0)
- React-RCTNetwork (0.64.0):
- FBReactNativeSpec (= 0.64.0)
- RCT-Folly (= 2020.01.13.00)
- RCTTypeSafety (= 0.64.0)
- React-Core/RCTNetworkHeaders (= 0.64.0)
- React-jsi (= 0.64.0)
- ReactCommon/turbomodule/core (= 0.64.0)
- React-RCTSettings (0.64.0):
- FBReactNativeSpec (= 0.64.0)
- RCT-Folly (= 2020.01.13.00)
- RCTTypeSafety (= 0.64.0)
- React-Core/RCTSettingsHeaders (= 0.64.0)
- React-jsi (= 0.64.0)
- ReactCommon/turbomodule/core (= 0.64.0)
- React-RCTText (0.64.0):
- React-Core/RCTTextHeaders (= 0.64.0)
- React-RCTVibration (0.64.0):
- FBReactNativeSpec (= 0.64.0)
- RCT-Folly (= 2020.01.13.00)
- React-Core/RCTVibrationHeaders (= 0.64.0)
- React-jsi (= 0.64.0)
- ReactCommon/turbomodule/core (= 0.64.0)
- React-runtimeexecutor (0.64.0):
- React-jsi (= 0.64.0)
- ReactCommon/turbomodule/core (0.64.0):
- DoubleConversion
- glog
- RCT-Folly (= 2020.01.13.00)
- React-callinvoker (= 0.64.0)
- React-Core (= 0.64.0)
- React-cxxreact (= 0.64.0)
- React-jsi (= 0.64.0)
- React-perflogger (= 0.64.0)
- ReactNativeART (1.2.0):
- React
- RNDeviceInfo (8.0.5):
- React-Core
- RNGestureHandler (1.10.3):
- React-Core
- RNKeychain (6.2.0):
- React
- RNPermissions (3.0.1):
- React-Core
- RNReanimated (2.0.0):
- DoubleConversion
- FBLazyVector
- FBReactNativeSpec
- glog
- RCT-Folly
- RCTRequired
- RCTTypeSafety
- React
- React-callinvoker
- React-Core
- React-Core/DevSupport
- React-Core/RCTWebSocket
- React-CoreModules
- React-cxxreact
- React-jsi
- React-jsiexecutor
- React-jsinspector
- React-RCTActionSheet
- React-RCTAnimation
- React-RCTBlob
- React-RCTImage
- React-RCTLinking
- React-RCTNetwork
- React-RCTSettings
- React-RCTText
- React-RCTVibration
- ReactCommon/turbomodule/core
- Yoga
- RNScreens (2.18.1):
- React-Core
- RNSensors (7.2.0):
- React-Core
- RNSVG (12.1.0):
- React
- RNVectorIcons (8.1.0):
- React-Core
- Yoga (1.14.0)
- YogaKit (1.18.1):
- Yoga (~> 1.14)
DEPENDENCIES:
- BVLinearGradient (from `../node_modules/react-native-linear-gradient`)
- DoubleConversion (from `../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec`)
- FBLazyVector (from `../node_modules/react-native/Libraries/FBLazyVector`)
- FBReactNativeSpec (from `../node_modules/react-native/React/FBReactNativeSpec`)
- Flipper (~> 0.75.1)
- Flipper-DoubleConversion (= 1.1.7)
- Flipper-Folly (~> 2.5)
- Flipper-Glog (= 0.3.6)
- Flipper-PeerTalk (~> 0.0.4)
- Flipper-RSocket (~> 1.3)
- FlipperKit (~> 0.75.1)
- FlipperKit/Core (~> 0.75.1)
- FlipperKit/CppBridge (~> 0.75.1)
- FlipperKit/FBCxxFollyDynamicConvert (~> 0.75.1)
- FlipperKit/FBDefines (~> 0.75.1)
- FlipperKit/FKPortForwarding (~> 0.75.1)
- FlipperKit/FlipperKitHighlightOverlay (~> 0.75.1)
- FlipperKit/FlipperKitLayoutPlugin (~> 0.75.1)
- FlipperKit/FlipperKitLayoutTextSearchable (~> 0.75.1)
- FlipperKit/FlipperKitNetworkPlugin (~> 0.75.1)
- FlipperKit/FlipperKitReactPlugin (~> 0.75.1)
- FlipperKit/FlipperKitUserDefaultsPlugin (~> 0.75.1)
- FlipperKit/SKIOSNetworkPlugin (~> 0.75.1)
- glog (from `../node_modules/react-native/third-party-podspecs/glog.podspec`)
- Permission-Camera (from `../node_modules/react-native-permissions/ios/Camera`)
- RCT-Folly (from `../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec`)
- RCTRequired (from `../node_modules/react-native/Libraries/RCTRequired`)
- RCTTypeSafety (from `../node_modules/react-native/Libraries/TypeSafety`)
- React (from `../node_modules/react-native/`)
- React-callinvoker (from `../node_modules/react-native/ReactCommon/callinvoker`)
- React-Core (from `../node_modules/react-native/`)
- React-Core/DevSupport (from `../node_modules/react-native/`)
- React-Core/RCTWebSocket (from `../node_modules/react-native/`)
- React-CoreModules (from `../node_modules/react-native/React/CoreModules`)
- React-cxxreact (from `../node_modules/react-native/ReactCommon/cxxreact`)
- React-jsi (from `../node_modules/react-native/ReactCommon/jsi`)
- React-jsiexecutor (from `../node_modules/react-native/ReactCommon/jsiexecutor`)
- React-jsinspector (from `../node_modules/react-native/ReactCommon/jsinspector`)
- react-native-camera (from `../node_modules/react-native-camera`)
- "react-native-geolocation (from `../node_modules/@react-native-community/geolocation`)"
- react-native-get-random-values (from `../node_modules/react-native-get-random-values`)
- react-native-image-picker (from `../node_modules/react-native-image-picker`)
- react-native-maps (from `../node_modules/react-native-maps`)
- react-native-safe-area-context (from `../node_modules/react-native-safe-area-context`)
- React-perflogger (from `../node_modules/react-native/ReactCommon/reactperflogger`)
- React-RCTActionSheet (from `../node_modules/react-native/Libraries/ActionSheetIOS`)
- React-RCTAnimation (from `../node_modules/react-native/Libraries/NativeAnimation`)
- React-RCTBlob (from `../node_modules/react-native/Libraries/Blob`)
- React-RCTImage (from `../node_modules/react-native/Libraries/Image`)
- React-RCTLinking (from `../node_modules/react-native/Libraries/LinkingIOS`)
- React-RCTNetwork (from `../node_modules/react-native/Libraries/Network`)
- React-RCTSettings (from `../node_modules/react-native/Libraries/Settings`)
- React-RCTText (from `../node_modules/react-native/Libraries/Text`)
- React-RCTVibration (from `../node_modules/react-native/Libraries/Vibration`)
- React-runtimeexecutor (from `../node_modules/react-native/ReactCommon/runtimeexecutor`)
- ReactCommon/turbomodule/core (from `../node_modules/react-native/ReactCommon`)
- "ReactNativeART (from `../node_modules/@react-native-community/art`)"
- RNDeviceInfo (from `../node_modules/react-native-device-info`)
- RNGestureHandler (from `../node_modules/react-native-gesture-handler`)
- RNKeychain (from `../node_modules/react-native-keychain`)
- RNPermissions (from `../node_modules/react-native-permissions`)
- RNReanimated (from `../node_modules/react-native-reanimated`)
- RNScreens (from `../node_modules/react-native-screens`)
- RNSensors (from `../node_modules/react-native-sensors`)
- RNSVG (from `../node_modules/react-native-svg`)
- RNVectorIcons (from `../node_modules/react-native-vector-icons`)
- Yoga (from `../node_modules/react-native/ReactCommon/yoga`)
SPEC REPOS:
trunk:
- boost-for-react-native
- CocoaAsyncSocket
- Flipper
- Flipper-DoubleConversion
- Flipper-Folly
- Flipper-Glog
- Flipper-PeerTalk
- Flipper-RSocket
- FlipperKit
- libevent
- OpenSSL-Universal
- YogaKit
EXTERNAL SOURCES:
BVLinearGradient:
:path: "../node_modules/react-native-linear-gradient"
DoubleConversion:
:podspec: "../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec"
FBLazyVector:
:path: "../node_modules/react-native/Libraries/FBLazyVector"
FBReactNativeSpec:
:path: "../node_modules/react-native/React/FBReactNativeSpec"
glog:
:podspec: "../node_modules/react-native/third-party-podspecs/glog.podspec"
Permission-Camera:
:path: "../node_modules/react-native-permissions/ios/Camera"
RCT-Folly:
:podspec: "../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec"
RCTRequired:
:path: "../node_modules/react-native/Libraries/RCTRequired"
RCTTypeSafety:
:path: "../node_modules/react-native/Libraries/TypeSafety"
React:
:path: "../node_modules/react-native/"
React-callinvoker:
:path: "../node_modules/react-native/ReactCommon/callinvoker"
React-Core:
:path: "../node_modules/react-native/"
React-CoreModules:
:path: "../node_modules/react-native/React/CoreModules"
React-cxxreact:
:path: "../node_modules/react-native/ReactCommon/cxxreact"
React-jsi:
:path: "../node_modules/react-native/ReactCommon/jsi"
React-jsiexecutor:
:path: "../node_modules/react-native/ReactCommon/jsiexecutor"
React-jsinspector:
:path: "../node_modules/react-native/ReactCommon/jsinspector"
react-native-camera:
:path: "../node_modules/react-native-camera"
react-native-geolocation:
:path: "../node_modules/@react-native-community/geolocation"
react-native-get-random-values:
:path: "../node_modules/react-native-get-random-values"
react-native-image-picker:
:path: "../node_modules/react-native-image-picker"
react-native-maps:
:path: "../node_modules/react-native-maps"
react-native-safe-area-context:
:path: "../node_modules/react-native-safe-area-context"
React-perflogger:
:path: "../node_modules/react-native/ReactCommon/reactperflogger"
React-RCTActionSheet:
:path: "../node_modules/react-native/Libraries/ActionSheetIOS"
React-RCTAnimation:
:path: "../node_modules/react-native/Libraries/NativeAnimation"
React-RCTBlob:
:path: "../node_modules/react-native/Libraries/Blob"
React-RCTImage:
:path: "../node_modules/react-native/Libraries/Image"
React-RCTLinking:
:path: "../node_modules/react-native/Libraries/LinkingIOS"
React-RCTNetwork:
:path: "../node_modules/react-native/Libraries/Network"
React-RCTSettings:
:path: "../node_modules/react-native/Libraries/Settings"
React-RCTText:
:path: "../node_modules/react-native/Libraries/Text"
React-RCTVibration:
:path: "../node_modules/react-native/Libraries/Vibration"
React-runtimeexecutor:
:path: "../node_modules/react-native/ReactCommon/runtimeexecutor"
ReactCommon:
:path: "../node_modules/react-native/ReactCommon"
ReactNativeART:
:path: "../node_modules/@react-native-community/art"
RNDeviceInfo:
:path: "../node_modules/react-native-device-info"
RNGestureHandler:
:path: "../node_modules/react-native-gesture-handler"
RNKeychain:
:path: "../node_modules/react-native-keychain"
RNPermissions:
:path: "../node_modules/react-native-permissions"
RNReanimated:
:path: "../node_modules/react-native-reanimated"
RNScreens:
:path: "../node_modules/react-native-screens"
RNSensors:
:path: "../node_modules/react-native-sensors"
RNSVG:
:path: "../node_modules/react-native-svg"
RNVectorIcons:
:path: "../node_modules/react-native-vector-icons"
Yoga:
:path: "../node_modules/react-native/ReactCommon/yoga"
SPEC CHECKSUMS:
boost-for-react-native: 39c7adb57c4e60d6c5479dd8623128eb5b3f0f2c
BVLinearGradient: e3aad03778a456d77928f594a649e96995f1c872
CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99
DoubleConversion: cf9b38bf0b2d048436d9a82ad2abe1404f11e7de
FBLazyVector: 49cbe4b43e445b06bf29199b6ad2057649e4c8f5
FBReactNativeSpec: 916258a038154431ac1de27bf67b330837a30d10
Flipper: d3da1aa199aad94455ae725e9f3aa43f3ec17021
Flipper-DoubleConversion: 38631e41ef4f9b12861c67d17cb5518d06badc41
Flipper-Folly: f7a3caafbd74bda4827954fd7a6e000e36355489
Flipper-Glog: 1dfd6abf1e922806c52ceb8701a3599a79a200a6
Flipper-PeerTalk: 116d8f857dc6ef55c7a5a75ea3ceaafe878aadc9
Flipper-RSocket: 602921fee03edacf18f5d6f3d3594ba477f456e5
FlipperKit: 8a20b5c5fcf9436cac58551dc049867247f64b00
glog: 73c2498ac6884b13ede40eda8228cb1eee9d9d62
libevent: 4049cae6c81cdb3654a443be001fb9bdceff7913
OpenSSL-Universal: 1aa4f6a6ee7256b83db99ec1ccdaa80d10f9af9b
Permission-Camera: 0d2d15352e9c54c3ea8686c8c21fb1a9edf3431b
RCT-Folly: ec7a233ccc97cc556cf7237f0db1ff65b986f27c
RCTRequired: 2f8cb5b7533219bf4218a045f92768129cf7050a
RCTTypeSafety: 512728b73549e72ad7330b92f3d42936f2a4de5b
React: 98eac01574128a790f0bbbafe2d1a8607291ac24
React-callinvoker: def3f7fae16192df68d9b69fd4bbb59092ee36bc
React-Core: 70a52aa5dbe9b83befae82038451a7df9fd54c5a
React-CoreModules: 052edef46117862e2570eb3a0f06d81c61d2c4b8
React-cxxreact: c1dc71b30653cfb4770efdafcbdc0ad6d388baab
React-jsi: 74341196d9547cbcbcfa4b3bbbf03af56431d5a1
React-jsiexecutor: 06a9c77b56902ae7ffcdd7a4905f664adc5d237b
React-jsinspector: 0ae35a37b20d5e031eb020a69cc5afdbd6406301
react-native-camera: c2cb270b2546bb6d99352455676cd01a1cbeb1d5
react-native-geolocation: cbd9d6bd06bac411eed2671810f454d4908484a8
react-native-get-random-values: f0fc24a5887a3341589515a86282a574407b59e4
react-native-image-picker: 5b2f1ea1f9230b131abbfb8a4aa1eb209aba9ed9
react-native-maps: f4b89da81626ad7f151a8bfcb79733295d31ce5c
react-native-safe-area-context: e471852c5ed67eea4b10c5d9d43c1cebae3b231d
React-perflogger: 9c547d8f06b9bf00cb447f2b75e8d7f19b7e02af
React-RCTActionSheet: 3080b6e12e0e1a5b313c8c0050699b5c794a1b11
React-RCTAnimation: 3f96f21a497ae7dabf4d2f150ee43f906aaf516f
React-RCTBlob: 283b8e5025e7f954176bc48164f846909002f3ed
React-RCTImage: 5088a484faac78f2d877e1b79125d3bb1ea94a16
React-RCTLinking: 5e8fbb3e9a8bc2e4e3eb15b1eb8bda5fcac27b8c
React-RCTNetwork: 38ec277217b1e841d5e6a1fa78da65b9212ccb28
React-RCTSettings: 242d6e692108c3de4f3bb74b7586a8799e9ab070
React-RCTText: 8746736ac8eb5a4a74719aa695b7a236a93a83d2
React-RCTVibration: 0fd6b21751a33cb72fce1a4a33ab9678416d307a
React-runtimeexecutor: cad74a1eaa53ee6e7a3620231939d8fe2c6afcf0
ReactCommon: cfe2b7fd20e0dbd2d1185cd7d8f99633fbc5ff05
ReactNativeART: f003b07dfa7098aa419ed95b69560923440b1eee
RNDeviceInfo: e92b781f4af9d0faebe00695ffe5ce5b7671ec0f
RNGestureHandler: a479ebd5ed4221a810967000735517df0d2db211
RNKeychain: b8e0711b959a19c5b057d1e970d3c83d159b6da5
RNPermissions: eb94f9fdc0a8ecd02fcce0676d56ffb1395d41e1
RNReanimated: 64f6c5789f82818c07ba3c71864b73619cb23c76
RNScreens: f7ad633b2e0190b77b6a7aab7f914fad6f198d8d
RNSensors: aefce56de71b313fbdeb6d26c024d7fc9258373f
RNSVG: ce9d996113475209013317e48b05c21ee988d42e
RNVectorIcons: 31cebfcf94e8cf8686eb5303ae0357da64d7a5a4
Yoga: 8c8436d4171c87504c648ae23b1d81242bdf3bbf
YogaKit: f782866e155069a2cca2517aafea43200b01fd5a
PODFILE CHECKSUM: 09b919162b47dc6eb1d81cc511f41e90d34b77e8
COCOAPODS: 1.10.1

Просмотреть файл

@ -0,0 +1,4 @@
//
// Use this file to import your target's public headers that you would like to expose to Swift.
//

Просмотреть файл

@ -0,0 +1,698 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 54;
objects = {
/* Begin PBXBuildFile section */
00E356F31AD99517003FC87E /* my_first_pnp_deviceTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* my_first_pnp_deviceTests.m */; };
13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.m */; };
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };
220F32EA28F3DF9B2DF11CD2 /* libPods-my_first_pnp_device.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 05366595F36F300B95145CC2 /* libPods-my_first_pnp_device.a */; };
4A14B5A025FF78810056CDB3 /* Charts.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A14B59F25FF78810056CDB3 /* Charts.swift */; };
81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */; };
EB0046AEC35627DBD1408441 /* libPods-my_first_pnp_device-my_first_pnp_deviceTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 93E589CA1B818E56A179DD6C /* libPods-my_first_pnp_device-my_first_pnp_deviceTests.a */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
00E356F41AD99517003FC87E /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */;
proxyType = 1;
remoteGlobalIDString = 13B07F861A680F5B00A75B9A;
remoteInfo = my_first_pnp_device;
};
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
00E356EE1AD99517003FC87E /* my_first_pnp_deviceTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = my_first_pnp_deviceTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
00E356F11AD99517003FC87E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
00E356F21AD99517003FC87E /* my_first_pnp_deviceTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = my_first_pnp_deviceTests.m; sourceTree = "<group>"; };
05366595F36F300B95145CC2 /* libPods-my_first_pnp_device.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-my_first_pnp_device.a"; sourceTree = BUILT_PRODUCTS_DIR; };
13B07F961A680F5B00A75B9A /* my_first_pnp_device.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = my_first_pnp_device.app; sourceTree = BUILT_PRODUCTS_DIR; };
13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = my_first_pnp_device/AppDelegate.h; sourceTree = "<group>"; };
13B07FB01A68108700A75B9A /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AppDelegate.m; path = my_first_pnp_device/AppDelegate.m; sourceTree = "<group>"; };
13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = my_first_pnp_device/Images.xcassets; sourceTree = "<group>"; };
13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = my_first_pnp_device/Info.plist; sourceTree = "<group>"; };
13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = my_first_pnp_device/main.m; sourceTree = "<group>"; };
3DDA8450741F9EDB0FFEC2A6 /* Pods-my_first_pnp_device-my_first_pnp_deviceTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-my_first_pnp_device-my_first_pnp_deviceTests.release.xcconfig"; path = "Target Support Files/Pods-my_first_pnp_device-my_first_pnp_deviceTests/Pods-my_first_pnp_device-my_first_pnp_deviceTests.release.xcconfig"; sourceTree = "<group>"; };
4A14B59E25FF78800056CDB3 /* my_first_pnp_device-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "my_first_pnp_device-Bridging-Header.h"; sourceTree = "<group>"; };
4A14B59F25FF78810056CDB3 /* Charts.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Charts.swift; sourceTree = "<group>"; };
7190CFFA99BDCF08BD0B7BBD /* Pods-my_first_pnp_device.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-my_first_pnp_device.release.xcconfig"; path = "Target Support Files/Pods-my_first_pnp_device/Pods-my_first_pnp_device.release.xcconfig"; sourceTree = "<group>"; };
8166B076FEEE5FA0B4046143 /* Pods-my_first_pnp_device.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-my_first_pnp_device.debug.xcconfig"; path = "Target Support Files/Pods-my_first_pnp_device/Pods-my_first_pnp_device.debug.xcconfig"; sourceTree = "<group>"; };
81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = LaunchScreen.storyboard; path = my_first_pnp_device/LaunchScreen.storyboard; sourceTree = "<group>"; };
93E589CA1B818E56A179DD6C /* libPods-my_first_pnp_device-my_first_pnp_deviceTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-my_first_pnp_device-my_first_pnp_deviceTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
9880DA3DD6DDDDE6993EBAE0 /* Pods-my_first_pnp_device-my_first_pnp_deviceTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-my_first_pnp_device-my_first_pnp_deviceTests.debug.xcconfig"; path = "Target Support Files/Pods-my_first_pnp_device-my_first_pnp_deviceTests/Pods-my_first_pnp_device-my_first_pnp_deviceTests.debug.xcconfig"; sourceTree = "<group>"; };
ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
00E356EB1AD99517003FC87E /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
EB0046AEC35627DBD1408441 /* libPods-my_first_pnp_device-my_first_pnp_deviceTests.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
13B07F8C1A680F5B00A75B9A /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
220F32EA28F3DF9B2DF11CD2 /* libPods-my_first_pnp_device.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
00E356EF1AD99517003FC87E /* my_first_pnp_deviceTests */ = {
isa = PBXGroup;
children = (
00E356F21AD99517003FC87E /* my_first_pnp_deviceTests.m */,
00E356F01AD99517003FC87E /* Supporting Files */,
);
path = my_first_pnp_deviceTests;
sourceTree = "<group>";
};
00E356F01AD99517003FC87E /* Supporting Files */ = {
isa = PBXGroup;
children = (
00E356F11AD99517003FC87E /* Info.plist */,
);
name = "Supporting Files";
sourceTree = "<group>";
};
13B07FAE1A68108700A75B9A /* my_first_pnp_device */ = {
isa = PBXGroup;
children = (
13B07FAF1A68108700A75B9A /* AppDelegate.h */,
13B07FB01A68108700A75B9A /* AppDelegate.m */,
13B07FB51A68108700A75B9A /* Images.xcassets */,
13B07FB61A68108700A75B9A /* Info.plist */,
81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */,
13B07FB71A68108700A75B9A /* main.m */,
4A14B59F25FF78810056CDB3 /* Charts.swift */,
4A14B59E25FF78800056CDB3 /* my_first_pnp_device-Bridging-Header.h */,
);
name = my_first_pnp_device;
sourceTree = "<group>";
};
2D16E6871FA4F8E400B85C8A /* Frameworks */ = {
isa = PBXGroup;
children = (
ED297162215061F000B7C4FE /* JavaScriptCore.framework */,
05366595F36F300B95145CC2 /* libPods-my_first_pnp_device.a */,
93E589CA1B818E56A179DD6C /* libPods-my_first_pnp_device-my_first_pnp_deviceTests.a */,
);
name = Frameworks;
sourceTree = "<group>";
};
6678D5C939B9D8E03D5C4EBA /* Pods */ = {
isa = PBXGroup;
children = (
8166B076FEEE5FA0B4046143 /* Pods-my_first_pnp_device.debug.xcconfig */,
7190CFFA99BDCF08BD0B7BBD /* Pods-my_first_pnp_device.release.xcconfig */,
9880DA3DD6DDDDE6993EBAE0 /* Pods-my_first_pnp_device-my_first_pnp_deviceTests.debug.xcconfig */,
3DDA8450741F9EDB0FFEC2A6 /* Pods-my_first_pnp_device-my_first_pnp_deviceTests.release.xcconfig */,
);
path = Pods;
sourceTree = "<group>";
};
832341AE1AAA6A7D00B99B32 /* Libraries */ = {
isa = PBXGroup;
children = (
);
name = Libraries;
sourceTree = "<group>";
};
83CBB9F61A601CBA00E9B192 = {
isa = PBXGroup;
children = (
13B07FAE1A68108700A75B9A /* my_first_pnp_device */,
832341AE1AAA6A7D00B99B32 /* Libraries */,
00E356EF1AD99517003FC87E /* my_first_pnp_deviceTests */,
83CBBA001A601CBA00E9B192 /* Products */,
2D16E6871FA4F8E400B85C8A /* Frameworks */,
6678D5C939B9D8E03D5C4EBA /* Pods */,
);
indentWidth = 2;
sourceTree = "<group>";
tabWidth = 2;
usesTabs = 0;
};
83CBBA001A601CBA00E9B192 /* Products */ = {
isa = PBXGroup;
children = (
13B07F961A680F5B00A75B9A /* my_first_pnp_device.app */,
00E356EE1AD99517003FC87E /* my_first_pnp_deviceTests.xctest */,
);
name = Products;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
00E356ED1AD99517003FC87E /* my_first_pnp_deviceTests */ = {
isa = PBXNativeTarget;
buildConfigurationList = 00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget "my_first_pnp_deviceTests" */;
buildPhases = (
E8655E970C2C933F420282CC /* [CP] Check Pods Manifest.lock */,
00E356EA1AD99517003FC87E /* Sources */,
00E356EB1AD99517003FC87E /* Frameworks */,
00E356EC1AD99517003FC87E /* Resources */,
EE82BEE620DFD428B4DBA593 /* [CP] Embed Pods Frameworks */,
D0CB8F520DAE00F0C0A0F955 /* [CP] Copy Pods Resources */,
);
buildRules = (
);
dependencies = (
00E356F51AD99517003FC87E /* PBXTargetDependency */,
);
name = my_first_pnp_deviceTests;
productName = my_first_pnp_deviceTests;
productReference = 00E356EE1AD99517003FC87E /* my_first_pnp_deviceTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
13B07F861A680F5B00A75B9A /* my_first_pnp_device */ = {
isa = PBXNativeTarget;
buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "my_first_pnp_device" */;
buildPhases = (
26D93C0EC1B9F32BD5943622 /* [CP] Check Pods Manifest.lock */,
FD10A7F022414F080027D42C /* Start Packager */,
13B07F871A680F5B00A75B9A /* Sources */,
13B07F8C1A680F5B00A75B9A /* Frameworks */,
13B07F8E1A680F5B00A75B9A /* Resources */,
00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */,
DCD8EFB6C40EF666367B2D07 /* [CP] Embed Pods Frameworks */,
5A6507A588E6EC44B3F7E645 /* [CP] Copy Pods Resources */,
);
buildRules = (
);
dependencies = (
);
name = my_first_pnp_device;
productName = my_first_pnp_device;
productReference = 13B07F961A680F5B00A75B9A /* my_first_pnp_device.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
83CBB9F71A601CBA00E9B192 /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 1210;
TargetAttributes = {
00E356ED1AD99517003FC87E = {
CreatedOnToolsVersion = 6.2;
TestTargetID = 13B07F861A680F5B00A75B9A;
};
13B07F861A680F5B00A75B9A = {
LastSwiftMigration = 1230;
};
};
};
buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "my_first_pnp_device" */;
compatibilityVersion = "Xcode 12.0";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 83CBB9F61A601CBA00E9B192;
productRefGroup = 83CBBA001A601CBA00E9B192 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
13B07F861A680F5B00A75B9A /* my_first_pnp_device */,
00E356ED1AD99517003FC87E /* my_first_pnp_deviceTests */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
00E356EC1AD99517003FC87E /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
13B07F8E1A680F5B00A75B9A /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */,
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Bundle React Native code and images";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "set -e\n\nexport NODE_BINARY=node\n../node_modules/react-native/scripts/react-native-xcode.sh\n";
};
26D93C0EC1B9F32BD5943622 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputFileListPaths = (
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-my_first_pnp_device-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
5A6507A588E6EC44B3F7E645 /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-my_first_pnp_device/Pods-my_first_pnp_device-resources-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Copy Pods Resources";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-my_first_pnp_device/Pods-my_first_pnp_device-resources-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-my_first_pnp_device/Pods-my_first_pnp_device-resources.sh\"\n";
showEnvVarsInLog = 0;
};
D0CB8F520DAE00F0C0A0F955 /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-my_first_pnp_device-my_first_pnp_deviceTests/Pods-my_first_pnp_device-my_first_pnp_deviceTests-resources-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Copy Pods Resources";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-my_first_pnp_device-my_first_pnp_deviceTests/Pods-my_first_pnp_device-my_first_pnp_deviceTests-resources-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-my_first_pnp_device-my_first_pnp_deviceTests/Pods-my_first_pnp_device-my_first_pnp_deviceTests-resources.sh\"\n";
showEnvVarsInLog = 0;
};
DCD8EFB6C40EF666367B2D07 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-my_first_pnp_device/Pods-my_first_pnp_device-frameworks-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-my_first_pnp_device/Pods-my_first_pnp_device-frameworks-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-my_first_pnp_device/Pods-my_first_pnp_device-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
E8655E970C2C933F420282CC /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputFileListPaths = (
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-my_first_pnp_device-my_first_pnp_deviceTests-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
EE82BEE620DFD428B4DBA593 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-my_first_pnp_device-my_first_pnp_deviceTests/Pods-my_first_pnp_device-my_first_pnp_deviceTests-frameworks-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-my_first_pnp_device-my_first_pnp_deviceTests/Pods-my_first_pnp_device-my_first_pnp_deviceTests-frameworks-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-my_first_pnp_device-my_first_pnp_deviceTests/Pods-my_first_pnp_device-my_first_pnp_deviceTests-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
FD10A7F022414F080027D42C /* Start Packager */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
);
name = "Start Packager";
outputFileListPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "export RCT_METRO_PORT=\"${RCT_METRO_PORT:=8081}\"\necho \"export RCT_METRO_PORT=${RCT_METRO_PORT}\" > \"${SRCROOT}/../node_modules/react-native/scripts/.packager.env\"\nif [ -z \"${RCT_NO_LAUNCH_PACKAGER+xxx}\" ] ; then\n if nc -w 5 -z localhost ${RCT_METRO_PORT} ; then\n if ! curl -s \"http://localhost:${RCT_METRO_PORT}/status\" | grep -q \"packager-status:running\" ; then\n echo \"Port ${RCT_METRO_PORT} already in use, packager is either not running or not running correctly\"\n exit 2\n fi\n else\n open \"$SRCROOT/../node_modules/react-native/scripts/launchPackager.command\" || echo \"Can't start packager automatically\"\n fi\nfi\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
00E356EA1AD99517003FC87E /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
00E356F31AD99517003FC87E /* my_first_pnp_deviceTests.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
13B07F871A680F5B00A75B9A /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
4A14B5A025FF78810056CDB3 /* Charts.swift in Sources */,
13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */,
13B07FC11A68108700A75B9A /* main.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
00E356F51AD99517003FC87E /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 13B07F861A680F5B00A75B9A /* my_first_pnp_device */;
targetProxy = 00E356F41AD99517003FC87E /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin XCBuildConfiguration section */
00E356F61AD99517003FC87E /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 9880DA3DD6DDDDE6993EBAE0 /* Pods-my_first_pnp_device-my_first_pnp_deviceTests.debug.xcconfig */;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
BUNDLE_LOADER = "$(TEST_HOST)";
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
INFOPLIST_FILE = my_first_pnp_deviceTests/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
OTHER_LDFLAGS = (
"-ObjC",
"-lc++",
"$(inherited)",
);
PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = "$(TARGET_NAME)";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/my_first_pnp_device.app/my_first_pnp_device";
};
name = Debug;
};
00E356F71AD99517003FC87E /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 3DDA8450741F9EDB0FFEC2A6 /* Pods-my_first_pnp_device-my_first_pnp_deviceTests.release.xcconfig */;
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
BUNDLE_LOADER = "$(TEST_HOST)";
COPY_PHASE_STRIP = NO;
INFOPLIST_FILE = my_first_pnp_deviceTests/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
OTHER_LDFLAGS = (
"-ObjC",
"-lc++",
"$(inherited)",
);
PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = "$(TARGET_NAME)";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/my_first_pnp_device.app/my_first_pnp_device";
};
name = Release;
};
13B07F941A680F5B00A75B9A /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 8166B076FEEE5FA0B4046143 /* Pods-my_first_pnp_device.debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = 32R2QHB9WJ;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = my_first_pnp_device/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",
"-lc++",
);
PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = my_first_pnp_device;
SWIFT_OBJC_BRIDGING_HEADER = "my_first_pnp_device-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
};
name = Debug;
};
13B07F951A680F5B00A75B9A /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7190CFFA99BDCF08BD0B7BBD /* Pods-my_first_pnp_device.release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = 32R2QHB9WJ;
INFOPLIST_FILE = my_first_pnp_device/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",
"-lc++",
);
PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = my_first_pnp_device;
SWIFT_OBJC_BRIDGING_HEADER = "my_first_pnp_device-Bridging-Header.h";
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
};
name = Release;
};
83CBBA201A601CBA00E9B192 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
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;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = "arm64 ";
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
LD_RUNPATH_SEARCH_PATHS = (
/usr/lib/swift,
"$(inherited)",
);
LIBRARY_SEARCH_PATHS = (
"\"$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)\"",
"\"$(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)\"",
"\"$(inherited)\"",
);
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
};
name = Debug;
};
83CBBA211A601CBA00E9B192 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
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;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = YES;
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = "arm64 ";
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
LD_RUNPATH_SEARCH_PATHS = (
/usr/lib/swift,
"$(inherited)",
);
LIBRARY_SEARCH_PATHS = (
"\"$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)\"",
"\"$(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)\"",
"\"$(inherited)\"",
);
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
VALIDATE_PRODUCT = YES;
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget "my_first_pnp_deviceTests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
00E356F61AD99517003FC87E /* Debug */,
00E356F71AD99517003FC87E /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "my_first_pnp_device" */ = {
isa = XCConfigurationList;
buildConfigurations = (
13B07F941A680F5B00A75B9A /* Debug */,
13B07F951A680F5B00A75B9A /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "my_first_pnp_device" */ = {
isa = XCConfigurationList;
buildConfigurations = (
83CBBA201A601CBA00E9B192 /* Debug */,
83CBBA211A601CBA00E9B192 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 83CBB9F71A601CBA00E9B192 /* Project object */;
}

Просмотреть файл

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:">
</FileRef>
</Workspace>

Просмотреть файл

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>

Просмотреть файл

@ -0,0 +1,88 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1210"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "13B07F861A680F5B00A75B9A"
BuildableName = "my_first_pnp_device.app"
BlueprintName = "my_first_pnp_device"
ReferencedContainer = "container:my_first_pnp_device.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "00E356ED1AD99517003FC87E"
BuildableName = "my_first_pnp_deviceTests.xctest"
BlueprintName = "my_first_pnp_deviceTests"
ReferencedContainer = "container:my_first_pnp_device.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "13B07F861A680F5B00A75B9A"
BuildableName = "my_first_pnp_device.app"
BlueprintName = "my_first_pnp_device"
ReferencedContainer = "container:my_first_pnp_device.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "13B07F861A680F5B00A75B9A"
BuildableName = "my_first_pnp_device.app"
BlueprintName = "my_first_pnp_device"
ReferencedContainer = "container:my_first_pnp_device.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

10
ios/my_first_pnp_device.xcworkspace/contents.xcworkspacedata сгенерированный Normal file
Просмотреть файл

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:my_first_pnp_device.xcodeproj">
</FileRef>
<FileRef
location = "group:Pods/Pods.xcodeproj">
</FileRef>
</Workspace>

Просмотреть файл

@ -0,0 +1,8 @@
#import <React/RCTBridgeDelegate.h>
#import <UIKit/UIKit.h>
@interface AppDelegate : UIResponder <UIApplicationDelegate, RCTBridgeDelegate>
@property (nonatomic, strong) UIWindow *window;
@end

Просмотреть файл

@ -0,0 +1,62 @@
#import "AppDelegate.h"
#import <React/RCTBridge.h>
#import <React/RCTBundleURLProvider.h>
#import <React/RCTRootView.h>
#ifdef FB_SONARKIT_ENABLED
#import <FlipperKit/FlipperClient.h>
#import <FlipperKitLayoutPlugin/FlipperKitLayoutPlugin.h>
#import <FlipperKitUserDefaultsPlugin/FKUserDefaultsPlugin.h>
#import <FlipperKitNetworkPlugin/FlipperKitNetworkPlugin.h>
#import <SKIOSNetworkPlugin/SKIOSNetworkAdapter.h>
#import <FlipperKitReactPlugin/FlipperKitReactPlugin.h>
static void InitializeFlipper(UIApplication *application) {
FlipperClient *client = [FlipperClient sharedClient];
SKDescriptorMapper *layoutDescriptorMapper = [[SKDescriptorMapper alloc] initWithDefaults];
[client addPlugin:[[FlipperKitLayoutPlugin alloc] initWithRootNode:application withDescriptorMapper:layoutDescriptorMapper]];
[client addPlugin:[[FKUserDefaultsPlugin alloc] initWithSuiteName:nil]];
[client addPlugin:[FlipperKitReactPlugin new]];
[client addPlugin:[[FlipperKitNetworkPlugin alloc] initWithNetworkAdapter:[SKIOSNetworkAdapter new]]];
[client start];
}
#endif
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
#ifdef FB_SONARKIT_ENABLED
InitializeFlipper(application);
#endif
RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions];
RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge
moduleName:@"my_first_pnp_device"
initialProperties:nil];
if (@available(iOS 13.0, *)) {
rootView.backgroundColor = [UIColor systemBackgroundColor];
} else {
rootView.backgroundColor = [UIColor whiteColor];
}
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
UIViewController *rootViewController = [UIViewController new];
rootViewController.view = rootView;
self.window.rootViewController = rootViewController;
[self.window makeKeyAndVisible];
return YES;
}
- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
{
#if DEBUG
return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];
#else
return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
#endif
}
@end

Просмотреть файл

@ -0,0 +1,116 @@
{
"images" : [
{
"filename" : "iotc_logo-20@2x.png",
"idiom" : "iphone",
"scale" : "2x",
"size" : "20x20"
},
{
"filename" : "iotc_logo-20@3x.png",
"idiom" : "iphone",
"scale" : "3x",
"size" : "20x20"
},
{
"filename" : "iotc_logo-29@2x.png",
"idiom" : "iphone",
"scale" : "2x",
"size" : "29x29"
},
{
"filename" : "iotc_logo-29@3x.png",
"idiom" : "iphone",
"scale" : "3x",
"size" : "29x29"
},
{
"filename" : "iotc_logo-40@2x.png",
"idiom" : "iphone",
"scale" : "2x",
"size" : "40x40"
},
{
"filename" : "iotc_logo-40@3x.png",
"idiom" : "iphone",
"scale" : "3x",
"size" : "40x40"
},
{
"filename" : "iotc_logo-60@2x.png",
"idiom" : "iphone",
"scale" : "2x",
"size" : "60x60"
},
{
"filename" : "iotc_logo-60@3x.png",
"idiom" : "iphone",
"scale" : "3x",
"size" : "60x60"
},
{
"filename" : "iotc_logo-20.png",
"idiom" : "ipad",
"scale" : "1x",
"size" : "20x20"
},
{
"filename" : "iotc_logo-20@2x.png",
"idiom" : "ipad",
"scale" : "2x",
"size" : "20x20"
},
{
"filename" : "iotc_logo-29.png",
"idiom" : "ipad",
"scale" : "1x",
"size" : "29x29"
},
{
"filename" : "iotc_logo-29@2x.png",
"idiom" : "ipad",
"scale" : "2x",
"size" : "29x29"
},
{
"filename" : "iotc_logo-40.png",
"idiom" : "ipad",
"scale" : "1x",
"size" : "40x40"
},
{
"filename" : "iotc_logo-40@2x.png",
"idiom" : "ipad",
"scale" : "2x",
"size" : "40x40"
},
{
"filename" : "iotc_logo-76.png",
"idiom" : "ipad",
"scale" : "1x",
"size" : "76x76"
},
{
"filename" : "iotc_logo-76@2x.png",
"idiom" : "ipad",
"scale" : "2x",
"size" : "76x76"
},
{
"filename" : "iotc_logo-83.5@2x.png",
"idiom" : "ipad",
"scale" : "2x",
"size" : "83.5x83.5"
},
{
"filename" : "iotc_logo-1024.png",
"idiom" : "ios-marketing",
"scale" : "1x",
"size" : "1024x1024"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 77 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 2.0 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 3.0 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 3.8 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 2.5 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 3.6 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 4.9 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 3.0 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 4.7 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 5.7 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 5.7 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 8.6 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 4.4 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 7.5 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 7.9 KiB

Просмотреть файл

@ -0,0 +1,6 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}

Просмотреть файл

@ -0,0 +1,67 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleDisplayName</key>
<string>My First PnP Device</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSExceptionDomains</key>
<dict>
<key>localhost</key>
<dict>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
</dict>
</dict>
</dict>
<key>NSCameraUsageDescription</key>
<string>"My First PnP Device" needs access to your camera for scanning QR codes</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<true/>
<key>NSLocationWhenInUseUsageDescription</key>
<string>"My First PnP Device" needs access to your location</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>"My First PnP Device" wants to access your gallery to upload pictures</string>
<key>UIAppFonts</key>
<array>
<string>Ionicons.ttf</string>
<string>MaterialIcons.ttf</string>
<string>MaterialCommunityIcons.ttf</string>
</array>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
</dict>
</plist>

Просмотреть файл

@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="15702" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<device id="retina4_7" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="15704"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="EHf-IW-A2E">
<objects>
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="my_first_pnp_device" textAlignment="center" lineBreakMode="middleTruncation" baselineAdjustment="alignBaselines" minimumFontSize="18" translatesAutoresizingMaskIntoConstraints="NO" id="GJd-Yh-RWb">
<rect key="frame" x="0.0" y="202" width="375" height="43"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="36"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Powered by React Native" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="9" translatesAutoresizingMaskIntoConstraints="NO" id="MN2-I3-ftu">
<rect key="frame" x="0.0" y="626" width="375" height="21"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
<constraints>
<constraint firstItem="Bcu-3y-fUS" firstAttribute="bottom" secondItem="MN2-I3-ftu" secondAttribute="bottom" constant="20" id="OZV-Vh-mqD"/>
<constraint firstItem="Bcu-3y-fUS" firstAttribute="centerX" secondItem="GJd-Yh-RWb" secondAttribute="centerX" id="Q3B-4B-g5h"/>
<constraint firstItem="MN2-I3-ftu" firstAttribute="centerX" secondItem="Bcu-3y-fUS" secondAttribute="centerX" id="akx-eg-2ui"/>
<constraint firstItem="MN2-I3-ftu" firstAttribute="leading" secondItem="Bcu-3y-fUS" secondAttribute="leading" id="i1E-0Y-4RG"/>
<constraint firstItem="GJd-Yh-RWb" firstAttribute="centerY" secondItem="Ze5-6b-2t3" secondAttribute="bottom" multiplier="1/3" constant="1" id="moa-c2-u7t"/>
<constraint firstItem="GJd-Yh-RWb" firstAttribute="leading" secondItem="Bcu-3y-fUS" secondAttribute="leading" symbolic="YES" id="x7j-FC-K8j"/>
</constraints>
<viewLayoutGuide key="safeArea" id="Bcu-3y-fUS"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="52.173913043478265" y="375"/>
</scene>
</scenes>
</document>

Просмотреть файл

@ -0,0 +1,9 @@
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
int main(int argc, char * argv[]) {
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}

Просмотреть файл

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>

Просмотреть файл

@ -0,0 +1,65 @@
#import <UIKit/UIKit.h>
#import <XCTest/XCTest.h>
#import <React/RCTLog.h>
#import <React/RCTRootView.h>
#define TIMEOUT_SECONDS 600
#define TEXT_TO_LOOK_FOR @"Welcome to React"
@interface my_first_pnp_deviceTests : XCTestCase
@end
@implementation my_first_pnp_deviceTests
- (BOOL)findSubviewInView:(UIView *)view matching:(BOOL(^)(UIView *view))test
{
if (test(view)) {
return YES;
}
for (UIView *subview in [view subviews]) {
if ([self findSubviewInView:subview matching:test]) {
return YES;
}
}
return NO;
}
- (void)testRendersWelcomeScreen
{
UIViewController *vc = [[[RCTSharedApplication() delegate] window] rootViewController];
NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS];
BOOL foundElement = NO;
__block NSString *redboxError = nil;
#ifdef DEBUG
RCTSetLogFunction(^(RCTLogLevel level, RCTLogSource source, NSString *fileName, NSNumber *lineNumber, NSString *message) {
if (level >= RCTLogLevelError) {
redboxError = message;
}
});
#endif
while ([date timeIntervalSinceNow] > 0 && !foundElement && !redboxError) {
[[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
[[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
foundElement = [self findSubviewInView:vc.view matching:^BOOL(UIView *view) {
if ([view.accessibilityLabel isEqualToString:TEXT_TO_LOOK_FOR]) {
return YES;
}
return NO;
}];
}
#ifdef DEBUG
RCTSetLogFunction(RCTDefaultLogFunction);
#endif
XCTAssertNil(redboxError, @"RedBox error: %@", redboxError);
XCTAssertTrue(foundElement, @"Couldn't find element with text '%@' in %d seconds", TEXT_TO_LOOK_FOR, TIMEOUT_SECONDS);
}
@end

22
metro.config.js Normal file
Просмотреть файл

@ -0,0 +1,22 @@
const { getDefaultConfig } = require('metro-config');
module.exports = (async () => {
const {
resolver: { sourceExts, assetExts },
} = await getDefaultConfig();
return {
transformer: {
getTransformOptions: async () => ({
transform: {
experimentalImportSupport: false,
inlineRequires: false,
},
}),
babelTransformerPath: require.resolve('react-native-svg-transformer'),
},
resolver: {
assetExts: assetExts.filter(ext => ext !== 'svg'),
sourceExts: [...sourceExts, 'svg'],
},
};
})();

10051
package-lock.json сгенерированный Normal file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

88
package.json Normal file
Просмотреть файл

@ -0,0 +1,88 @@
{
"name": "my_first_pnp_device",
"version": "0.0.1",
"private": true,
"scripts": {
"android": "react-native run-android",
"ios": "react-native run-ios",
"start": "react-native start",
"build": "npm run format && npm run lint && tsc",
"test": "jest",
"lint": "tsc --noEmit && eslint --ext .js,.jsx,.ts,.tsx ./src",
"podinstall": "node ./podinstall.js",
"postinstall": "npx jetify && npm run podinstall",
"format": "prettier --write src/"
},
"dependencies": {
"@react-native-community/art": "^1.2.0",
"@react-native-community/geolocation": "^2.0.2",
"@react-navigation/bottom-tabs": "^5.11.8",
"@react-navigation/native": "^5.9.3",
"@react-navigation/stack": "^5.14.3",
"events": "^3.3.0",
"react": "17.0.1",
"react-native": "0.64.0",
"react-native-animatable": "^1.3.3",
"react-native-azure-iotcentral-client": "^1.1.7",
"react-native-camera": "^3.43.0",
"react-native-charts-wrapper": "^0.5.7",
"react-native-circular-progress": "^1.3.7",
"react-native-device-info": "^8.0.5",
"react-native-elements": "^3.3.1",
"react-native-gesture-handler": "^1.10.3",
"react-native-get-random-values": "^1.6.0",
"react-native-image-picker": "^3.3.2",
"react-native-keychain": "^6.2.0",
"react-native-linear-gradient": "^2.5.6",
"react-native-maps": "^0.27.1",
"react-native-permissions": "^3.0.1",
"react-native-progress": "^4.1.2",
"react-native-qrcode-scanner": "^1.5.3",
"react-native-reanimated": "^2.0.0",
"react-native-safe-area-context": "^3.2.0",
"react-native-screens": "^2.18.1",
"react-native-sensors": "^7.2.0",
"react-native-svg": "^12.1.0",
"react-native-vector-icons": "^8.1.0"
},
"devDependencies": {
"@babel/core": "^7.12.9",
"@babel/runtime": "^7.12.5",
"@react-native-community/eslint-config": "^2.0.0",
"@types/react": "^17.0.3",
"@types/react-native": "^0.63.51",
"@types/react-native-charts-wrapper": "^0.5.1",
"@types/react-native-elements": "^0.18.0",
"@typescript-eslint/eslint-plugin": "^4.17.0",
"@typescript-eslint/parser": "^4.17.0",
"babel-jest": "^26.6.3",
"babel-plugin-module-resolver": "^4.1.0",
"eslint": "7.14.0",
"eslint-plugin-react": "^7.22.0",
"eslint-plugin-react-hooks": "^4.2.0",
"jest": "^26.6.3",
"metro-react-native-babel-preset": "^0.64.0",
"prettier": "^2.2.1",
"react-native-svg-transformer": "^0.14.3",
"react-test-renderer": "17.0.1",
"typescript": "^4.2.3"
},
"jest": {
"preset": "react-native",
"transform": {
"^.+\\.js$": "<rootDir>/node_modules/react-native/jest/preprocessor.js",
"\\.(ts|tsx)$": "ts-jest"
},
"globals": {
"ts-jest": {
"tsConfig": "tsconfig.jest.json"
}
},
"moduleFileExtensions": [
"ts",
"tsx",
"js"
],
"testRegex": "(/__tests__/.*|\\.(test|spec))\\.(ts|tsx|js)$"
}
}

21
podinstall.js Normal file
Просмотреть файл

@ -0,0 +1,21 @@
'use strict';
const exec = require('child_process').exec;
const path = require('path');
switch (process.platform) {
case 'darwin':
exec('pod install', { cwd: path.join(__dirname, 'ios') }, (err, stdout, stderr) => {
if (err) {
console.error(err);
}
if (stderr) {
console.error(stderr);
}
if (stdout) {
console.log(stdout);
}
});
break;
default:
break;
}

522
src/App.tsx Normal file
Просмотреть файл

@ -0,0 +1,522 @@
import React, {
useContext,
useState,
useRef,
useEffect,
useCallback,
} from 'react';
import {View, Platform, Alert} from 'react-native';
import Settings from './Settings';
import {
NavigationContainer,
DarkTheme,
DefaultTheme,
useTheme,
} from '@react-navigation/native';
import {createBottomTabNavigator} from '@react-navigation/bottom-tabs';
import {
Screens,
NavigationScreens,
NavigationParams,
NavigationProperty,
ScreenNames,
DATA_AVAILABLE_EVENT,
TELEMETRY,
PROPERTY,
ENABLE_DISABLE_COMMAND,
SET_FREQUENCY_COMMAND,
ItemProps,
} from './types';
import {SafeAreaProvider} from 'react-native-safe-area-context';
import {
LogsProvider,
StorageProvider,
IoTCProvider,
ThemeProvider,
ThemeContext,
ThemeMode,
} from 'contexts';
import LogoIcon from './assets/IotcLogo.svg';
import {Icon} from 'react-native-elements';
import {createStackNavigator, HeaderTitle} from '@react-navigation/stack';
import {camelToName, Text} from './components/typography';
import Insight, {ChartType} from './Insight';
import {Welcome} from './Welcome';
import Logs from './Logs';
import {
IIcon,
useIoTCentralClient,
useLogger,
useProperties,
useSensors,
useSimulation,
} from 'hooks';
import FileUpload from './FileUpload';
import {Registration} from './Registration';
import CardView from './CardView';
import {Loader} from './components/loader';
import {
IIoTCCommand,
IIoTCCommandResponse,
IIoTCProperty,
IoTCClient,
IOTC_EVENTS,
} from 'react-native-azure-iotcentral-client';
import {AVAILABLE_SENSORS} from 'sensors';
const Tab = createBottomTabNavigator<NavigationScreens>();
const Stack = createStackNavigator();
export default function App() {
const [initialized, setInitialized] = useState(false);
if (initialized) {
return (
<ThemeProvider>
<SafeAreaProvider>
<IoTCProvider>
<StorageProvider>
<LogsProvider>
<Navigation />
</LogsProvider>
</StorageProvider>
</IoTCProvider>
</SafeAreaProvider>
</ThemeProvider>
);
}
return <Welcome setInitialized={setInitialized} />;
}
const Navigation = React.memo(() => {
const {mode} = useContext(ThemeContext);
return (
<NavigationContainer
theme={mode === ThemeMode.DARK ? DarkTheme : DefaultTheme}>
<Stack.Navigator>
{/* @ts-ignore */}
<Stack.Screen
name="root"
options={({navigation}: {navigation: NavigationProperty}) => ({
headerTitle: () => null,
headerLeft: () => <Logo />,
headerRight: () => <Profile navigate={navigation.navigate} />,
})}
component={Root}
/>
<Stack.Screen
name="Insight"
component={Insight}
options={({route}) => {
let data = {};
if (route.params) {
const params = route.params as NavigationParams;
if (params.title) {
data = {...data, headerTitle: params.title};
}
if (params.backTitle) {
data = {...data, headerBackTitle: params.backTitle};
}
}
return data;
}}
/>
<Stack.Screen
name="Settings"
options={({navigation}: {navigation: NavigationProperty}) => ({
stackAnimation: 'flip',
headerTitle: Platform.select({
ios: undefined,
android: '',
}),
headerLeft: () => (
<BackButton goBack={navigation.goBack} title="Settings" />
),
})}
component={Settings}
/>
</Stack.Navigator>
</NavigationContainer>
);
});
const Root = React.memo(() => {
const [simulated] = useSimulation();
const [, append] = useLogger();
const [sensors, addSensorListener, removeSensorListener] = useSensors();
// const [healths, addHealthListener, removeHealthListener] = useHealth();
const {
loading: propertiesLoading,
properties,
updateProperty,
} = useProperties();
const onConnectionRefresh = useCallback(
async (client: IoTCClient) => {
await client.fetchTwin();
await client.sendProperty({
[PROPERTY]: {
__t: 'c',
...properties.reduce((obj, p) => ({...obj, [p.id]: p.value}), {}),
},
});
},
[properties],
);
const [iotcentralClient] = useIoTCentralClient(onConnectionRefresh);
// const { connect, addListener, removeListener } = useContext(IoTCContext);
// const { append } = useContext(LogsContext);
// const prevCredentials = usePrevious(credentials);
// connect client if credentials are retrieved
const iconsRef = useRef<{[x in ScreenNames]: IIcon}>({
[Screens.TELEMETRY_SCREEN]: Platform.select({
ios: {
name: 'stats-chart-outline',
type: 'ionicon',
},
android: {
name: 'chart-bar',
type: 'material-community',
},
}) as IIcon,
[Screens.PROPERTIES_SCREEN]: Platform.select({
ios: {
name: 'create-outline',
type: 'ionicon',
},
android: {
name: 'playlist-edit',
type: 'material-community',
},
}) as IIcon,
[Screens.HEALTH_SCREEN]: {
name: 'heartbeat',
type: 'font-awesome',
} as IIcon,
[Screens.FILE_UPLOAD_SCREEN]: Platform.select({
ios: {
name: 'cloud-upload-outline',
type: 'ionicon',
},
android: {
name: 'cloud-upload-outline',
type: 'material-community',
},
}) as IIcon,
[Screens.LOGS_SCREEN]: Platform.select({
ios: {
name: 'console',
type: 'material-community',
},
android: {
name: 'console',
type: 'material-community',
},
}) as IIcon,
});
const icons = iconsRef.current;
const sensorRef = useRef(sensors);
// const healthRef = useRef(healths);
const sendToCentralHandler = useCallback(
async (componentName: string, id: string, value: any) => {
if (iotcentralClient && iotcentralClient.isConnected()) {
await iotcentralClient.sendTelemetry(
{[id]: value},
{'$.sub': componentName},
);
}
},
[iotcentralClient],
);
const onCommandUpdate = useCallback(async (command: IIoTCCommand) => {
let data: any;
data = JSON.parse(command.requestPayload);
if (data.sensor) {
if (command.name === ENABLE_DISABLE_COMMAND) {
const sensor = sensorRef.current.find(s => s.id === data.sensor);
if (sensor) {
sensor.enable(data.enable ? data.enable : false);
await command.reply(IIoTCCommandResponse.SUCCESS, 'Enable');
}
} else if (command.name === SET_FREQUENCY_COMMAND) {
const sensor = sensorRef.current.find(s => s.id === data.sensor);
if (sensor) {
sensor.sendInterval(data.interval ? data.interval * 1000 : 5000);
await command.reply(IIoTCCommandResponse.SUCCESS, 'Frequency');
}
}
}
}, []);
const onPropUpdate = useCallback(
async (prop: IIoTCProperty) => {
let {name, value} = prop;
if (value.__t === 'c') {
// inside a component: TODO: change sdk
name = Object.keys(value).filter(v => v !== '__t')[0];
value = value[name];
}
updateProperty(name, value);
await prop.ack();
},
[updateProperty],
);
const sendTelemetryHandler = useCallback(
(id: string, value: any) => sendToCentralHandler(TELEMETRY, id, value),
[sendToCentralHandler],
);
// const sendHealthHandler = useCallback(
// (id: string, value: any) => sendToCentralHandler(HEALTH, id, value),
// [sendToCentralHandler],
// );
useEffect(() => {
const currentSensorRef = sensorRef.current;
// const currentHealthRef = healthRef.current;
if (iotcentralClient) {
currentSensorRef.forEach(s =>
addSensorListener(s.id, DATA_AVAILABLE_EVENT, sendTelemetryHandler),
);
append({
eventName: 'INFO',
eventData: 'Sensor initialized.',
});
// currentHealthRef.forEach(h =>
// addHealthListener(h.id, DATA_AVAILABLE_EVENT, sendHealthHandler),
// );
append({
eventName: 'INFO',
eventData: 'Health initialized.',
});
append({
eventName: 'INFO',
eventData: 'Properties initialized.',
});
iotcentralClient.on(IOTC_EVENTS.Commands, onCommandUpdate);
iotcentralClient.on(IOTC_EVENTS.Properties, onPropUpdate);
iotcentralClient.fetchTwin();
}
return () => {
currentSensorRef.forEach(s =>
removeSensorListener(s.id, DATA_AVAILABLE_EVENT, sendTelemetryHandler),
);
// currentHealthRef.forEach(h =>
// removeHealthListener(h.id, DATA_AVAILABLE_EVENT, sendHealthHandler),
// );
};
}, [
iotcentralClient,
// addHealthListener,
addSensorListener,
append,
onCommandUpdate,
onPropUpdate,
// removeHealthListener,
removeSensorListener,
// sendHealthHandler,
sendTelemetryHandler,
]);
if (!simulated) {
if (iotcentralClient === null) {
return <Registration />;
}
}
return (
<Tab.Navigator
key="tab"
tabBarOptions={Platform.select({
android: {safeAreaInsets: {bottom: 0}},
})}>
<Tab.Screen
name={Screens.TELEMETRY_SCREEN}
options={{
tabBarIcon: ({color, size}) => (
<TabBarIcon icon={icons.Telemetry} color={color} size={size} />
),
}}>
{getCardView(sensors, 'Telemetry', true)}
</Tab.Screen>
{/* <Tab.Screen
name={Screens.HEALTH_SCREEN}
options={{
tabBarIcon: ({color, size}) => (
<TabBarIcon icon={icons.Health} color={color} size={size} />
),
}}>
{getCardView(healths, 'Health', true)}
</Tab.Screen> */}
<Tab.Screen
name={Screens.PROPERTIES_SCREEN}
options={{
tabBarIcon: ({color, size}) => (
<TabBarIcon icon={icons.Properties} color={color} size={size} />
),
}}>
{propertiesLoading
? () => (
<Loader
message={'Waiting for properties...'}
visible={true}
style={{flex: 1, justifyContent: 'center'}}
/>
)
: () => (
<CardView
items={properties}
componentName="Property"
onEdit={async (item, value) => {
try {
await iotcentralClient?.sendProperty({
[PROPERTY]: {__t: 'c', [item.id]: value},
});
Alert.alert(
'Property',
`Property ${item.name} successfully sent to IoT Central`,
[{text: 'OK'}],
);
} catch (e) {
Alert.alert(
'Property',
`Property ${item.name} not sent to IoT Central`,
[{text: 'OK'}],
);
}
}}
/>
)}
</Tab.Screen>
<Tab.Screen
name={Screens.FILE_UPLOAD_SCREEN}
component={FileUpload}
options={{
tabBarIcon: ({color, size}) => (
<TabBarIcon
icon={icons['Image Upload']}
color={color}
size={size}
/>
),
}}
/>
<Tab.Screen
name={Screens.LOGS_SCREEN}
component={Logs}
options={{
tabBarIcon: ({color, size}) => (
<TabBarIcon icon={icons.Logs} color={color} size={size} />
),
}}
/>
</Tab.Navigator>
);
});
const getCardView = (items: ItemProps[], name: string, detail: boolean) => ({
navigation,
}: {
navigation: any;
}) => (
<CardView
items={items}
componentName={name}
onItemPress={
detail
? item => {
navigation.navigate('Insight', {
chartType:
item.id === AVAILABLE_SENSORS.GEOLOCATION
? ChartType.MAP
: ChartType.DEFAULT,
currentValue: item.value,
telemetryId: item.id,
title: camelToName(item.id),
backTitle: 'Telemetry',
});
}
: undefined
}
/>
);
const Logo = React.memo(() => {
const {colors} = useTheme();
return (
<View
style={{
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-around',
marginHorizontal: 10,
}}>
<LogoIcon width={30} fill={colors.primary} />
<Text
style={{
marginStart: 10,
color: colors.text,
fontWeight: 'bold',
fontSize: 16,
letterSpacing: 0.1,
}}>
Azure IoT Central
</Text>
</View>
);
});
const Profile = React.memo((props: {navigate: any}) => {
const {colors} = useTheme();
return (
<View style={{marginHorizontal: 10}}>
<Icon
style={{marginEnd: 20}}
name={
Platform.select({
ios: 'settings-outline',
android: 'settings',
}) as string
}
type={Platform.select({ios: 'ionicon', android: 'material'})}
color={colors.text}
onPress={() => {
props.navigate('Settings');
}}
/>
</View>
);
});
const BackButton = React.memo((props: {goBack: any; title: string}) => {
const {colors} = useTheme();
const {goBack, title} = props;
return (
<View style={{flexDirection: 'row', marginLeft: 10, alignItems: 'center'}}>
<Icon name="close" color={colors.text} onPress={goBack} />
{Platform.OS === 'android' && (
<HeaderTitle style={{marginLeft: 20}}>{title}</HeaderTitle>
)}
</View>
);
});
const TabBarIcon = React.memo<{icon: IIcon; color: string; size: number}>(
({icon, color, size}) => {
return (
<Icon
name={icon ? icon.name : 'home'}
type={icon ? icon.type : 'ionicon'}
size={size}
color={color}
/>
);
},
);

124
src/CardView.tsx Normal file
Просмотреть файл

@ -0,0 +1,124 @@
import React from 'react';
import {View, FlatList} from 'react-native';
import {useSafeAreaInsets} from 'react-native-safe-area-context';
import {ItemProps} from 'types';
import {Card} from './components/card';
type CardPressCallback = (item: ItemProps) => void | Promise<void>;
type CardEditCallback = (item: ItemProps, value: any) => void | Promise<void>;
const CardView = React.memo<{
items: ItemProps[];
componentName?: string;
onItemPress?: CardPressCallback;
onEdit?: CardEditCallback;
}>(({items, onItemPress, componentName, onEdit}) => {
const insets = useSafeAreaInsets();
// const navigation = useNavigation();
// const [, append] = useLogger();
// const sendTelemetryHandler = useCallback(
// async (id: string, value: any) => {
// if (iotcentralClient && iotcentralClient.isConnected()) {
// await iotcentralClient.sendTelemetry(
// { [id]: value },
// { '$.sub': TELEMETRY_COMPONENT },
// );
// }
// }, [iotcentralClient]
// );
// const onCommandUpdate = useCallback(
// async (command: IIoTCCommand) => {
// let data: any;
// data = JSON.parse(command.requestPayload);
// if (data.item) {
// if (command.name === ENABLE_DISABLE_COMMAND) {
// items?.[data.item].enable(data.enable ? data.enable : false);
// await command.reply(IIoTCCommandResponse.SUCCESS, 'Enable');
// } else if (command.name === SET_FREQUENCY_COMMAND) {
// itemMap[data.item].sendInterval(
// data.frequency ? data.frequency * 1000 : 5000,
// );
// await command.reply(IIoTCCommandResponse.SUCCESS, 'Frequency');
// }
// }
// },
// [items],
// );
// useEffect(() => {
// if (iotcentralClient && iotcentralClient.isConnected()) {
// items?.forEach((s) =>
// itemMap[s.id].addListener(DATA_AVAILABLE_EVENT, sendTelemetryHandler),
// );
// append({
// eventName: 'INFO',
// eventData: 'item initialized.'
// });
// }
// return () => {
// items?.forEach((s) =>
// itemMap[s.id].removeListener(DATA_AVAILABLE_EVENT, sendTelemetryHandler),
// );
// };
// }, [items, iotcentralClient]);
// useEffect(() => {
// if (iotcentralClient) {
// iotcentralClient.on(IOTC_EVENTS.Commands, onCommandUpdate);
// }
// }, [iotcentralClient, onCommandUpdate]);
// if (!simulated) {
// if (iotcentralClient === null) {
// console.log('chiamo registration qua');
// return <Registration />;
// }
// if (!items) {
// return (
// <Loader
// message={'Waiting for items...'}
// visible={true}
// style={{ flex: 1, justifyContent: 'center' }}
// />
// );
// }
// }
return (
<View
style={{flex: 1, paddingTop: insets.top, paddingBottom: insets.bottom}}>
<FlatList
numColumns={items.length > 4 ? 2 : 1}
data={items}
renderItem={getCard(componentName, onItemPress, onEdit)}
/>
</View>
);
});
const getCard = (
componentName?: string,
onItemPress?: CardPressCallback,
onEdit?: CardEditCallback,
) => ({item, index}: {item: ItemProps; index: number}) => (
<Card
key={`${componentName ?? 'card'}-${index}`}
title={item.name}
value={item.value}
unit={item.unit}
enabled={item.enabled}
editable={(item as any).editable}
icon={item.icon}
onToggle={() => item.enable(!item.enabled)}
onLongPress={e => console.log('longpress')} // edit card
onEdit={onEdit?.bind(null, item)}
onPress={
item.enabled && onItemPress ? onItemPress.bind(null, item) : undefined
}
/>
);
export default CardView;

298
src/FileUpload.tsx Normal file
Просмотреть файл

@ -0,0 +1,298 @@
import React, {useContext, useEffect, useRef, useState} from 'react';
import ImagePicker from 'react-native-image-picker';
import {View} from 'react-native-animatable';
import {Card} from './components/card';
import {useSafeAreaInsets} from 'react-native-safe-area-context';
import {useScreenDimensions} from './hooks/layout';
import {Icon} from 'react-native-elements';
import {useTheme} from '@react-navigation/native';
import {Headline, Text} from './components/typography';
import {useIoTCentralClient, useSimulation} from './hooks/iotc';
import {Registration} from './Registration';
import {Loader} from './components/loader';
import {AnimatedCircularProgress} from 'react-native-circular-progress';
import {Platform} from 'react-native';
import {StateUpdater} from './types';
import {LogsContext} from './contexts/logs';
export default function FileUpload() {
const [client] = useIoTCentralClient();
const [simulated] = useSimulation();
const insets = useSafeAreaInsets();
const {screen} = useScreenDimensions();
const {append} = useContext(LogsContext);
const [uploading, setUploading] = useState(false);
const [uploadStatus, setuploadStatus] = useState<boolean | undefined>(
undefined,
);
const fileName = useRef('');
const fileSize = useRef('');
useEffect(() => {
setuploadStatus(undefined);
}, [uploading]);
if (simulated) {
return (
<View
style={{
flex: 1,
justifyContent: 'center',
alignItems: 'center',
marginHorizontal: 30,
}}>
<Headline style={{textAlign: 'center'}}>
Simulation mode is enabled
</Headline>
<Text style={{textAlign: 'center'}}>
{' '}
File upload is not available. Disable simulation mode and connect to
IoT Central to work with file uploads.
</Text>
</View>
);
}
if (client === null) {
return <Registration />;
}
if (client === undefined) {
return <Loader message={'Connecting to IoT Central ...'} visible={true} />;
}
return (
<View
style={{
flex: 1,
paddingTop: insets.top,
paddingBottom: insets.bottom,
justifyContent: 'center',
alignItems: 'center',
}}>
<Card
containerStyle={{
flex: 0,
height: screen.height / 3,
width: screen.width - 100,
}}
enabled={false}
title=""
onPress={
uploading
? undefined
: () => {
ImagePicker.launchImageLibrary(
{
mediaType: 'photo',
},
async response => {
if (response.didCancel) {
console.log('User cancelled');
} else if (response.errorMessage) {
console.log('ImagePicker Error: ', response.errorMessage);
} else {
// send response data
let fileType = 'image/jpg';
if (response.type) {
fileType = response.type;
}
let curfileName = response.fileName;
if (!curfileName && Platform.OS === 'ios') {
curfileName = response.uri?.split('/').pop();
}
try {
setUploading(true);
append({
eventName: 'FILE UPLOAD',
eventData: `Starting upload of file ${curfileName}`,
});
fileName.current = curfileName as string;
fileSize.current = formatBytes(response.fileSize!);
await new Promise(r => setTimeout(r, 6000));
const res = await client.uploadFile(
curfileName as string,
fileType,
response.base64,
'base64',
);
if (res.status >= 200 && res.status < 300) {
append({
eventName: 'FILE UPLOAD',
eventData: `Successfully uploaded ${curfileName}`,
});
setuploadStatus(true);
} else {
append({
eventName: 'FILE UPLOAD',
eventData: `Error uploading ${curfileName}${
res.errorMessage
? `. Reason:${res.errorMessage}`
: '.'
}`,
});
setuploadStatus(false);
}
} catch (e) {
console.log(e);
}
}
},
);
}
}
value={
uploading
? () => (
<UploadProgress
size={fileSize.current}
filename={fileName.current}
uploadStatus={uploadStatus}
setUploading={setUploading}
/>
)
: UploadIcon
}
/>
</View>
);
}
function UploadIcon() {
const {colors} = useTheme();
return (
<View style={{flex: 1, justifyContent: 'center', alignItems: 'center'}}>
<Icon
size={50}
name="upload-outline"
type="material-community"
color={colors.text}
/>
<Text style={{marginTop: 30}}>
Select image to upload on Azure Storage
</Text>
</View>
);
}
function UploadProgress(props: {
filename: string;
size: string;
uploadStatus: boolean | undefined;
setUploading: StateUpdater<boolean>;
}) {
const {colors: themeColors} = useTheme();
const [fill, setFill] = useState(1);
const {size, uploadStatus, filename, setUploading} = props;
const {screen} = useScreenDimensions();
const [showResult, setShowResult] = useState(false);
const [rotationStyle] = useState({});
const [colors, setColors] = useState({
tint: themeColors.text,
background: themeColors.card,
});
const intid = useRef<number>();
useEffect(() => {
// @ts-ignore
intid.current = setInterval(
() =>
setFill(cur => {
if (cur === 100 || cur === 101) {
// reset counter
return 0;
}
return cur + 5;
}),
300,
);
// @ts-ignore
return () => clearInterval(intid.current);
}, []);
useEffect(() => {
if (fill === 0) {
// setRotationStyle({ transform: [{ scaleX: -1 }] });
setColors(cur => ({
tint:
cur.tint === themeColors.text ? themeColors.card : themeColors.text,
background:
cur.background === themeColors.card
? themeColors.text
: themeColors.card,
}));
}
}, [fill, themeColors.card, themeColors.text]);
useEffect(() => {
if (uploadStatus !== undefined) {
setShowResult(true);
// wait before go back to standard screen
setTimeout(() => {
setUploading(false);
}, 3000);
// @ts-ignore
clearInterval(intid.current);
}
}, [uploadStatus, setUploading]);
if (uploadStatus !== undefined && showResult) {
return (
<View style={{flex: 1, alignItems: 'center'}}>
<Icon
size={screen.height / 6}
color={uploadStatus ? 'green' : 'red'}
name={
Platform.select({
ios: uploadStatus
? 'checkmark-circle-outline'
: 'close-circle-outline',
android: uploadStatus
? 'check-circle-outline'
: 'close-circle-outline',
}) as string
}
type={Platform.select({
ios: 'ionicon',
android: 'material-community',
})}
/>
<Text>
{uploadStatus
? `Successfully uploaded ${filename}`
: `Failed to upload ${filename}`}
</Text>
</View>
);
}
return (
<View style={{flex: 1, justifyContent: 'center', alignItems: 'center'}}>
<AnimatedCircularProgress
size={screen.height / 5}
width={5}
fill={fill}
tintColor={colors.tint}
backgroundColor={colors.background}
rotation={360}
style={rotationStyle}>
{() => <Text style={rotationStyle}>{size}</Text>}
</AnimatedCircularProgress>
<Text style={{marginTop: 30}}>{filename}</Text>
</View>
);
}
function formatBytes(a: number, b = 2) {
if (0 === a) return '0 Bytes';
const c = 0 > b ? 0 : b;
const d = Math.floor(Math.log(a) / Math.log(1024));
return (
parseFloat((a / Math.pow(1024, d)).toFixed(c)) +
' ' +
['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'][d]
);
}

286
src/Insight.tsx Normal file
Просмотреть файл

@ -0,0 +1,286 @@
import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react';
import {View, StyleSheet, processColor} from 'react-native';
import {LineChart} from 'react-native-charts-wrapper';
import {
getRandomColor,
Text,
LightenDarkenColor,
Name,
} from './components/typography';
import {
ExtendedLineData,
ItemData,
CustomLineDatasetConfig,
NavigationParams,
DATA_AVAILABLE_EVENT,
} from './types';
import {useTheme, RouteProp} from '@react-navigation/native';
import {AnimatedCircularProgress} from 'react-native-circular-progress';
import {useScreenDimensions} from './hooks/layout';
import {Loader} from './components/loader';
import Map from './components/map';
import {SensorMap} from './sensors';
export enum ChartType {
DEFAULT,
MAP,
}
const Insight = React.memo<{
route: RouteProp<
Record<
string,
NavigationParams & {
chartType: ChartType;
telemetryId: string;
currentValue: any;
}
>,
'Insight'
>;
}>(({route}) => {
const {screen} = useScreenDimensions();
const {colors, dark} = useTheme();
const [data, setData] = useState<ExtendedLineData>({
dataSets: [],
});
const {current: start} = useRef(Date.now());
const timestamp = Date.now() - start;
const {chartType, telemetryId, currentValue} = route.params;
const mapStyle = useMemo(
() => ({
flex: 3,
margin: 20,
borderRadius: 20,
...(!dark
? {
shadowColor: "'rgba(0, 0, 0, 0.14)'",
shadowOffset: {
width: 0,
height: 3,
},
shadowOpacity: 0.8,
shadowRadius: 3.84,
elevation: 5,
}
: {}),
}),
[dark],
);
/**
*
* @param itemdata Current sample for the item
* @param startTime Start time of the sampling. Must be the same value used as "since" param in the chart
* @param setData Dispatch to update dataset with current sample
*/
const updateData = useCallback(
(id: string, value: any) => {
const item = {id, value};
if (id !== telemetryId) {
return;
}
let itemToProcess: ItemData[] = [item];
if (typeof item.value !== 'string' && typeof item.value !== 'number') {
// data is composite
itemToProcess = Object.keys(item.value).map(i => ({
id: `${item.id}.${i}`,
value: item.value[i],
}));
}
itemToProcess.forEach(itemdata => {
setData(currentDataSet => {
const currentItemData = currentDataSet.dataSets.find(
d => d.itemId === itemdata.id,
);
// Current sample time (x-axis) is the difference between current timestamp e the start time of sampling
const newSample = {x: Date.now() - start, y: itemdata.value};
if (!currentItemData) {
// current item is not in the dataset yet
const rgbcolor = getRandomColor();
return {
...currentDataSet,
dataSets: [
...currentDataSet.dataSets,
...[
{
itemId: itemdata.id,
values: [newSample],
label: itemdata.id,
config: {
color: processColor(rgbcolor),
valueTextColor: processColor(rgbcolor),
rgbcolor,
} as CustomLineDatasetConfig,
},
],
],
};
}
if (
currentItemData.values?.[currentItemData.values?.length] ===
itemdata.value
) {
return {...currentDataSet};
}
return {
...currentDataSet,
dataSets: currentDataSet.dataSets.map(({...currentItem}) => {
if (currentItem.itemId === itemdata.id && currentItem.values) {
currentItem.values = [...currentItem.values, ...[newSample]];
}
return currentItem;
}),
};
});
});
},
[start, telemetryId],
);
useEffect(() => {
const sensor = SensorMap[telemetryId]; // || HealthMap[telemetryId];
sensor?.addListener(DATA_AVAILABLE_EVENT, updateData);
// init chart with current value
if (currentValue !== undefined) {
updateData(telemetryId, currentValue);
}
return () => {
sensor?.removeListener(DATA_AVAILABLE_EVENT, updateData);
};
}, [telemetryId, currentValue, updateData]);
if (chartType === ChartType.MAP) {
return (
<View style={style.container}>
<Map style={mapStyle} location={currentValue} />
<View style={style.summary}>
<Text>
<Name>Latitude:</Name> {currentValue.lat}
</Text>
<Text>
<Name>Longitude:</Name> {currentValue.lon}
</Text>
</View>
</View>
);
}
return (
<>
{data.dataSets.length === 0 ? (
<Loader message="" visible={true} />
) : (
<View style={style.container}>
<View style={style.chart}>
<LineChart
style={style.chartBox}
chartDescription={{text: ''}}
touchEnabled={true}
dragEnabled={true}
scaleEnabled={true}
pinchZoom={true}
extraOffsets={{bottom: 20}}
legend={{
wordWrapEnabled: true,
textColor: processColor(colors.text),
textSize: 16,
}}
xAxis={{
position: 'BOTTOM',
axisMaximum: timestamp + 500,
axisMinimum: timestamp - 10000,
valueFormatter: 'date',
since: start,
valueFormatterPattern: 'HH:mm:ss',
timeUnit: 'MILLISECONDS',
drawAxisLines: false,
drawGridLines: false,
textColor: processColor(colors.text),
}}
yAxis={{
right: {
drawAxisLines: false,
textColor: processColor(colors.text),
},
left: {
drawAxisLines: false,
textColor: processColor(colors.text),
},
}}
data={data}
/>
<View style={style.summary}>
<View
style={{
flexDirection: 'row',
justifyContent: 'space-around',
marginTop: 40,
}}>
{data.dataSets.map((d, i) => {
if (!d.values) {
return null;
}
const val = (d.values[d.values.length - 1] as {
x: any;
y: any;
}).y;
const fill = val > 1 || val < -1 ? val : Math.abs(val * 1000);
return (
<AnimatedCircularProgress
key={`circle-${i}`}
size={screen.width / 5}
width={5}
fill={fill}
tintColor={
d.config ? d.config.rgbcolor : getRandomColor()
}
backgroundColor={
d.config
? LightenDarkenColor(d.config.rgbcolor, 90, true)
: getRandomColor()
}
rotation={360}>
{() => {
const strVal = `${val}`;
return (
<Text>
{strVal.length > 6
? `${strVal.substring(0, 6)}...`
: strVal}
</Text>
);
}}
</AnimatedCircularProgress>
);
})}
</View>
</View>
</View>
</View>
)}
</>
);
});
const style = StyleSheet.create({
container: {
flex: 1,
},
chart: {
flex: 1,
marginTop: 30,
marginHorizontal: 10,
},
chartBox: {
flex: 2,
},
summary: {
flex: 1,
padding: 20,
},
});
export default Insight;

41
src/Logs.tsx Normal file
Просмотреть файл

@ -0,0 +1,41 @@
import React from 'react';
import {View} from 'react-native';
import {useLogger} from './hooks/common';
import {Text} from './components/typography';
import {ScrollView} from 'react-native-gesture-handler';
import {useTheme} from '@react-navigation/native';
const Logs = React.memo(() => {
const {colors} = useTheme();
const [logs] = useLogger();
return (
<View style={{flex: 1, padding: 10}}>
<Text>Received commands will be logged below.</Text>
<ScrollView
style={{
margin: 10,
borderWidth: 1,
borderColor: colors.border,
paddingHorizontal: 10,
paddingBottom: 100,
}}>
{logs.map((l, i) => (
<React.Fragment key={`logf-${i}`}>
<Text key={`log-${i}`}>
{l.timestamp}:
<Text key={`logdata-${i}`} style={{color: 'green'}}>
{l.logItem.eventName}
</Text>
</Text>
<Text style={{marginBottom: 5}} key={`logpayload-${i}`}>
{l.logItem.eventData}
</Text>
</React.Fragment>
))}
</ScrollView>
</View>
);
});
export default Logs;

142
src/Registration.tsx Normal file
Просмотреть файл

@ -0,0 +1,142 @@
import React, {useRef} from 'react';
import {View, StyleSheet, Alert} from 'react-native';
import {Text} from './components/typography';
import {Button, Overlay} from 'react-native-elements';
import {useScreenDimensions} from './hooks/layout';
import {RouteProp, useTheme} from '@react-navigation/native';
import {Loader} from './components/loader';
import {useConnectIoTCentralClient} from './hooks/iotc';
import {NavigationParams, NavigationProperty, OnPressCallback} from './types';
import QRCodeScanner, {Event} from './components/qrcodeScanner';
import {useBoolean} from 'hooks/common';
export const Registration = React.memo<{
route?: RouteProp<
Record<string, NavigationParams & {previousScreen?: string}>,
'Registration'
>;
navigation?: NavigationProperty;
}>(({route, navigation}) => {
const {screen, orientation} = useScreenDimensions();
const {colors} = useTheme();
const [showQR, setShowQR] = useBoolean(false);
const [
connect,
cancel,
{loading, client, error},
] = useConnectIoTCentralClient();
const qrCodeRef = useRef<QRCodeScanner>(null);
const onQRRead = useRef(async (e: Event) => {
setShowQR.False();
await connect(e.data);
});
if (error) {
if (qrCodeRef.current) {
Alert.alert(
'Error',
'The QR code you have scanned is not an Azure IoT Central Device QR code',
[
{
text: 'Retry',
onPress: qrCodeRef.current?.reactivate,
},
{
text: 'Cancel',
style: 'cancel',
onPress: () => {
setShowQR.False;
console.log(`Loading: ${loading}`);
cancel({clear: false});
},
},
],
{
cancelable: false,
},
);
}
}
return (
<>
<Overlay
isVisible={showQR || loading}
overlayStyle={{
height: screen.height,
width: screen.width,
backgroundColor: colors.background,
}}
supportedOrientations={['portrait', 'landscape']}>
<View style={{position: 'relative', margin: -10}}>
{showQR && (
<QRCodeScanner
ref={qrCodeRef}
onRead={onQRRead.current}
onClose={setShowQR.False}
width={screen.width}
height={screen.height}
markerSize={Math.floor(
(orientation === 'portrait' ? screen.width : screen.height) /
1.5,
)}
/>
)}
<Loader
visible={loading}
message={'Connecting client...'}
modal
buttons={[
{
text: 'Cancel',
onPress: cancel,
},
]}
/>
</View>
</Overlay>
{!showQR && client && (
<View style={style.container}>
<Text style={style.header}>
Mobile device is currently registered to IoT Central with Id{' '}
<Text style={{fontWeight: 'bold'}}>"{client.id}" </Text>
and Scope{' '}
<Text style={{fontWeight: 'bold'}}>"{client.scopeId}".</Text>
{'\n'}To disconnect and register a different device, scan the
associated QR Code
</Text>
<Button type="clear" title="Scan QR code" onPress={setShowQR.True} />
</View>
)}
{!showQR && !client && <EmptyClient scan={setShowQR.True} />}
</>
);
});
const EmptyClient = React.memo<{scan: OnPressCallback}>(({scan}) => (
<View style={style.container}>
<Text style={style.header}>
Mobile device is not currently registered to any application in Azure IoT
Central. To register this phone as a device scan the associated QR Code .
</Text>
<Button type="clear" title="Scan QR code" onPress={scan} />
</View>
));
const style = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
marginHorizontal: 30,
},
header: {},
center: {
position: 'absolute',
top: '50%',
bottom: 0,
left: 0,
right: 0,
},
});

164
src/Settings.tsx Normal file
Просмотреть файл

@ -0,0 +1,164 @@
import {useContext, useState} from 'react';
import {ThemeContext} from './contexts/theme';
import React from 'react';
import {View, Switch, ScrollView, Platform, Alert} from 'react-native';
import {useTheme, useNavigation} from '@react-navigation/native';
import {useSafeAreaInsets} from 'react-native-safe-area-context';
import {Icon, ListItem} from 'react-native-elements';
import {Registration} from './Registration';
import {createStackNavigator} from '@react-navigation/stack';
import {useIoTCentralClient, useSimulation} from './hooks/iotc';
import {defaults} from './contexts/defaults';
import {StorageContext} from './contexts/storage';
import {LogsContext} from './contexts/logs';
const Stack = createStackNavigator();
type ProfileItem = {
title: string;
icon: string;
value?: boolean;
action?: {
type: 'switch' | 'expand' | 'select';
fn: (...args: any) => void;
};
};
export default function Settings() {
const {toggle} = useContext(ThemeContext);
const {clear} = useContext(StorageContext);
const {clear: clearLogs} = useContext(LogsContext);
const [client, clearClient] = useIoTCentralClient();
const [centralSimulated, simulate] = useSimulation();
const {colors, dark} = useTheme();
const insets = useSafeAreaInsets();
const updateUIItems = (title: string, val: any) => {
setItems(current =>
current.map(i => {
if (i.title === title) {
i = {...i, value: val};
}
return i;
}),
);
};
const [items, setItems] = useState<ProfileItem[]>([
{
title: 'Registration',
icon: 'hammer-outline',
action: {
type: 'expand',
fn: navigation => {
navigation.navigate('Registration', {previousScreen: 'root'});
},
},
},
{
title: 'Clear Data',
icon: 'trash-outline',
action: {
type: 'select',
fn: async val => {
await client?.disconnect();
await clear();
clearLogs();
clearClient();
Alert.alert('Success', 'Successfully clean data');
},
},
},
{
title: 'Dark Mode',
icon: dark ? 'moon-outline' : 'moon',
action: {
type: 'switch',
fn: val => {
updateUIItems('Dark Mode', val);
toggle();
},
},
value: dark,
},
...(defaults.dev
? [
{
title: 'Simulation Mode',
icon: dark ? 'sync-outline' : 'sync',
action: {
type: 'switch',
fn: async val => {
updateUIItems('Simulation Mode', val);
await simulate(val);
},
},
value: centralSimulated,
} as ProfileItem,
]
: []),
]);
return (
<View style={{flex: 1, marginTop: insets.top, marginBottom: insets.bottom}}>
<Stack.Navigator
screenOptions={({route}) => ({
headerShown: false, // TODO: fix header
})}>
<Stack.Screen name="setting_root">
{() => <Root items={items} colors={colors} />}
</Stack.Screen>
<Stack.Screen name="Registration" component={Registration} />
</Stack.Navigator>
</View>
);
}
const RightElement = React.memo<{item: ProfileItem; colors: any}>(
({item, colors}) => {
if (item.action && item.action.type === 'switch') {
return (
<Switch
value={item.value}
onValueChange={item.action.fn}
{...(Platform.OS === 'android' && {
thumbColor: item.value ? colors.primary : colors.background,
})}
/>
);
}
return null;
},
);
const Root = React.memo<{items: ProfileItem[]; colors: any}>(
({items, colors}) => {
const nav = useNavigation<any>();
return (
<ScrollView style={{flex: 1}}>
{items.map((item, index) => (
<ListItem
key={`setting-${index}`}
bottomDivider
containerStyle={{backgroundColor: colors.card}}
onPress={
item.action && item.action.type !== 'switch'
? item.action.fn.bind(null, nav)
: undefined
}>
<Icon name={item.icon} type="ionicon" color={colors.text} />
<ListItem.Content>
<ListItem.Title style={{color: colors.text}}>
{item.title}
</ListItem.Title>
</ListItem.Content>
<RightElement item={item} colors={colors} />
{item.action && item.action.type === 'expand' && (
<ListItem.Chevron />
)}
</ListItem>
))}
</ScrollView>
);
},
);

125
src/Welcome.tsx Normal file
Просмотреть файл

@ -0,0 +1,125 @@
import React, {useState, useEffect, useRef, useCallback} from 'react';
import {StyleSheet, View} from 'react-native';
import Logo from './assets/IotcLogo.svg';
import * as Animatable from 'react-native-animatable';
import LinearGradient from 'react-native-linear-gradient';
import {defaults} from './contexts/defaults';
import DeviceInfo from 'react-native-device-info';
import {StateUpdater} from './types';
import ProgressCircleSnail from 'react-native-progress/CircleSnail';
import {useScreenDimensions} from './hooks/layout';
import {Text} from 'react-native-elements';
const animations = {
slideOutLogo: {
from: {
left: '50%',
},
to: {
left: '25%',
},
},
slideInName: {
from: {
left: '100%',
},
to: {
left: '65%',
},
},
};
Animatable.initializeRegistryWithDefinitions(animations);
export function Welcome(props: {setInitialized: StateUpdater<boolean>}) {
const {setInitialized} = props;
const [animationStarted, setAnimationStarted] = useState(false);
const [animationEnded, setAnimationEnded] = useState(false);
const {screen} = useScreenDimensions();
const animation = useRef<any>();
const initDefaults = useCallback(
async (animationHasEnded: boolean) => {
defaults.emulator = await DeviceInfo.isEmulator();
defaults.dev = __DEV__;
while (!animationHasEnded) {
await new Promise(r => setTimeout(r, 2000));
}
setInitialized(true);
},
[setInitialized],
);
// init authentication
useEffect(() => {
initDefaults(animationEnded);
}, [animationEnded, initDefaults]);
return (
<LinearGradient colors={['#041b5c', '#136BFB']} style={style.container}>
<View style={{flexDirection: 'row', marginBottom: 80}}>
<Animatable.View
ref={animation}
animation="slideOutLogo"
delay={1000}
onAnimationBegin={() => setAnimationStarted(true)}
style={style.logo}>
<Logo width={100} height={100} fill={'#1881e0'} />
</Animatable.View>
{animationStarted ? (
<Animatable.View
animation="slideInName"
style={style.name}
onAnimationEnd={() => {
setTimeout(() => {
setAnimationEnded(true);
}, 1000);
}}>
<Text
style={{
color: 'white',
fontWeight: 'bold',
fontSize: 20,
letterSpacing: 0.1,
}}>
Azure IoT Central
</Text>
</Animatable.View>
) : null}
</View>
<View style={{alignItems: 'center'}}>
<ProgressCircleSnail
size={Math.floor(screen.width / 8)}
indeterminate={true}
color="white"
thickness={3}
spinDuration={1000}
duration={1000}
/>
</View>
{/* <Button title='Animate' onPress={() => {
animation.current?.animate();
}} /> */}
</LinearGradient>
);
}
const style = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
},
logo: {
position: 'absolute',
top: '50%',
transform: [{translateX: -50}, {translateY: -50}],
},
name: {
position: 'absolute',
top: '50%',
flex: 1,
alignItems: 'center',
justifyContent: 'center',
transform: [{translateX: -80}, {translateY: -20}],
},
});

62
src/assets/IotcLogo.svg Normal file
Просмотреть файл

@ -0,0 +1,62 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
class="a5c653e1"
width="200"
height="200"
viewBox="0 0 200 200"
version="1.1"
id="svg838"
sodipodi:docname="central_logo2.svg"
inkscape:version="0.92.4 (5da689c313, 2019-01-14)">
<metadata
id="metadata844">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs842" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1440"
inkscape:window-height="837"
id="namedview840"
showgrid="false"
inkscape:zoom="2.4583333"
inkscape:cx="103.69842"
inkscape:cy="94.546068"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="svg838" />
<path
d="m 101.67247,142.72414 35.02816,-21.02005 V 77.339815 L 101.67247,56.327642 66.644303,77.324057 v 44.380033 l 35.028167,21.01218 z"
id="path834"
inkscape:connector-curvature="0"
style="fill:#000000;stroke-width:7.87858009" />
<path
d="M 101.67247,6.1016949 19.932203,52.813795 V 84.335993 L 58.466337,106.52207 V 89.007991 L 35.114226,74.999876 V 62.157791 l 66.558244,-38.542013 66.55824,38.534134 v 74.736208 l -66.55824,38.53413 -81.740267,-46.70422 v 17.51408 l 81.740267,46.70422 81.74026,-46.70422 V 52.813795 Z"
id="path836"
inkscape:connector-curvature="0"
style="fill:#000000;stroke-width:7.87858009" />
</svg>

После

Ширина:  |  Высота:  |  Размер: 2.1 KiB

193
src/components/card.tsx Normal file
Просмотреть файл

@ -0,0 +1,193 @@
import React, {useRef, useState, useEffect} from 'react';
import {
CardProps,
IconProps,
Icon,
CheckBox,
Input,
Button,
} from 'react-native-elements';
import {useTheme} from '@react-navigation/native';
import {
View,
ColorValue,
TouchableOpacity,
TouchableOpacityProps,
ViewStyle,
} from 'react-native';
import {Text, Name, Headline, getRandomColor} from './typography';
type EditCallback = (value: any) => void | Promise<void>;
export function Card(
props: CardProps &
TouchableOpacityProps & {
title?: string;
onToggle?: () => void;
enabled: boolean;
value?: any | React.FC;
unit?: string;
icon?: IconProps;
editable?: boolean;
onEdit?: EditCallback;
},
) {
const {
containerStyle,
enabled,
onToggle,
editable,
onEdit,
value,
unit,
icon,
...otherProps
} = props;
const {dark, colors} = useTheme();
const textColor = enabled ? colors.text : '#9490a9';
const barColor = useRef(getRandomColor() as ColorValue);
const checkboxStyle: ViewStyle = {position: 'absolute', top: -25, right: -40};
const iconStyle: ViewStyle = {
alignSelf: 'flex-end',
justifyContent: 'flex-end',
};
return (
<TouchableOpacity
style={[
{
backgroundColor: colors.card,
flex: 1,
height: 200,
padding: 25,
margin: 10,
borderRadius: 20,
...(!dark
? {
shadowColor: "'rgba(0, 0, 0, 0.14)'",
shadowOffset: {
width: 0,
height: 3,
},
shadowOpacity: 0.8,
shadowRadius: 3.84,
elevation: 5,
}
: {}),
},
containerStyle,
]}
{...otherProps}>
<View style={{flex: 1, position: 'relative'}}>
{enabled && (
<View
style={{
backgroundColor: enabled ? barColor.current : 'white',
width: `60%`,
height: 5,
marginBottom: 20,
borderRadius: 5,
}}></View>
)}
{onToggle && (
<CheckBox
center
checkedIcon="dot-circle-o"
uncheckedIcon="circle-o"
checked={enabled}
containerStyle={checkboxStyle}
onPress={onToggle}
/>
)}
<View style={{flex: 2}}>
<Name style={{color: textColor}}>{otherProps.title}</Name>
{typeof value === 'function' ? (
value()
) : (
<View style={{flexDirection: 'row', paddingVertical: 10}}>
<Value
value={value}
enabled
editable={editable}
onEdit={onEdit}
textColor={textColor}
/>
{unit && enabled && (
<Headline style={{color: '#9490a9', alignSelf: 'flex-end'}}>
{unit}
</Headline>
)}
</View>
)}
</View>
{icon && (
<Icon
name={icon.name}
type={icon.type}
style={iconStyle}
color="#9490a9"
/>
)}
</View>
</TouchableOpacity>
);
}
const Value = React.memo<{
value: any;
enabled: boolean;
editable: boolean | undefined;
onEdit: EditCallback | undefined;
textColor: string;
}>(({value, enabled, editable, onEdit, textColor}) => {
const [edited, setEdited] = useState(value);
useEffect(() => {
setEdited(value);
}, [value]);
if (!enabled) {
return null;
}
if (value === undefined || edited === null || edited === undefined) {
return <Text>N/A</Text>;
}
if (typeof value !== 'string' && typeof value !== 'number') {
return (
<View>
{Object.keys(value).map((v, i) => {
const strVal: string = value[v].toString();
return (
<Text key={`data-${i}`}>
{v}: {strVal.length > 6 ? `${strVal.substring(0, 6)}...` : strVal}
</Text>
);
})}
</View>
);
} else {
const strVal: string = value.toString();
if (editable && onEdit) {
return (
<View style={{flex: 1}}>
<Input
value={edited.toString()}
onChangeText={setEdited}
inputStyle={{color: textColor}}
keyboardType={typeof value === 'number' ? 'numeric' : 'default'}
/>
<Button title="Send" onPress={e => onEdit(edited)} type="clear" />
</View>
);
} else {
return (
<Headline style={{fontSize: 26, marginEnd: 5, color: textColor}}>
{strVal.length > 6 ? `${strVal.substring(0, 6)}...` : strVal}
</Headline>
);
}
}
});

77
src/components/loader.tsx Normal file
Просмотреть файл

@ -0,0 +1,77 @@
import React from 'react';
import {View, ActivityIndicator, ViewStyle, ScaledSize} from 'react-native';
import {Text} from './typography';
import {Theme, useTheme} from '@react-navigation/native';
import {Button, Divider, Overlay} from 'react-native-elements';
import {useScreenDimensions} from '../hooks/layout';
type ILoaderButton = {
text: string;
onPress: () => void | Promise<void>;
};
interface ILoaderProps {
message: string;
buttons?: ILoaderButton[];
visible: boolean;
modal?: boolean;
style?: ViewStyle;
}
export function Loader(props: ILoaderProps) {
const {colors, dark} = useTheme();
const {screen} = useScreenDimensions();
const {visible, modal, style} = props;
const overlayStyle = [
...[style],
{
padding: 0,
borderRadius: 20,
backgroundColor: colors.card,
width: screen.width / 1.5,
},
];
const backdropStyle = {backgroundColor: colors.background};
if (!visible) {
return null;
}
if (modal) {
return (
<Overlay
isVisible={visible}
overlayStyle={overlayStyle}
backdropStyle={backdropStyle}>
{getLoader({...props, ...screen, colors, dark})}
</Overlay>
);
}
return getLoader({...props, colors, ...screen, dark});
}
function getLoader(props: ILoaderProps & Theme & ScaledSize) {
const {message, buttons, colors, style, height} = props;
return (
<View style={[...[style], {height: height / 4, padding: 0}]}>
<View style={{flex: 2, justifyContent: 'center', alignItems: 'center'}}>
<ActivityIndicator animating={true} size={40} color={colors.text} />
<Text>{message}</Text>
</View>
{buttons && buttons.length > 0 && (
<View style={{flex: 1, justifyContent: 'flex-end', margin: 0}}>
<Divider />
{buttons.map(b => (
<Button
key={b.text}
type="clear"
title={b.text}
onPress={b.onPress}
style={{paddingVertical: 10}}
/>
))}
</View>
)}
</View>
);
}

44
src/components/map.tsx Normal file
Просмотреть файл

@ -0,0 +1,44 @@
import React, {useState} from 'react';
import {StyleProp, ViewStyle} from 'react-native';
import {
Marker,
// @ts-ignore
Animated,
PROVIDER_DEFAULT,
AnimatedRegion,
} from 'react-native-maps';
import {GeoCoordinates} from '../types';
const Map = React.memo<{
location: GeoCoordinates;
style?: StyleProp<ViewStyle>;
}>(({location, style}) => {
const [region, setRegion] = useState(
new AnimatedRegion({
latitude: location.lat,
longitude: location.lon,
latitudeDelta: location.latD ? location.latD : 0.0922,
longitudeDelta: location.lonD ? location.lonD : 0.0421,
}),
);
return (
<Animated
provider={PROVIDER_DEFAULT}
style={style ? style : {width: '100%', height: '100%'}}
scrollEnabled={true}
zoomEnabled={true}
rotateEnabled={true}
region={region}
onRegionChangeComplete={setRegion}>
<Marker
coordinate={{latitude: location.lat, longitude: location.lon}}
title="Current location"
description={`${location.lat
.toString()
.substring(0, 6)}... - ${location.lon.toString().substring(0, 6)}...`}
/>
</Animated>
);
});
export default Map;

Просмотреть файл

@ -0,0 +1,217 @@
import React from 'react';
import {Platform, StyleSheet, View} from 'react-native';
import {Icon} from 'react-native-elements';
import Scanner from 'react-native-qrcode-scanner';
import {BarCodeReadEvent} from 'react-native-camera';
import {Text} from './typography';
interface QRCodeScannerProps {
height: number;
width: number;
markerSize: number;
}
export type Event = BarCodeReadEvent;
interface IQRCodeScanner {
reactivate: () => void;
}
export type IQRCodeProps = QRCodeScannerProps & {
onRead: (e: Event) => void | Promise<void>;
onClose?: () => void | Promise<void>;
};
export default class QRCodeScanner
extends React.Component<IQRCodeProps, {}>
implements IQRCodeScanner {
public overlayDimension: any;
private qrCodeRef: Scanner | null;
public onRead: (e: Event) => void | Promise<void>;
public onClose: (() => void | Promise<void>) | undefined;
private calculateSideWidth(width: number, markerSize: number): number {
return (width - markerSize) / 2;
}
private calculateVerticals(height: number, markerSize: number): number {
return (height - markerSize) / 2;
}
constructor(props: IQRCodeProps) {
super(props);
({onRead: this.onRead, onClose: this.onClose} = props);
this.qrCodeRef = null;
}
public reactivate() {
this.qrCodeRef?.reactivate();
}
render() {
const sideWidth = this.calculateSideWidth(
this.props.width,
this.props.markerSize,
);
const verticals = this.calculateVerticals(
this.props.height,
this.props.markerSize,
);
return (
<Scanner
ref={sc => (this.qrCodeRef = sc)}
onRead={this.onRead}
topViewStyle={{
position: 'absolute',
zIndex: 2,
marginLeft:
this.props.width > this.props.height ? sideWidth - verticals : 0,
}} // hack: margin is needed when in landscape
topContent={
<View
style={{
position: 'relative',
height: this.props.height,
width: this.props.width,
}}>
<View
key="left"
style={{
height: this.props.height,
backgroundColor: 'rgba(0,0,0,.5)',
width: sideWidth,
left: 0,
position: 'absolute',
top: 0,
}}></View>
<View
key="right"
style={{
height: this.props.height,
backgroundColor: 'rgba(0,0,0,.5)',
width: sideWidth,
right: 0,
position: 'absolute',
top: 0,
}}></View>
<View
key="top"
style={{
marginHorizontal: sideWidth,
width: this.props.markerSize,
backgroundColor: 'rgba(0,0,0,.5)',
height: verticals + 10,
top: 0,
position: 'absolute',
}}></View>
<View
key="bottom"
style={{
marginHorizontal: sideWidth,
width: this.props.markerSize,
backgroundColor: 'rgba(0,0,0,.5)',
height: verticals,
bottom: -10,
position: 'absolute',
}}></View>
{this.onClose && (
<Icon
name="close-circle-outline"
type={Platform.select({
ios: 'ionicon',
android: 'material-community',
})}
size={40}
color="black"
containerStyle={{
position: 'absolute',
top: verticals - 40,
right: sideWidth - 40,
}}
onPress={this.onClose}
/>
)}
</View>
}
customMarker={
<View>
<QRCodeMask width={this.props.markerSize} color={'black'} />
<Text style={{...style.center, textAlign: 'center'}}>
Move closer to scan
</Text>
</View>
}
showMarker={true}
cameraStyle={{height: this.props.height + 20, width: this.props.width}}
/>
);
}
}
function QRCodeMask(props: {width: number; color: string}) {
const {width: markerWidth, color} = props;
const sectorWidth = markerWidth / 5;
return (
<View
style={{position: 'relative', width: markerWidth, height: markerWidth}}>
<View
key="top-left"
style={{
position: 'absolute',
top: 0,
left: 0,
height: sectorWidth,
width: sectorWidth,
borderColor: color,
borderLeftWidth: 5,
borderTopWidth: 5,
}}></View>
<View
key="top-right"
style={{
position: 'absolute',
top: 0,
left: markerWidth - sectorWidth,
height: sectorWidth,
width: sectorWidth,
borderColor: color,
borderRightWidth: 5,
borderTopWidth: 5,
}}></View>
<View
key="bottom-left"
style={{
position: 'absolute',
top: markerWidth - sectorWidth,
left: 0,
height: sectorWidth,
width: sectorWidth,
borderColor: color,
borderLeftWidth: 5,
borderBottomWidth: 5,
}}></View>
<View
key="bottom-right"
style={{
position: 'absolute',
top: markerWidth - sectorWidth,
left: markerWidth - sectorWidth,
height: sectorWidth,
width: sectorWidth,
borderColor: color,
borderRightWidth: 5,
borderBottomWidth: 5,
}}></View>
</View>
);
}
const style = StyleSheet.create({
center: {
position: 'absolute',
top: '50%',
bottom: 0,
left: 0,
right: 0,
},
});

Просмотреть файл

@ -0,0 +1,9 @@
import React from 'react';
import {useSafeAreaInsets} from 'react-native-safe-area-context';
import {View} from 'react-native';
export default function ScreenView() {
const insets = useSafeAreaInsets();
return <View style={{marginTop: insets.top}}></View>;
}

Просмотреть файл

@ -0,0 +1,160 @@
import React from 'react';
import {Text as ELText} from 'react-native-elements';
import {TextProperties, Dimensions, Platform, PixelRatio} from 'react-native';
import {useTheme} from '@react-navigation/native';
const {width: SCREEN_WIDTH} = Dimensions.get('window');
// based on iphone 5s's scale
const scale = SCREEN_WIDTH / 350;
interface Props extends TextProperties {
children?: any;
theme?: any;
}
function normalize(size: number) {
const newSize = size * scale;
if (Platform.OS === 'ios') {
return Math.round(PixelRatio.roundToNearestPixel(newSize)) - 1;
} else {
return Math.round(PixelRatio.roundToNearestPixel(newSize)) - 2;
}
}
export function Headline(props: Props) {
const {children, style} = props;
const {colors} = useTheme();
return (
<ELText
style={[
{fontSize: normalize(20), fontWeight: 'bold', color: colors.text},
style,
]}>
{children}
</ELText>
);
}
export function Text(props: Props) {
const {children, style} = props;
const {colors} = useTheme();
return (
<ELText
style={[
{fontSize: normalize(14), fontStyle: 'normal', color: colors.text},
style,
]}>
{children}
</ELText>
);
}
export function Name(props: Props) {
const {children, style} = props;
const {colors} = useTheme();
return (
<ELText
style={[
{
fontSize: normalize(14),
fontWeight: 'bold',
color: colors.text,
fontStyle: 'normal',
letterSpacing: 1.15,
},
style,
]}>
{children}
</ELText>
);
}
export function camelToName(text: string): string {
return (
text
// insert a space before all caps
.replace(/([A-Z])/g, ' $1')
// uppercase the first character
.replace(/^./, str => {
return str.toUpperCase();
})
);
}
export function getRandomColor(): string {
return `rgb(${Math.floor(Math.random() * 256)},${Math.floor(
Math.random() * 256,
)},${Math.floor(Math.random() * 256)})`;
}
export function getNegativeColor(color: string): string {
const colors = color
.substr(0, color.length)
.split('rgb(')[1]
.split(',')
.map(c => +c);
let R = +colors[0];
let G = Math.floor(+colors[1] * 1.8);
let B = Math.floor(+colors[2] * 1.8);
R = R < 255 ? R : 255;
G = G < 255 ? G : 255;
B = B < 255 ? B : 255;
return `rgb(${R},${G},${B})`;
}
export function LightenDarkenColor(
colorCode: string,
amount: number,
usePound: boolean = false,
) {
if (colorCode[0] === '#') {
colorCode = colorCode.slice(1);
usePound = true;
}
if (colorCode.startsWith('rgb(')) {
colorCode = colorCode
.substr(0, colorCode.length)
.split('rgb(')[1]
.split(',')
.map(c => {
c = parseInt(c, 16).toString(16);
return c.length === 1 ? `0${c}` : c;
})
.join('');
}
const num = parseInt(colorCode, 16);
/* tslint:disable:no-bitwise */
let r = (num >> 16) + amount;
if (r > 255) {
r = 255;
} else if (r < 0) {
r = 0;
}
let b = ((num >> 8) & 0x00ff) + amount;
if (b > 255) {
b = 255;
} else if (b < 0) {
b = 0;
}
let g = (num & 0x0000ff) + amount;
if (g > 255) {
g = 255;
} else if (g < 0) {
g = 0;
}
return (usePound ? '#' : '') + (g | (b << 8) | (r << 16)).toString(16);
}
/* tslint:enable:no-bitwise */

11
src/contexts/defaults.ts Normal file
Просмотреть файл

@ -0,0 +1,11 @@
export type DefaultProps = {
emulator: boolean;
initialized: boolean;
dev: boolean;
};
export const defaults: DefaultProps = {
emulator: false,
initialized: false,
dev: false,
};

4
src/contexts/index.ts Normal file
Просмотреть файл

@ -0,0 +1,4 @@
export {default as IoTCProvider, IoTCContext} from './iotc';
export {default as LogsProvider, LogsContext} from './logs';
export {default as StorageProvider, StorageContext} from './storage';
export {default as ThemeProvider, ThemeContext, ThemeMode} from './theme';

50
src/contexts/iotc.tsx Normal file
Просмотреть файл

@ -0,0 +1,50 @@
import React, {useCallback, useReducer} from 'react';
import {IoTCClient} from 'react-native-azure-iotcentral-client';
type ICentralState = {
client: IoTCClient | null;
connecting: boolean;
};
type ICentralAction =
| {type: 'UPDATE_CLIENT'; value: IoTCClient | null}
| {type: 'SET_CONNECTING'; value: boolean};
export type IIoTCContext = ICentralState & {
setClient: (client: IoTCClient | null) => void;
setConnecting: (connecting: boolean) => void;
};
const IoTCContext = React.createContext({} as IIoTCContext);
const {Provider} = IoTCContext;
const IoTCProvider: React.FC<{children: React.ReactNode}> = ({children}) => {
const [state, dispatch] = useReducer(
(state: ICentralState, action: ICentralAction) => {
switch (action.type) {
case 'UPDATE_CLIENT':
return {client: action.value, connecting: false};
case 'SET_CONNECTING':
return {...state, connecting: action.value};
default:
return {...state};
}
},
{client: null, connecting: false},
);
const setClient = useCallback((client: IoTCClient | null) => {
dispatch({type: 'UPDATE_CLIENT', value: client});
}, []);
const setConnecting = useCallback((value: boolean) => {
dispatch({type: 'SET_CONNECTING', value});
}, []);
const value = {
client: state.client,
setClient,
connecting: state.connecting,
setConnecting,
};
return <Provider value={value}>{children}</Provider>;
};
export {IoTCProvider as default, IoTCContext};

40
src/contexts/logs.tsx Normal file
Просмотреть файл

@ -0,0 +1,40 @@
import React, {useCallback, useState} from 'react';
import {LogItem, TimedLog} from '../types';
interface ILogsContext {
logs: TimedLog;
append: (logItem: LogItem) => void;
clear: () => void;
}
const initialState: TimedLog = [];
const LogsContext = React.createContext({} as ILogsContext);
const {Provider} = LogsContext;
const LogsProvider: React.FC<{children: React.ReactNode}> = ({children}) => {
const [logs, setLogs] = useState<TimedLog>(initialState);
const append = useCallback(
(logItem: LogItem) => {
setLogs(current => [
...current,
{logItem, timestamp: new Date(Date.now()).toLocaleString()},
]);
},
[setLogs],
);
const clear = useCallback(() => {
setLogs([
{
logItem: {
eventData: 'Application just reset',
eventName: 'INFO',
},
timestamp: new Date(Date.now()).toLocaleString(),
},
]);
}, [setLogs]);
return <Provider value={{logs, append, clear}}>{children}</Provider>;
};
export {LogsProvider as default, LogsContext};

103
src/contexts/storage.tsx Normal file
Просмотреть файл

@ -0,0 +1,103 @@
import React, {useState, useEffect} from 'react';
import {IoTCCredentials} from 'react-native-azure-iotcentral-client';
import * as Keychain from 'react-native-keychain';
import {Debug, Log} from '../tools/CustomLogger';
import {StateUpdater} from '../types';
const USERNAME = 'IOTC_PAD_CLIENT';
type IStorageState = {
dark?: boolean;
simulated: boolean;
credentials: IoTCCredentials | null;
initialized: boolean;
};
export type IStorageContext = IStorageState & {
save: (state: Partial<IStorageState>, store?: boolean) => Promise<void>;
read: () => Promise<void>;
clear: () => Promise<void>;
};
const StorageContext = React.createContext({} as IStorageContext);
const {Provider} = StorageContext;
const retrieveStorage = async (update: StateUpdater<IStorageContext>) => {
/**
* Credentials must be null if not available. This value means app has been initialized but no credentials are available.
*/
Debug(
`Retrieving credentials from storage.`,
'storage_context',
'retrieveStorage',
);
const data = await Keychain.getGenericPassword();
if (data && data.password) {
const parsed = JSON.parse(data.password) as IStorageState;
Debug(
`Parsed storage: ${data.password}`,
'storage_context',
'retrieveStorage',
);
if (parsed) {
if (!parsed.credentials) {
parsed.credentials = null;
}
update(current => ({...current, ...parsed, initialized: true}));
}
} else {
update(current => ({...current, credentials: null, initialized: true}));
}
};
const persist = async (state: IStorageState) => {
Log(`Persisting ${JSON.stringify(state)}`);
await Keychain.setGenericPassword(USERNAME, JSON.stringify(state));
};
const StorageProvider: React.FC<{children: React.ReactNode}> = ({children}) => {
const [state, setState] = useState<IStorageContext>({
credentials: null,
simulated: false,
initialized: false,
save: async (data: Partial<IStorageState>, store: boolean = true) => {
const newState = {...state, ...data};
if (store) {
await persist(newState);
}
setState(newState);
},
read: async () => {
await retrieveStorage(setState);
},
clear: async () => {
await Keychain.resetGenericPassword();
setState(current => ({
...current,
simulated: false,
credentials: null,
}));
},
});
// read from storage
useEffect(() => {
Debug(
`Currently credentials:${state.credentials}`,
'storage_provider',
'initial_useeffect',
);
retrieveStorage(setState);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
// const contextObj = React.useMemo(
// () => ({
// ...state,
// ,
// }),
// [state],
// );
return <Provider value={state}>{children}</Provider>;
};
export {StorageProvider as default, StorageContext};

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше