From 41f3c7a4da9c8f1cc5600ad23f5dd958b14ede12 Mon Sep 17 00:00:00 2001 From: wangyue Date: Mon, 20 Jan 2025 11:02:06 +0800 Subject: [PATCH] chore: add example dir Signed-off-by: wangyue --- .gitignore | 4 +- OAT.xml | 3 + example/.gitignore | 71 ++++++++ example/app.json | 4 + example/babel.config.js | 5 + example/contexts.ts | 3 + example/harmony/.gitignore | 24 +++ example/harmony/AppScope/app.json5 | 10 ++ .../resources/base/element/string.json | 8 + .../resources/base/media/app_icon.png | Bin 0 -> 6790 bytes example/harmony/build-profile.template.json5 | 40 +++++ example/harmony/codelinter.json | 32 ++++ example/harmony/entry/.gitignore | 7 + example/harmony/entry/build-profile.json5 | 19 +++ example/harmony/entry/hvigorfile.ts | 17 ++ example/harmony/entry/oh-package.json5 | 11 ++ example/harmony/entry/src/main/cpp/.gitignore | 2 + .../harmony/entry/src/main/cpp/CMakeLists.txt | 32 ++++ .../entry/src/main/cpp/PackageProvider.cpp | 20 +++ .../entry/src/main/ets/RNPackagesFactory.ets | 19 +++ .../main/ets/entryability/EntryAbility.ets | 19 +++ .../entry/src/main/ets/pages/Index.ets | 118 ++++++++++++++ example/harmony/entry/src/main/module.json5 | 52 ++++++ .../entry/src/main/resources/.gitignore | 1 + .../main/resources/base/element/color.json | 8 + .../main/resources/base/element/string.json | 16 ++ .../resources/base/profile/main_pages.json | 5 + .../entry/src/main/resources/rawfile/1.txt | 1 + example/harmony/format.ps1 | 12 ++ example/harmony/hvigor/.gitignore | 1 + example/harmony/hvigor/hvigor-config.json5 | 21 +++ example/harmony/hvigorfile.ts | 2 + example/harmony/oh-package.json5 | 14 ++ example/index.js | 12 ++ example/jest.config.js | 13 ++ example/metro.config.js | 24 +++ example/package.json | 66 ++++++++ example/scripts/create-build-profile.js | 39 +++++ example/src/Example.tsx | 152 ++++++++++++++++++ example/tsconfig.json | 14 ++ harmony/image_editor.har | Bin 0 -> 7812 bytes harmony/image_editor/BuildProfile.ets | 24 +++ harmony/image_editor/oh-package-lock.json5 | 19 +++ .../src/main/ets/ImageEditorModule.ts | 2 +- harmony/image_editor/src/main/module.json5 | 7 +- 45 files changed, 969 insertions(+), 4 deletions(-) create mode 100644 example/.gitignore create mode 100644 example/app.json create mode 100644 example/babel.config.js create mode 100644 example/contexts.ts create mode 100644 example/harmony/.gitignore create mode 100644 example/harmony/AppScope/app.json5 create mode 100644 example/harmony/AppScope/resources/base/element/string.json create mode 100644 example/harmony/AppScope/resources/base/media/app_icon.png create mode 100644 example/harmony/build-profile.template.json5 create mode 100644 example/harmony/codelinter.json create mode 100644 example/harmony/entry/.gitignore create mode 100644 example/harmony/entry/build-profile.json5 create mode 100644 example/harmony/entry/hvigorfile.ts create mode 100644 example/harmony/entry/oh-package.json5 create mode 100644 example/harmony/entry/src/main/cpp/.gitignore create mode 100644 example/harmony/entry/src/main/cpp/CMakeLists.txt create mode 100644 example/harmony/entry/src/main/cpp/PackageProvider.cpp create mode 100644 example/harmony/entry/src/main/ets/RNPackagesFactory.ets create mode 100644 example/harmony/entry/src/main/ets/entryability/EntryAbility.ets create mode 100644 example/harmony/entry/src/main/ets/pages/Index.ets create mode 100644 example/harmony/entry/src/main/module.json5 create mode 100644 example/harmony/entry/src/main/resources/.gitignore create mode 100644 example/harmony/entry/src/main/resources/base/element/color.json create mode 100644 example/harmony/entry/src/main/resources/base/element/string.json create mode 100644 example/harmony/entry/src/main/resources/base/profile/main_pages.json create mode 100644 example/harmony/entry/src/main/resources/rawfile/1.txt create mode 100644 example/harmony/format.ps1 create mode 100644 example/harmony/hvigor/.gitignore create mode 100644 example/harmony/hvigor/hvigor-config.json5 create mode 100644 example/harmony/hvigorfile.ts create mode 100644 example/harmony/oh-package.json5 create mode 100644 example/index.js create mode 100644 example/jest.config.js create mode 100644 example/metro.config.js create mode 100644 example/package.json create mode 100644 example/scripts/create-build-profile.js create mode 100644 example/src/Example.tsx create mode 100644 example/tsconfig.json create mode 100644 harmony/image_editor.har create mode 100644 harmony/image_editor/BuildProfile.ets create mode 100644 harmony/image_editor/oh-package-lock.json5 diff --git a/.gitignore b/.gitignore index 4d31fb3..f82fc89 100644 --- a/.gitignore +++ b/.gitignore @@ -79,5 +79,5 @@ lefthook.yml # eslint .eslintcache -scripts -harmony/image_editor.har \ No newline at end of file +./scripts/* +*.tgz diff --git a/OAT.xml b/OAT.xml index bf6666b..bd897f2 100644 --- a/OAT.xml +++ b/OAT.xml @@ -16,6 +16,7 @@ + @@ -32,6 +33,7 @@ + @@ -52,6 +54,7 @@ + diff --git a/example/.gitignore b/example/.gitignore new file mode 100644 index 0000000..7613cde --- /dev/null +++ b/example/.gitignore @@ -0,0 +1,71 @@ +.husky +bundle.harmony.js +package-lock.json +*.hbc +lintCppResult.txt + +# --- + +# 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 +*.hprof +.cxx/ +*.keystore +!debug.keystore +BuildProfile.ets + +# node.js +# +node_modules/ +npm-debug.log +yarn-error.log + +# 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 +**/fastlane/test_output + +# Bundle artifact +*.jsbundle + +# Ruby / CocoaPods +/vendor/bundle/ + +# Temporary files created by Metro to check the health of the file watcher +.metro-health-check* +*.htrace \ No newline at end of file diff --git a/example/app.json b/example/app.json new file mode 100644 index 0000000..7586f6f --- /dev/null +++ b/example/app.json @@ -0,0 +1,4 @@ +{ + "name": "app_name", + "displayName": "tester" +} \ No newline at end of file diff --git a/example/babel.config.js b/example/babel.config.js new file mode 100644 index 0000000..4811361 --- /dev/null +++ b/example/babel.config.js @@ -0,0 +1,5 @@ +module.exports = { + presets: ['module:metro-react-native-babel-preset'], + plugins: [ + ], +}; diff --git a/example/contexts.ts b/example/contexts.ts new file mode 100644 index 0000000..9437598 --- /dev/null +++ b/example/contexts.ts @@ -0,0 +1,3 @@ +import React from 'react'; + +export const AppParamsContext = React.createContext(undefined); diff --git a/example/harmony/.gitignore b/example/harmony/.gitignore new file mode 100644 index 0000000..72d73fb --- /dev/null +++ b/example/harmony/.gitignore @@ -0,0 +1,24 @@ +# it may cause some issues when building the project when switching branches +package-lock.json +# we add this because we want to keep the signing configs out of git +/build-profile.json5 + +rnoh_modules + +**/oh-package-lock.json5 +# --- + +/node_modules +/local.properties +/.idea +**/build +/.hvigor +.cxx +/.clangd +/.clang-format +/.clang-tidy +/oh_modules +hvigorw +hvigorw.bat +hvigor/hvigor-wrapper.js + diff --git a/example/harmony/AppScope/app.json5 b/example/harmony/AppScope/app.json5 new file mode 100644 index 0000000..058bd39 --- /dev/null +++ b/example/harmony/AppScope/app.json5 @@ -0,0 +1,10 @@ +{ + "app": { + "bundleName": "com.harmony.wechat.lib.demo", + "vendor": "example", + "versionCode": 1000000, + "versionName": "1.0.0", + "icon": "$media:app_icon", + "label": "$string:app_name" + } +} diff --git a/example/harmony/AppScope/resources/base/element/string.json b/example/harmony/AppScope/resources/base/element/string.json new file mode 100644 index 0000000..698a720 --- /dev/null +++ b/example/harmony/AppScope/resources/base/element/string.json @@ -0,0 +1,8 @@ +{ + "string": [ + { + "name": "app_name", + "value": "RN Tester" + } + ] +} diff --git a/example/harmony/AppScope/resources/base/media/app_icon.png b/example/harmony/AppScope/resources/base/media/app_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..ce307a8827bd75456441ceb57d530e4c8d45d36c GIT binary patch literal 6790 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 PackageProvider::getPackages(Package::Context ctx) +{ + return { + std::make_shared(ctx), // generated by codegen-harmony v1 at app build time + std::make_shared(ctx), + }; +} diff --git a/example/harmony/entry/src/main/ets/RNPackagesFactory.ets b/example/harmony/entry/src/main/ets/RNPackagesFactory.ets new file mode 100644 index 0000000..a7d3eb5 --- /dev/null +++ b/example/harmony/entry/src/main/ets/RNPackagesFactory.ets @@ -0,0 +1,19 @@ +/* +* +* Copyright (c) 2024 Huawei Device Co., Ltd. All rights reserved +* Use of this source code is governed by a MIT license that can be +* found in the LICENSE file +* +*/ + +import type { RNPackageContext, RNPackage } from '@rnoh/react-native-openharmony/ts'; +import {ImageEditorPackage} from '@react-native-ohos/image-editor/ts'; +/** + * Importing ets files from top level barrel file doesn't work. + */ + +export function createRNPackages(ctx: RNPackageContext): RNPackage[] { + return [ + new ImageEditorPackage(ctx), + ]; +} diff --git a/example/harmony/entry/src/main/ets/entryability/EntryAbility.ets b/example/harmony/entry/src/main/ets/entryability/EntryAbility.ets new file mode 100644 index 0000000..3574649 --- /dev/null +++ b/example/harmony/entry/src/main/ets/entryability/EntryAbility.ets @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. All rights reserved + * Use of this source code is governed by a MIT license that can be + * found in the LICENSE file. + */ + +import {RNAbility} from '@rnoh/react-native-openharmony'; +import { AbilityConstant, Want } from '@kit.AbilityKit'; + +export default class EntryAbility extends RNAbility { + + onCreate(want: Want) { + super.onCreate(want) + } + + getPagePath() { + return 'pages/Index'; + } +} diff --git a/example/harmony/entry/src/main/ets/pages/Index.ets b/example/harmony/entry/src/main/ets/pages/Index.ets new file mode 100644 index 0000000..5d4aa1e --- /dev/null +++ b/example/harmony/entry/src/main/ets/pages/Index.ets @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. All rights reserved + * Use of this source code is governed by a MIT license that can be + * found in the LICENSE file. + */ + +import { + AnyJSBundleProvider, + ComponentBuilderContext, + FileJSBundleProvider, + MetroJSBundleProvider, + ResourceJSBundleProvider, + RNApp, + RNOHErrorDialog, + RNOHLogger, + TraceJSBundleProviderDecorator, + RNOHCoreContext +} from '@rnoh/react-native-openharmony'; +import font from '@ohos.font'; +import { createRNPackages } from '../RNPackagesFactory'; + +const arkTsComponentNames: Array = [ +]; + +@Builder +export function buildCustomRNComponent(ctx: ComponentBuilderContext) { + // There seems to be a problem with the placement of ArkTS components in mixed mode. Nested Stack temporarily avoided. + Stack() { + } + .position({ x: 0, y: 0 }) + +} + +const wrappedCustomRNComponentBuilder = wrapBuilder(buildCustomRNComponent) + +/** + * If you want to use custom fonts, you need to register them here. + * We should support react-native-asset to handle registering fonts automatically. + */ +const fonts: font.FontOptions[] = [ + { + familyName: 'Pacifico-Regular', + familySrc: '/assets/fonts/Pacifico-Regular.ttf' + }, + { + familyName: 'StintUltraCondensed-Regular', + familySrc: '/assets/fonts/StintUltraCondensed-Regular.ttf' + } +] + +@Entry +@Component +struct Index { + @StorageLink('RNOHCoreContext') private rnohCoreContext: RNOHCoreContext | undefined = undefined + @State shouldShow: boolean = false + private logger!: RNOHLogger + bundlePath: string = 'bunlde.harmony.js' + @State hasBundle: boolean = false + + aboutToAppear() { + this.logger = this.rnohCoreContext!.logger.clone("Index") + const stopTracing = this.logger.clone("aboutToAppear").startTracing() + for (const customFont of fonts) { + font.registerFont(customFont) + } + + this.shouldShow = true + stopTracing() + } + + onBackPress(): boolean | undefined { + // NOTE: this is required since `Ability`'s `onBackPressed` function always + // terminates or puts the app in the background, but we want Ark to ignore it completely + // when handled by RN + this.rnohCoreContext!.dispatchBackPress() + return true + } + + build() { + Column() { + if (this.rnohCoreContext && this.shouldShow) { + if (this.rnohCoreContext?.isDebugModeEnabled) { + RNOHErrorDialog({ ctx: this.rnohCoreContext }) + } + RNApp({ + rnInstanceConfig: { + createRNPackages, + enableNDKTextMeasuring: true, + enableBackgroundExecutor: false, + enableCAPIArchitecture: true, + arkTsComponentNames: arkTsComponentNames, + }, + initialProps: { "foo": "bar" } as Record, + appKey: "app_name", + wrappedCustomRNComponentBuilder: wrappedCustomRNComponentBuilder, + onSetUp: (rnInstance) => { + rnInstance.enableFeatureFlag("ENABLE_RN_INSTANCE_CLEAN_UP") + }, + jsBundleProvider: new TraceJSBundleProviderDecorator( + new AnyJSBundleProvider([ + new MetroJSBundleProvider(), + // NOTE: to load the bundle from file, place it in + // `/data/app/el2/100/base/com.rnoh.tester/files/bundle.harmony.js` + // on your device. The path mismatch is due to app sandboxing on HarmonyOS + new FileJSBundleProvider('/data/storage/el2/base/files/bundle.harmony.js'), + // new FileJSBundleProvider(context.filesDir + '/' + this.bundlePath), + new ResourceJSBundleProvider(this.rnohCoreContext.uiAbilityContext.resourceManager, 'hermes_bundle.hbc'), + new ResourceJSBundleProvider(this.rnohCoreContext.uiAbilityContext.resourceManager, 'bundle.harmony.js') + ]), + this.rnohCoreContext.logger), + }) + } + Text("1233333333122 1212323") + } + .height('100%') + .width('100%') + } +} diff --git a/example/harmony/entry/src/main/module.json5 b/example/harmony/entry/src/main/module.json5 new file mode 100644 index 0000000..fdf398e --- /dev/null +++ b/example/harmony/entry/src/main/module.json5 @@ -0,0 +1,52 @@ +{ + "module": { + "name": "entry", + "type": "entry", + "description": "$string:module_desc", + "mainElement": "EntryAbility", + "deviceTypes": [ + "default" + ], + "querySchemes": [ + "weixin", + ], + "deliveryWithInstall": true, + "installationFree": false, + "pages": "$profile:main_pages", + // below property is supported from 5.0.0 - it is needed by bundleManager.canOpenLink to check if the app can open some url + // "querySchemes": ["maps", "http", "https", "customDomain"], + "requestPermissions": [ + { + "name": "ohos.permission.INTERNET" + }, + ], + "metadata": [ + { + "name": "OPTLazyForEach", + "value": "true", + } + ], + "abilities": [ + { + "name": "EntryAbility", + "srcEntry": "./ets/entryability/EntryAbility.ets", + "description": "$string:EntryAbility_desc", + "icon": "$media:app_icon", + "label": "$string:EntryAbility_label", + "startWindowIcon": "$media:app_icon", + "startWindowBackground": "$color:start_window_background", + "visible": true, + "skills": [ + { + "entities": [ + "entity.system.home" + ], + "actions": [ + "action.system.home" + ] + } + ] + } + ] + } +} diff --git a/example/harmony/entry/src/main/resources/.gitignore b/example/harmony/entry/src/main/resources/.gitignore new file mode 100644 index 0000000..037cea9 --- /dev/null +++ b/example/harmony/entry/src/main/resources/.gitignore @@ -0,0 +1 @@ +rawfile/assets diff --git a/example/harmony/entry/src/main/resources/base/element/color.json b/example/harmony/entry/src/main/resources/base/element/color.json new file mode 100644 index 0000000..3c71296 --- /dev/null +++ b/example/harmony/entry/src/main/resources/base/element/color.json @@ -0,0 +1,8 @@ +{ + "color": [ + { + "name": "start_window_background", + "value": "#FFFFFF" + } + ] +} \ No newline at end of file diff --git a/example/harmony/entry/src/main/resources/base/element/string.json b/example/harmony/entry/src/main/resources/base/element/string.json new file mode 100644 index 0000000..074b217 --- /dev/null +++ b/example/harmony/entry/src/main/resources/base/element/string.json @@ -0,0 +1,16 @@ +{ + "string": [ + { + "name": "module_desc", + "value": "module description" + }, + { + "name": "EntryAbility_desc", + "value": "description" + }, + { + "name": "EntryAbility_label", + "value": "RN Tester" + } + ] +} \ No newline at end of file diff --git a/example/harmony/entry/src/main/resources/base/profile/main_pages.json b/example/harmony/entry/src/main/resources/base/profile/main_pages.json new file mode 100644 index 0000000..1898d94 --- /dev/null +++ b/example/harmony/entry/src/main/resources/base/profile/main_pages.json @@ -0,0 +1,5 @@ +{ + "src": [ + "pages/Index" + ] +} diff --git a/example/harmony/entry/src/main/resources/rawfile/1.txt b/example/harmony/entry/src/main/resources/rawfile/1.txt new file mode 100644 index 0000000..71f6ee3 --- /dev/null +++ b/example/harmony/entry/src/main/resources/rawfile/1.txt @@ -0,0 +1 @@ +text test \ No newline at end of file diff --git a/example/harmony/format.ps1 b/example/harmony/format.ps1 new file mode 100644 index 0000000..7735881 --- /dev/null +++ b/example/harmony/format.ps1 @@ -0,0 +1,12 @@ +$directoryPath = Split-Path -Parent $MyInvocation.MyCommand.Path +$filePaths = Get-ChildItem $directoryPath -Recurse -Include *.h, *.cpp | +Where-Object { + $_.DirectoryName -notmatch 'third-party' -and + $_.DirectoryName -notmatch 'patches' -and + $_.DirectoryName -notmatch 'node_modules' -and + $_.DirectoryName -notmatch '.cxx' -and + $_.DirectoryName -notmatch 'build' +} +foreach ($filePath in $filePaths) { + & "clang-format.exe" -style=file -i $filePath.FullName +} \ No newline at end of file diff --git a/example/harmony/hvigor/.gitignore b/example/harmony/hvigor/.gitignore new file mode 100644 index 0000000..aa1ec1e --- /dev/null +++ b/example/harmony/hvigor/.gitignore @@ -0,0 +1 @@ +*.tgz diff --git a/example/harmony/hvigor/hvigor-config.json5 b/example/harmony/hvigor/hvigor-config.json5 new file mode 100644 index 0000000..c8ba182 --- /dev/null +++ b/example/harmony/hvigor/hvigor-config.json5 @@ -0,0 +1,21 @@ +{ + "modelVersion": "5.0.0", + "dependencies": { + }, + "execution": { + // "analyze": "default", /* Define the build analyze mode. Value: [ "default" | "verbose" | false ]. Default: "default" */ + // "daemon": true, /* Enable daemon compilation. Value: [ true | false ]. Default: true */ + // "incremental": true, /* Enable incremental compilation. Value: [ true | false ]. Default: true */ + // "parallel": true, /* Enable parallel compilation. Value: [ true | false ]. Default: true */ + // "typeCheck": false, /* Enable typeCheck. Value: [ true | false ]. Default: false */ + }, + "logging": { + // "level": "info" /* Define the log level. Value: [ "debug" | "info" | "warn" | "error" ]. Default: "info" */ + }, + "debugging": { + "stacktrace": false /* Disable stacktrace compilation. Value: [ true | false ]. Default: false */ + }, + "nodeOptions": { + // "maxOldSpaceSize": 4096 /* Enable nodeOptions maxOldSpaceSize compilation. Unit M. Used for the daemon process */ + } +} \ No newline at end of file diff --git a/example/harmony/hvigorfile.ts b/example/harmony/hvigorfile.ts new file mode 100644 index 0000000..6478186 --- /dev/null +++ b/example/harmony/hvigorfile.ts @@ -0,0 +1,2 @@ +// Script for compiling build behavior. It is built in the build plug-in and cannot be modified currently. +export { appTasks } from '@ohos/hvigor-ohos-plugin'; \ No newline at end of file diff --git a/example/harmony/oh-package.json5 b/example/harmony/oh-package.json5 new file mode 100644 index 0000000..25ebaf5 --- /dev/null +++ b/example/harmony/oh-package.json5 @@ -0,0 +1,14 @@ +{ + "modelVersion": "5.0.0", + "license": "ISC", + "name": "rnoh", + "description": "example description", + "repository": {}, + "version": "1.0.0", + "dependencies": { + "@rnoh/react-native-openharmony": "0.72.38" + }, + "overrides": { + "@rnoh/react-native-openharmony": "0.72.38" + } +} diff --git a/example/index.js b/example/index.js new file mode 100644 index 0000000..9f1e098 --- /dev/null +++ b/example/index.js @@ -0,0 +1,12 @@ +/* +* +* Copyright (c) 2024 Huawei Device Co., Ltd. All rights reserved +* Use of this source code is governed by a MIT license that can be +* found in the LICENSE file +* +*/ +import {AppRegistry, View, Text} from 'react-native'; +import {name as appName} from './app.json'; +import App from './src/Example'; + +AppRegistry.registerComponent(appName, () => App); \ No newline at end of file diff --git a/example/jest.config.js b/example/jest.config.js new file mode 100644 index 0000000..bfbfdcd --- /dev/null +++ b/example/jest.config.js @@ -0,0 +1,13 @@ +/* +* +* Copyright (c) 2024 Huawei Device Co., Ltd. All rights reserved +* Use of this source code is governed by a MIT license that can be +* found in the LICENSE file +* +*/ + +/** @type {import('ts-jest').JestConfigWithTsJest} */ +module.exports = { + preset: 'ts-jest', + testEnvironment: 'node', +}; diff --git a/example/metro.config.js b/example/metro.config.js new file mode 100644 index 0000000..f33c325 --- /dev/null +++ b/example/metro.config.js @@ -0,0 +1,24 @@ +const {mergeConfig, getDefaultConfig} = require('@react-native/metro-config'); +const {createHarmonyMetroConfig} = require('react-native-harmony/metro.config'); + +/** + * @type {import("metro-config").ConfigT} + */ +const config = { + transformer: { + getTransformOptions: async () => ({ + transform: { + experimentalImportSupport: false, + inlineRequires: true, + }, + }), + }, +}; + +module.exports = mergeConfig( + getDefaultConfig(__dirname), + createHarmonyMetroConfig({ + reactNativeHarmonyPackageName: 'react-native-harmony', + }), + config, +); diff --git a/example/package.json b/example/package.json new file mode 100644 index 0000000..d658da1 --- /dev/null +++ b/example/package.json @@ -0,0 +1,66 @@ +{ + "name": "react-native-harmony-tester", + "version": "1.0.0", + "private": true, + "scripts": { + "reStart": "npm run install:pkg && npm run codegen && hdc rport tcp:8081 tcp:8081 && react-native start", + "start": "hdc rport tcp:8081 tcp:8081 && react-native start", + "codegen": "react-native codegen-harmony --rnoh-module-path ./harmony/entry/oh_modules/@rnoh/react-native-openharmony", + "pack:pkg": "cd ../ && npm i --legacy-peer-deps && npm pack && cd ./example", + "install:pkg": "npm uninstall @react-native-ohos/image-editor && npm run pack:pkg && npm i @react-native-ohos/image-editor@file:../react-native-ohos-image-editor-3.2.1-rc.2.tgz", + "dev": "npm run codegen && react-native bundle-harmony --dev --minify=false", + "prod": "npm run codegen && react-native bundle-harmony --dev=false --minify=true", + "postinstall": "node ./scripts/create-build-profile.js", + "fast:pkg": "npm run pack:pkg && npm i --legacy-peer-deps && npm run dev" + }, + "dependencies": { + "@gorhom/portal": "^1.0.14", + "@react-native-ohos/image-editor": "file:../react-native-ohos-image-editor-3.2.1-rc.2.tgz", + "react": "18.2.0", + "react-native": "0.72.5", + "@rnoh/testerino": "npm:@react-native-oh-tpl/testerino@0.0.9", + "react-native-harmony": "npm:@react-native-oh/react-native-harmony@^0.72.32" + }, + "devDependencies": { + "@babel/core": "^7.20.0", + "@babel/preset-env": "^7.20.0", + "@babel/runtime": "^7.20.0", + "@react-native-community/eslint-config": "^3.2.0", + "@react-native/eslint-config": "^0.74.0", + "@react-native/metro-config": "^0.72.6", + "@tsconfig/react-native": "^2.0.2", + "@types/chai": "^4.3.4", + "@types/d3-scale-chromatic": "^3.0.0", + "@types/fs-extra": "^11.0.1", + "@types/jest": "^29.5.5", + "@types/metro-config": "^0.76.2", + "@types/react": "17.0.14", + "@types/react-dom": "17.0.14", + "@types/react-test-renderer": "^18.0.0", + "babel-jest": "^29.2.1", + "csv-parser": "^3.0.0", + "eslint": "^8.19.0", + "eslint-plugin-prettier": "^5.0.1", + "fs-extra": "^11.1.1", + "husky": "^8.0.3", + "jest": "^29.7.0", + "json5": "^2.2.3", + "metro": "^0.76.3", + "metro-config": "^0.76.3", + "metro-react-native-babel-preset": "0.73.9", + "prettier": "3.2.4", + "react-test-renderer": "18.2.0", + "simple-statistics": "^7.8.3", + "ts-jest": "^29.1.1", + "typescript": "^5.3.2", + "yargs": "^17.7.2" + }, + "overrides": { + "@rnoh/react-native-harmony-cli": "npm:@react-native-oh/react-native-harmony-cli@^0.0.27", + "@react-native-community/cli": "11.3.6", + "@react-native/codegen": "0.74.0" + }, + "resolutions": { + "@react-native-community/cli": "11.3.6" + } +} diff --git a/example/scripts/create-build-profile.js b/example/scripts/create-build-profile.js new file mode 100644 index 0000000..a7841d0 --- /dev/null +++ b/example/scripts/create-build-profile.js @@ -0,0 +1,39 @@ +const fs = require('fs'); +const JSON5 = require('json5'); +const path = require('path'); + +const templatePath = path.join( + __dirname, + '..', + 'harmony', + 'build-profile.template.json5', +); +const existingProfilePath = path.join( + __dirname, + '..', + 'harmony', + 'build-profile.json5', +); + +if (fs.existsSync(existingProfilePath)) { + let existingProfile = JSON5.parse( + fs.readFileSync(existingProfilePath, 'utf-8'), + ); + let template = JSON5.parse(fs.readFileSync(templatePath, 'utf-8')); + let signingConfigs = + existingProfile.app && existingProfile.app.signingConfigs; + + existingProfile = {...template}; + + if (signingConfigs) { + existingProfile.app.signingConfigs = signingConfigs; + } + + fs.writeFileSync( + existingProfilePath, + JSON5.stringify(existingProfile, null, 2), + ); +} else { + // File doesn't exist, create a copy from the template + fs.copyFileSync(templatePath, existingProfilePath); +} \ No newline at end of file diff --git a/example/src/Example.tsx b/example/src/Example.tsx new file mode 100644 index 0000000..b39987b --- /dev/null +++ b/example/src/Example.tsx @@ -0,0 +1,152 @@ +/* +* +* Copyright (c) 2024 Huawei Device Co., Ltd. All rights reserved +* Use of this source code is governed by a MIT license that can be +* found in the LICENSE file +* +*/ + +import React, { Component } from "react"; +import { + Image, + ScrollView, + Text, + View, + StyleSheet, + Button, + Alert, + KeyboardAvoidingView, +} from "react-native"; + +import ImageEditor from "@react-native-community/image-editor"; + +export interface Props { + // noop +} + +interface Size { + width: number; + height: number; +} + +interface State { + photoUri: any; + photoWidth: number; + photoHeight: number; + croppedImageURI: string | null; + targetSize?: Size; + cropHorizontal: boolean; +} + +class App extends Component { + constructor(props: Props) { + super(props); + this.state = { + photoUri: "https://octodex.github.com/images/OctoAsians_dex_Full.png", + photoWidth: 896, + photoHeight: 896, + croppedImageURI: null, + targetSize: { + width: 0, + height: 0, + }, + cropHorizontal: false, + }; + } + + _crop = async () => { + let cropData = { + offset: { x: 100, y: 100 }, + size: { width: 300, height: 300 }, + quality: 1, + format: "jpeg", + }; + if ( + cropData.size.width + cropData.offset.x > this.state.photoWidth || + cropData.size.height + cropData.offset.y > this.state.photoHeight + ) { + Alert.alert("The cropped size exceeds the original size"); + return; + } + const croppedImageURI = await ImageEditor.cropImage( + this.state.photoUri, + cropData + ); + if (croppedImageURI) { + this.setState({ + croppedImageURI, + targetSize: { + width: cropData.size.width, + height: cropData.size.height, + }, + }); + + if (this.state.targetSize.width >= this.state.targetSize.height) { + this.setState({ + cropHorizontal: true, + }); + } else { + this.setState({ + cropHorizontal: false, + }); + } + } + }; + + render() { + const { + photoUri, + photoWidth, + photoHeight, + croppedImageURI, + targetSize, + cropHorizontal, + } = this.state; + return ( + + + + + + {croppedImageURI ? ( + + + + ) : ( + 未生成图片 + )} + + {croppedImageURI} +