diff --git a/AppScope/app.json5 b/AppScope/app.json5 new file mode 100644 index 0000000000000000000000000000000000000000..7d9be58fe55d2b27adaaffb9b59ff2bc096657b6 --- /dev/null +++ b/AppScope/app.json5 @@ -0,0 +1,10 @@ +{ + "app": { + "bundleName": "com.example.knockfileshare", + "vendor": "example", + "versionCode": 1000000, + "versionName": "1.0.0", + "icon": "$media:layered_image", + "label": "$string:app_name" + } +} diff --git a/AppScope/resources/base/element/string.json b/AppScope/resources/base/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..2608907c665d53263a3b5c4ddf01294805e52736 --- /dev/null +++ b/AppScope/resources/base/element/string.json @@ -0,0 +1,8 @@ +{ + "string": [ + { + "name": "app_name", + "value": "KnockFileShare" + } + ] +} diff --git a/AppScope/resources/base/media/background.png b/AppScope/resources/base/media/background.png new file mode 100644 index 0000000000000000000000000000000000000000..923f2b3f27e915d6871871deea0420eb45ce102f Binary files /dev/null and b/AppScope/resources/base/media/background.png differ diff --git a/AppScope/resources/base/media/foreground.png b/AppScope/resources/base/media/foreground.png new file mode 100644 index 0000000000000000000000000000000000000000..eb9427585b36d14b12477435b6419d1f07b3e0bb Binary files /dev/null and b/AppScope/resources/base/media/foreground.png differ diff --git a/AppScope/resources/base/media/layered_image.json b/AppScope/resources/base/media/layered_image.json new file mode 100644 index 0000000000000000000000000000000000000000..fb49920440fb4d246c82f9ada275e26123a2136a --- /dev/null +++ b/AppScope/resources/base/media/layered_image.json @@ -0,0 +1,7 @@ +{ + "layered-image": + { + "background" : "$media:background", + "foreground" : "$media:foreground" + } +} \ No newline at end of file diff --git a/LICENCE b/LICENCE new file mode 100644 index 0000000000000000000000000000000000000000..18795a48d6b12fcdc1aa7bac9a9cb99f83815267 --- /dev/null +++ b/LICENCE @@ -0,0 +1,78 @@ + Copyright (c) 2025 Huawei Device Co., Ltd. All rights reserved. + + 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 + + http://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. + +Apache License, Version 2.0 +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. + +"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. + +2. Grant of Copyright License. + +Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. + +Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. + +You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: +1.You must give any other recipients of the Work or Derivative Works a copy of this License; and +2.You must cause any modified files to carry prominent notices stating that You changed the files; and +3.You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and +4.If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. + +You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. + +5. Submission of Contributions. + +Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. + +6. Trademarks. + +This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. + +Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. + +In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. + +While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS \ No newline at end of file diff --git a/README.md b/README.md index e7fbd6ecdf015d90c8c666c5bc4c089f862613f0..cd013e82a80b91c0397e5b54c530de4267a353c8 100644 --- a/README.md +++ b/README.md @@ -1,39 +1,59 @@ -# KnockFileShare +# 基于Share Kit实现碰一碰文件分享 -#### 介绍 -{**以下是 Gitee 平台说明,您可以替换此简介** -Gitee 是 OSCHINA 推出的基于 Git 的代码托管平台(同时支持 SVN)。专为开发者提供稳定、高效、安全的云端软件开发协作平台 -无论是个人、团队、或是企业,都能够用 Gitee 实现代码托管、项目管理、协作开发。企业项目请看 [https://gitee.com/enterprises](https://gitee.com/enterprises)} +### 介绍 -#### 软件架构 -软件架构说明 +本示例基于Share Kit实现了跨设备文件的快速分享功能:通过调用`harmonyShare.on ('knockShare')`方法注册碰一碰监听事件,在回调中触发`sharableTarget.share()`方法传输文件数据,即可完成碰一碰文件分享流程,供接收端设备获取。其中,接收端接收的文件默认存储于图库或文件管理系统,若接收端为PC端,应用可通过`harmonyShare.on('dataReceive')`方法注册文件接收监听,碰一碰后文件会自动保存至应用的沙箱目录。 +### 效果图预览 -#### 安装教程 +| 首页 | +|-----------------------------------| +| ![](screenshots/device/phone.png) | -1. xxxx -2. xxxx -3. xxxx +**使用说明** -#### 使用说明 +1. 设设备安装应用后,即可使用碰一碰文件分享功能,具体使用约束可参考[手机与手机碰一碰分享](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/knock-share-phone-to-phone)、[手机与PC/2in1碰一碰分享](https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/knock-share-phone-to-pc)。 +2. 在首页勾选文件后,通过碰一碰即可分享已选文件。 +3. 若接收端为PC设备,需确保手机与PC登录同一华为账号,方可实现碰一碰分享。 +4. 接收端文件默认存储于图库或文件管理器中,其中PC端应用可通过调用`harmonyShare.on('dataReceive')`方法注册文件接收监听,碰一碰传输的文件将存储至该应用的沙箱路径下。 +5. PC端应用接收时最大支持接收5个文件。 -1. xxxx -2. xxxx -3. xxxx +### 工程结构 -#### 参与贡献 +``` +├───entry/src/main/ets +│ ├───constants +│ │ └───BreakpointConstants.ets // 常量 +│ ├───controller +│ │ └───KnockController.ets // 碰一碰分享控制类 +│ ├───entryability +│ │ └───EntryAbility.ets // 程序入口类 +│ ├───entrybackupability +│ │ └───EntryBackupAbility.ets // 数据备份恢复类 +│ ├───model +│ │ └───FileData.ets // 文件数据 +│ ├───pages +│ │ └───Index.ets // 首页 +│ └───utils +│ ├───BreakpointSystem.ets // 一多断点工具类 +│ └───FileUtil.ets // 文件工具类 +└───entry/src/main/resources // 资源目录 +``` -1. Fork 本仓库 -2. 新建 Feat_xxx 分支 -3. 提交代码 -4. 新建 Pull Request +### 具体实现 +* 通过Share Kit的systemShare模块实现碰一碰分享功能以及PC设备应用内文件接收功能。 +### 相关权限 -#### 特技 +**不涉及** -1. 使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md -2. Gitee 官方博客 [blog.gitee.com](https://blog.gitee.com) -3. 你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解 Gitee 上的优秀开源项目 -4. [GVP](https://gitee.com/gvp) 全称是 Gitee 最有价值开源项目,是综合评定出的优秀开源项目 -5. Gitee 官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help) -6. Gitee 封面人物是一档用来展示 Gitee 会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/) +### 模块依赖 + +**不涉及** + +### 约束与限制 + +1. 本示例仅支持标准系统上运行,支持设备:华为手机、PC/2in1。 +2. HarmonyOS系统:HarmonyOS 6.0.0 beta2及以上。 +3. DevEco Studio版本:DevEco Studio 6.0.0 beta2及以上。 +4. HarmonyOS SDK版本:HarmonyOS 6.0.0 beta2 SDK及以上。 \ No newline at end of file diff --git a/build-profile.json5 b/build-profile.json5 new file mode 100644 index 0000000000000000000000000000000000000000..c4e8cef12735e3a7929c1740117603c46528ebe4 --- /dev/null +++ b/build-profile.json5 @@ -0,0 +1,42 @@ +{ + "app": { + "signingConfigs": [], + "products": [ + { + "name": "default", + "signingConfig": "default", + "targetSdkVersion": "6.0.0(20)", + "compatibleSdkVersion": "6.0.0(20)", + "runtimeOS": "HarmonyOS", + "buildOption": { + "strictMode": { + "caseSensitiveCheck": true, + "useNormalizedOHMUrl": true + } + } + } + ], + "buildModeSet": [ + { + "name": "debug", + }, + { + "name": "release" + } + ] + }, + "modules": [ + { + "name": "entry", + "srcPath": "./entry", + "targets": [ + { + "name": "default", + "applyToProducts": [ + "default" + ] + } + ] + } + ] +} \ No newline at end of file diff --git a/entry/build-profile.json5 b/entry/build-profile.json5 new file mode 100644 index 0000000000000000000000000000000000000000..0311b505dbf43f0d22662c8d783c5f4464d15b15 --- /dev/null +++ b/entry/build-profile.json5 @@ -0,0 +1,25 @@ +{ + "apiType": "stageMode", + "buildOption": { + }, + "buildOptionSet": [ + { + "name": "release", + "arkOptions": { + "obfuscation": { + "ruleOptions": { + "enable": false, + "files": [ + "./obfuscation-rules.txt" + ] + } + } + } + }, + ], + "targets": [ + { + "name": "default" + } + ] +} \ No newline at end of file diff --git a/entry/hvigorfile.ts b/entry/hvigorfile.ts new file mode 100644 index 0000000000000000000000000000000000000000..b0e3a1ab98a91bc918d6404b2413111a5011f14a --- /dev/null +++ b/entry/hvigorfile.ts @@ -0,0 +1,6 @@ +import { hapTasks } from '@ohos/hvigor-ohos-plugin'; + +export default { + system: hapTasks, /* Built-in plugin of Hvigor. It cannot be modified. */ + plugins: [] /* Custom plugin to extend the functionality of Hvigor. */ +} \ No newline at end of file diff --git a/entry/obfuscation-rules.txt b/entry/obfuscation-rules.txt new file mode 100644 index 0000000000000000000000000000000000000000..272efb6ca3f240859091bbbfc7c5802d52793b0b --- /dev/null +++ b/entry/obfuscation-rules.txt @@ -0,0 +1,23 @@ +# Define project specific obfuscation rules here. +# You can include the obfuscation configuration files in the current module's build-profile.json5. +# +# For more details, see +# https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/source-obfuscation-V5 + +# Obfuscation options: +# -disable-obfuscation: disable all obfuscations +# -enable-property-obfuscation: obfuscate the property names +# -enable-toplevel-obfuscation: obfuscate the names in the global scope +# -compact: remove unnecessary blank spaces and all line feeds +# -remove-log: remove all console.* statements +# -print-namecache: print the name cache that contains the mapping from the old names to new names +# -apply-namecache: reuse the given cache file + +# Keep options: +# -keep-property-name: specifies property names that you want to keep +# -keep-global-name: specifies names that you want to keep in the global scope + +-enable-property-obfuscation +-enable-toplevel-obfuscation +-enable-filename-obfuscation +-enable-export-obfuscation \ No newline at end of file diff --git a/entry/oh-package.json5 b/entry/oh-package.json5 new file mode 100644 index 0000000000000000000000000000000000000000..248c3b7541a589682a250f86a6d3ecf7414d2d6a --- /dev/null +++ b/entry/oh-package.json5 @@ -0,0 +1,10 @@ +{ + "name": "entry", + "version": "1.0.0", + "description": "Please describe the basic information.", + "main": "", + "author": "", + "license": "", + "dependencies": {} +} + diff --git a/entry/src/main/ets/constants/BreakpointConstants.ets b/entry/src/main/ets/constants/BreakpointConstants.ets new file mode 100644 index 0000000000000000000000000000000000000000..254068a6573dfb3b409aac3de7793a52a10ce36a --- /dev/null +++ b/entry/src/main/ets/constants/BreakpointConstants.ets @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * 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 + * + * http://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. + */ + +/** + * Constants for breakpoint. + */ +export class BreakpointConstants { + /** + * Breakpoints that represent small device types. + */ + public static readonly BREAKPOINT_XS: string = 'xs'; + /** + * Breakpoints that represent small device types. + */ + public static readonly BREAKPOINT_SM: string = 'sm'; + /** + * Breakpoints that represent middle device types. + */ + public static readonly BREAKPOINT_MD: string = 'md'; + /** + * Breakpoints that represent large device types. + */ + public static readonly BREAKPOINT_LG: string = 'lg'; + /** + * Breakpoints representing the type of oversized equipment. + */ + public static readonly BREAKPOINT_XL: string = 'xl'; + /** + * Breakpoint range sm + */ + public static readonly RANGE_SM: string = '(320vp<=width<600vp)'; + /** + * Breakpoint range md + */ + public static readonly RANGE_MD: string = '(600vp<=width<840vp)'; + /** + * Breakpoint range lg + */ + public static readonly RANGE_LG: string = '(840vp<=width)'; + /** + * Breakpoint value sm/md/lg + */ + public static readonly BREAKPOINT_VALUE: Array = ['320vp', '600vp', '840vp']; + /** + * AppStorage key breakpoint + */ + public static readonly BREAKPOINT_NAME: string = 'KnockFileShare_breakpoint'; +} \ No newline at end of file diff --git a/entry/src/main/ets/controller/KnockController.ets b/entry/src/main/ets/controller/KnockController.ets new file mode 100644 index 0000000000000000000000000000000000000000..b3dbcd838fc514e845d9108907cfedcddcb98739 --- /dev/null +++ b/entry/src/main/ets/controller/KnockController.ets @@ -0,0 +1,229 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * 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 + * + * http://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. + */ + +import { harmonyShare, systemShare } from '@kit.ShareKit'; +import { fileUri } from '@kit.CoreFileKit'; +import { BusinessError } from '@kit.BasicServicesKit'; +import { uniformTypeDescriptor } from '@kit.ArkData'; +import { common } from '@kit.AbilityKit'; +import { window } from '@kit.ArkUI'; +import { hilog } from '@kit.PerformanceAnalysisKit'; +import { FileUtil } from '../utils/FileUtil'; +import { FileData } from '../model/FileData'; + +export class KnockController { + private static controller: KnockController; + private context: common.UIAbilityContext | undefined = undefined; + + /** + * Initialize a KnockController instance. + * + * @param context common.UIAbilityContext. + * @returns KnockController. + */ + public static getInstance(context: common.UIAbilityContext): KnockController { + if (!KnockController.controller) { + KnockController.controller = new KnockController(context); + } + return KnockController.controller; + } + + constructor(context: common.UIAbilityContext) { + this.context = context; + } + + // [Start FileShare] + /** + * Knock listening callback. + * + * @param target After the Huawei Share event is triggered, + * you can call back the parameters and share them across devices. + */ + public immersiveCallback(target: harmonyShare.SharableTarget) { + let fileShare = AppStorage.get('KnockFileShare_fileShare') as number[]; + let videoDataList = AppStorage.get('KnockFileShare_videoDataList') as FileData[]; + if (!fileShare || fileShare.length === 0) { + return; + } + let shareData: systemShare.SharedData = new systemShare.SharedData(this.getShareRecord(videoDataList[fileShare[0]])); + for (let i = 1; i < fileShare.length; i++) { + shareData.addRecord(this.getShareRecord(videoDataList[fileShare[i]])); + } + target.share(shareData); + } + + /** + * Get shared data. + * + * @param data File data to be shared. + * @returns systemShare.SharedRecord. + */ + getShareRecord(data: FileData): systemShare.SharedRecord { + let suffix = '.' + data.url.split('.').pop(); + // Obtain the UTD through the file extension. + let utd = uniformTypeDescriptor.getUniformDataTypeByFilenameExtension(suffix); + hilog.info(0x0000, 'KnockFileShare', `getShareRecord utd ${utd}`) + return { + utd: utd, + uri: data.url, + thumbnailUri: data.thumbnail, + title: data.name, + description: data.description + }; + } + // [End FileShare] + + // [Start FileShareListening] + /** + * Add knock listening. + */ + public immersiveListening() { + if (canIUse('SystemCapability.Collaboration.HarmonyShare')) { + harmonyShare.on('knockShare', (target: harmonyShare.SharableTarget) => { + this.immersiveCallback(target); + }); + } + } + + /** + * Add knock listening in 2in1 device type. + */ + public immersiveListeningPC() { + if (canIUse('SystemCapability.Collaboration.HarmonyShare')) { + window.getLastWindow(this.context).then((data) => { + let mainWindowID: number = data.getWindowProperties().id; + harmonyShare.on('knockShare', { windowId: mainWindowID }, (target: harmonyShare.SharableTarget) => { + this.immersiveCallback(target); + }); + }) + } + } + + /** + * remove knock listening. + */ + public immersiveDisableListening() { + if (canIUse('SystemCapability.Collaboration.HarmonyShare')) { + harmonyShare.off('knockShare'); + } + } + + /** + * remove knock listening. + */ + public immersiveDisableListeningPC() { + if (canIUse('SystemCapability.Collaboration.HarmonyShare')) { + window.getLastWindow(this.context).then((data) => { + let mainWindowID: number = data.getWindowProperties().id; + harmonyShare.off('knockShare', { windowId: mainWindowID }); + }) + } + } + // [End FileShareListening] + + // [Start dataReceive] + /** + * Add dataReceive listening in 2in1 device type. + */ + public dataReceiveListeningPC() { + if (!canIUse('SystemCapability.Collaboration.HarmonyShare')) { + return; + } + window.getLastWindow(this.context).then(((data) => { + let mainWindowID: number = data.getWindowProperties().id; + harmonyShare.on('dataReceive', { windowId: mainWindowID, capabilities: [ + { + 'utd': uniformTypeDescriptor.UniformDataType.MEDIA, + 'maxSupportedCount': 5 + }, + { + 'utd': uniformTypeDescriptor.UniformDataType.FILE, + 'maxSupportedCount': 5 + } + ] }, + (receiveTarget: harmonyShare.ReceivableTarget) => { + if (!this.context) { + return; + } + // Process the received file data. + receiveTarget.receive(fileUri.getUriFromPath(this.context.filesDir), { + onDataReceived: (shareData: systemShare.SharedData) => { + let shareRecords = shareData.getRecords(); + let videoDataList = AppStorage.get('KnockFileShare_videoDataList') as FileData[]; + shareRecords.forEach(async (record: systemShare.SharedRecord) => { + if (!record.uri) { + return; + } + // Get video thumbnails. + let fileName = record.uri.split('/').pop()?.split('.')[0]; + let thumbPath: string = videoDataList[0].thumbnail; + if (record.uri.endsWith('mp4') || record.uri.endsWith('mkv')) { + thumbPath = record.uri.slice(0, record.uri.lastIndexOf('.')) + 'thumb.png'; + let result = await new FileUtil().getVideoThumbnail(record.uri, thumbPath); + if (!result) { + thumbPath = videoDataList[0].thumbnail; + } + } else if (record.uri.endsWith('png') || record.uri.endsWith('jpg') || record.uri.endsWith('jpeg')) { + thumbPath = record.uri; + } + + videoDataList.push({ + url: record.uri, + name: fileName, + description: record.description, + thumbnail: thumbPath, + index: videoDataList.length + }); + }); + }, + onResult(resultCode: harmonyShare.ShareResultCode) { + if (resultCode === harmonyShare.ShareResultCode.SHARE_SUCCESS) { + hilog.info(0x0000, 'KnockFileShare', 'receive file success'); + } else { + hilog.error(0x0000, 'KnockFileShare', 'receive failed ' + resultCode); + } + } + }); + }); + })).catch((error: BusinessError) => { + hilog.error(0x0000, 'KnockFileShare', `failed to obtain the window. cause ${error.code} ${error.message}`); + }) + } + // [End dataReceive] + + /** + * Remove dataReceive listening. + */ + public dataReceiveDisableListeningPC() { + if (!canIUse('SystemCapability.Collaboration.HarmonyShare')) { + return; + } + window.getLastWindow(this.context).then(((data) => { + let mainWindowID: number = data.getWindowProperties().id; + harmonyShare.off('dataReceive', { windowId: mainWindowID, capabilities: [ + { + 'utd': uniformTypeDescriptor.UniformDataType.MEDIA, + 'maxSupportedCount': 5 + }, + { + 'utd': uniformTypeDescriptor.UniformDataType.FILE, + 'maxSupportedCount': 5 + } + ] }); + })).catch((error: BusinessError) => { + hilog.error(0x0000, 'KnockFileShare', `failed to obtain the window. cause ${error.code} ${error.message}`); + }) + } +} diff --git a/entry/src/main/ets/entryability/EntryAbility.ets b/entry/src/main/ets/entryability/EntryAbility.ets new file mode 100644 index 0000000000000000000000000000000000000000..bcc67d137fc2c08e64e4d26268f83196492c6cf4 --- /dev/null +++ b/entry/src/main/ets/entryability/EntryAbility.ets @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * 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 + * + * http://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. + */ + +import { AbilityConstant, ConfigurationConstant, UIAbility, Want } from '@kit.AbilityKit'; +import { BusinessError } from '@kit.BasicServicesKit'; +import { hilog } from '@kit.PerformanceAnalysisKit'; +import { window } from '@kit.ArkUI'; +import { BreakpointConstants } from '../constants/BreakpointConstants'; + +const DOMAIN = 0x0000; + +export default class EntryAbility extends UIAbility { + private mainWindowClass?: window.Window; + private uiContext?: UIContext; + + onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void { + this.context.getApplicationContext().setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET); + hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onCreate'); + } + + onDestroy(): void { + hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onDestroy'); + } + + onWindowStageCreate(windowStage: window.WindowStage): void { + // Main window is created, set main page for this ability + hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onWindowStageCreate'); + + windowStage.loadContent('pages/Index', (err) => { + if (err.code) { + hilog.error(DOMAIN, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err)); + return; + } + windowStage.getMainWindow().then((data: window.Window) => { + this.mainWindowClass = data; + this.updateWidthBp(); + this.uiContext = data.getUIContext(); + data.on('windowSizeChange', this.onWindowSizeChange); + }).catch((err: BusinessError) => { + hilog.error(0x0000, 'WebAbility', + `Failed to obtain the main window. Cause code: ${err.code}, message: ${err.message}`); + }); + hilog.info(DOMAIN, 'testTag', 'Succeeded in loading the content.'); + }); + } + + private onWindowSizeChange: (windowSize: window.Size) => void = (windowSize: window.Size) => { + this.updateWidthBp(); + }; + + updateWidthBp(): void { + if (!this.uiContext) { + return; + } + let mainWindow: window.WindowProperties = this.mainWindowClass!.getWindowProperties(); + let windowWidth: number = mainWindow.windowRect.width; + let windowWidthVp = this.uiContext.px2vp(windowWidth); + let widthBp: string = ''; + if (windowWidthVp < 320) { + widthBp = BreakpointConstants.BREAKPOINT_XS; + } else if (windowWidthVp >= 320 && windowWidthVp < 600) { + widthBp = BreakpointConstants.BREAKPOINT_SM; + } else if (windowWidthVp >= 600 && windowWidthVp < 840) { + widthBp = BreakpointConstants.BREAKPOINT_MD; + } else if (windowWidthVp >= 840 && windowWidthVp < 1440) { + widthBp = BreakpointConstants.BREAKPOINT_LG; + } else { + widthBp = BreakpointConstants.BREAKPOINT_XL; + } + AppStorage.setOrCreate(BreakpointConstants.BREAKPOINT_NAME, widthBp); + AppStorage.setOrCreate('windowWidth', windowWidth); + let windowHeight: number = mainWindow.windowRect.height; + AppStorage.setOrCreate('windowHeight', windowHeight); + } + + onWindowStageDestroy(): void { + // Main window is destroyed, release UI related resources + hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onWindowStageDestroy'); + } + + onForeground(): void { + // Ability has brought to foreground + hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onForeground'); + } + + onBackground(): void { + // Ability has back to background + hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onBackground'); + } +} \ No newline at end of file diff --git a/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets b/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets new file mode 100644 index 0000000000000000000000000000000000000000..0a97e21bd7a15599af76a806695860ff1eb0ebfe --- /dev/null +++ b/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * 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 + * + * http://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. + */ + +import { hilog } from '@kit.PerformanceAnalysisKit'; +import { BackupExtensionAbility, BundleVersion } from '@kit.CoreFileKit'; + +const DOMAIN = 0x0000; + +export default class EntryBackupAbility extends BackupExtensionAbility { + async onBackup() { + hilog.info(DOMAIN, 'testTag', 'onBackup ok'); + await Promise.resolve(); + } + + async onRestore(bundleVersion: BundleVersion) { + hilog.info(DOMAIN, 'testTag', 'onRestore ok %{public}s', JSON.stringify(bundleVersion)); + await Promise.resolve(); + } +} \ No newline at end of file diff --git a/entry/src/main/ets/model/FileData.ets b/entry/src/main/ets/model/FileData.ets new file mode 100644 index 0000000000000000000000000000000000000000..4983101923668eb08bd23f767598a5cbf4e54af8 --- /dev/null +++ b/entry/src/main/ets/model/FileData.ets @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * 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 + * + * http://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. + */ + +export interface FileData { + url: string; + name: string; + description:string; + thumbnail: string; + index: number; +} + +export const VIDEO_SOURCES: FileData[] = [ + { + url: 'video_cover_0.png', + name: 'pura-x publicize video', + description: 'pura-x publicize video description', + thumbnail: 'video_cover_0.png', + index: 0 + }, + { + url: 'video_cover_1.png', + name: 'mate-xt publicize video', + description: 'mate-xt publicize video description', + thumbnail: 'video_cover_1.png', + index: 1 + }, + { + url: 'kv-intro-pop.mp4', + name: 'pura publicize video', + thumbnail: 'video_cover_2.png', + description: 'pura publicize video description', + index: 2 + }, + { + url: 'camera-intro-popup.mp4', + name: 'nova publicize video', + thumbnail: 'video_cover_3.png', + description: 'nova publicize video description', + index: 3 + }, +]; + +export const IMAGE_DATA: Resource[] = [$r('app.media.video_cover_0'), $r('app.media.video_cover_1'), + $r('app.media.video_cover_2'), $r('app.media.video_cover_3')]; \ No newline at end of file diff --git a/entry/src/main/ets/pages/Index.ets b/entry/src/main/ets/pages/Index.ets new file mode 100644 index 0000000000000000000000000000000000000000..e2e87d3504d67b1babe799ed7efe4983a160b002 --- /dev/null +++ b/entry/src/main/ets/pages/Index.ets @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * 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 + * + * http://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. + */ + +import { common } from '@kit.AbilityKit'; +import { fileIo, fileUri } from '@kit.CoreFileKit'; +import { hilog } from '@kit.PerformanceAnalysisKit'; +import { deviceInfo } from '@kit.BasicServicesKit'; +import { filePreview } from '@kit.PreviewKit'; +import { BreakpointConstants } from '../constants/BreakpointConstants'; +import { FileData, IMAGE_DATA, VIDEO_SOURCES } from '../model/FileData' +import { KnockController } from '../controller/KnockController'; +import { BreakpointType } from '../utils/BreakpointSystem'; +import { FileUtil } from '../utils/FileUtil'; + +@Entry +@Component +struct Index { + @StorageLink('KnockFileShare_videoDataList') dataList: FileData[] = VIDEO_SOURCES; + @StorageLink('KnockFileShare_fileShare') fileShare: number[] = []; + @StorageLink(BreakpointConstants.BREAKPOINT_NAME) currentBreakpoint: string = BreakpointConstants.BREAKPOINT_LG; + @State isEdit: boolean = true; + private knockController: KnockController | undefined = undefined; + private context: common.UIAbilityContext = this.getUIContext().getHostContext() as common.UIAbilityContext; + + aboutToAppear(): void { + this.handleFileInit(); + + this.knockController = KnockController.getInstance(this.context); + if (deviceInfo.deviceType === '2in1') { + this.knockController.immersiveListeningPC(); + this.knockController.dataReceiveListeningPC(); + } else { + this.knockController.immersiveListening(); + } + } + + aboutToDisappear(): void { + if (deviceInfo.deviceType === '2in1') { + this.knockController?.immersiveDisableListeningPC(); + this.knockController?.dataReceiveDisableListeningPC(); + } else { + this.knockController?.immersiveDisableListening(); + } + } + + build() { + Navigation() { + List({ space: 16 }) { + ForEach(this.dataList, (item: FileData, index: number) => { + ListItem() { + Stack() { + Column() { + Image(item.thumbnail) + .width('100%') + .aspectRatio(1) + .borderRadius(10) + .onClick(() => { + let uiContext = this.getUIContext().getHostContext(); + let displayInfo: filePreview.DisplayInfo = { + x: 100, + y: 100, + width: 800, + height: 800 + }; + let fileInfo: filePreview.PreviewInfo = { + title: item.name, + uri: item.url, + mimeType: FileUtil.getMimeTypeFromPath((item.url)) + }; + filePreview.openPreview(uiContext, fileInfo, displayInfo, (err) => { + if (err && err.code) { + hilog.error(0x0000, 'KnockFileShare', `Failed to open preview. ${JSON.stringify(err)}`); + return; + } + hilog.info(0x0000, 'KnockFileShare', 'Success in opening preview'); + }); + }) + } + Column() { + Checkbox({ name: index + '', group: 'checkboxGroup'}) + .select(false) + .selectedColor('#0A59F7') + .unselectedColor(Color.White) + .shape(CheckBoxShape.CIRCLE) + .margin({ + right: 10 + }) + .onChange((value: boolean) => { + if (value) { + this.fileShare.push(index); + } else { + this.fileShare.splice(this.fileShare.indexOf(index), 1); + } + }) + } + .layoutWeight(1) + } + .alignContent(Alignment.BottomEnd) + } + }, (item: FileData, index: number) => index + JSON.stringify(item)) + } + .lanes(new BreakpointType({ + sm: 2, + md: 4, + lg: 6 + }).getValue(this.currentBreakpoint), 8) + .margin({ + left: new BreakpointType({ + sm: 16, + md: 24, + lg: 32 + }).getValue(this.currentBreakpoint), + right: new BreakpointType({ + sm: 16, + md: 24, + lg: 32 + }).getValue(this.currentBreakpoint) + }) + } + .title($r('app.string.app_title')) + .titleMode(NavigationTitleMode.Mini) + .hideBackButton(true) + .mode(NavigationMode.Stack) + .backgroundColor($r('sys.color.container_modal_unfocus_background')) + } + + /** + * Initialize operations to process files. + */ + handleFileInit() { + let filesDir = this.context.filesDir; + let fileList = fileIo.listFileSync(filesDir); + for (let index = 0; index < fileList.length; index++) { + const fileName = fileList[index]; + fileIo.unlinkSync(filesDir + '/' + fileName); + } + for (const item of this.dataList) { + let file: fileIo.File | undefined = undefined; + try { + let url = this.context.filesDir + '/' + item.url; + file = fileIo.openSync(url, fileIo.OpenMode.READ_WRITE | fileIo.OpenMode.CREATE); + let writeLen = + fileIo.writeSync(file.fd, (this.context.resourceManager.getRawFileContentSync(item.url) as Uint8Array).buffer); + hilog.info(0x0000, 'KnockFileShare', `write data to file succeed and size is : ${writeLen}`); + item.url = fileUri.getUriFromPath(url); + } catch (err) { + hilog.error(0x0000, 'KnockFileShare', `Failed to save image. ${JSON.stringify(err)}`); + } finally { + fileIo.close(file); + } + try { + let url = this.context.filesDir + '/' + item.thumbnail; + file = fileIo.openSync(url, fileIo.OpenMode.READ_WRITE | fileIo.OpenMode.CREATE); + let writeLen = fileIo.writeSync(file.fd, + (this.context.resourceManager.getMediaContentSync(IMAGE_DATA[item.index]) as Uint8Array).buffer); + hilog.info(0x0000, 'KnockFileShare', `write data to file success and size is : ${writeLen}`); + item.thumbnail = fileUri.getUriFromPath(url); + } catch (err) { + hilog.error(0x0000, 'KnockFileShare', `Failed to save image. ${JSON.stringify(err)}`); + } finally { + fileIo.close(file); + } + } + } +} \ No newline at end of file diff --git a/entry/src/main/ets/utils/BreakpointSystem.ets b/entry/src/main/ets/utils/BreakpointSystem.ets new file mode 100644 index 0000000000000000000000000000000000000000..76d100690c09db9d99821965575373bf5571e841 --- /dev/null +++ b/entry/src/main/ets/utils/BreakpointSystem.ets @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * 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 + * + * http://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. + */ + +import { BreakpointConstants } from '../constants/BreakpointConstants'; + +declare interface BreakPointTypeOption { + sm?: T, + md?: T, + lg?: T, + xl?: T +} + +export class BreakpointType { + public options: BreakPointTypeOption; + + constructor(option: BreakPointTypeOption) { + this.options = option; + } + + getValue(currentPoint: string): T { + let point: T; + switch (currentPoint) { + case BreakpointConstants.BREAKPOINT_SM: + point = this.options.sm as T; + break; + case BreakpointConstants.BREAKPOINT_MD: + point = this.options.md as T; + break; + case BreakpointConstants.BREAKPOINT_LG: + point = this.options.lg as T; + break; + case BreakpointConstants.BREAKPOINT_XL: + if (this.options.xl) { + point = this.options.xl as T; + } else { + point = this.options.lg as T; + } + break; + default: + point = this.options.sm as T; + break; + } + return point; + } +} \ No newline at end of file diff --git a/entry/src/main/ets/utils/FileUtil.ets b/entry/src/main/ets/utils/FileUtil.ets new file mode 100644 index 0000000000000000000000000000000000000000..1fb3400cbc84fcb890bc6297edf0dbc015cca090 --- /dev/null +++ b/entry/src/main/ets/utils/FileUtil.ets @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * 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 + * + * http://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. + */ + +import { fileIo } from '@kit.CoreFileKit'; +import { media } from '@kit.MediaKit'; +import { image } from '@kit.ImageKit'; +import { hilog } from '@kit.PerformanceAnalysisKit'; + +export class FileUtil { + /** + * Get thumbnail from video file. + * + * @param path video file path. + * @param thumbPath thumbnail path. + */ + public async getVideoThumbnail(path: string, thumbPath: string): Promise { + if (!canIUse('SystemCapability.Multimedia.Media.AVImageGenerator')) { + return false; + } + let avImageGenerator: media.AVImageGenerator = await media.createAVImageGenerator(); + avImageGenerator.fdSrc = fileIo.openSync(path, fileIo.OpenMode.READ_ONLY); + let timeUs = 0; + let queryOption = media.AVImageQueryOptions.AV_IMAGE_QUERY_NEXT_SYNC; + let param: media.PixelMapParams = { + width: 300, + height: 300 + }; + try { + let pixmap: image.PixelMap = await avImageGenerator.fetchFrameByTime(timeUs, queryOption, param); + let packOpts: image.PackingOption = { format: 'image/jpeg', quality: 98 }; + const imagePackerApi = image.createImagePacker(); + let file = fileIo.openSync(thumbPath, fileIo.OpenMode.CREATE | fileIo.OpenMode.READ_WRITE); + await imagePackerApi.packToFile(pixmap, file.fd, packOpts); + return true; + } catch (error) { + hilog.error(0x0000, 'KnockFileShare', JSON.stringify(error)); + } + return false; + } + + /** + * Get MIME type by file extension. + * + * @param filePath file path. + * @returns mime type. + */ + public static getMimeTypeFromPath(filePath: string): string { + const extension = filePath.split('.').pop(); + if (!extension) { + return 'image/jpeg'; + } + const mimeType: Record = { + 'jpg': 'image/jpeg', + 'jpeg': 'image/jpeg', + 'png': 'image/png', + 'gif': 'image/gif', + 'webp': 'image/webp', + 'svg': 'image/svg+xml', + 'pdf': 'application/pdf', + 'doc': 'application/msword', + 'docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', + 'xls': 'application/vnd.ms-excel', + 'xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', + 'ppt': 'application/vnd.ms-powerpoint', + 'pptx': 'application/vnd.openxmlformats-officedocument.presentationml.presentation', + 'txt': 'text/plain', + 'mp3': 'audio/mpeg', + 'wav': 'audio/wav', + 'mp4': 'video/mp4', + 'mkv': 'video/x-matroska', + 'webm': 'video/webm', + 'zip': 'application/zip', + 'rar': 'application/x-rar-compressed', + '7z': 'application/x-7z-compressed' + }; + return mimeType[extension] || 'image/jpeg'; + } +} diff --git a/entry/src/main/module.json5 b/entry/src/main/module.json5 new file mode 100644 index 0000000000000000000000000000000000000000..fdabab48807218af772a83a9097b6b028199e764 --- /dev/null +++ b/entry/src/main/module.json5 @@ -0,0 +1,51 @@ +{ + "module": { + "name": "entry", + "type": "entry", + "description": "$string:module_desc", + "mainElement": "EntryAbility", + "deviceTypes": [ + "phone", + "2in1" + ], + "deliveryWithInstall": true, + "installationFree": false, + "pages": "$profile:main_pages", + "abilities": [ + { + "name": "EntryAbility", + "srcEntry": "./ets/entryability/EntryAbility.ets", + "description": "$string:EntryAbility_desc", + "icon": "$media:layered_image", + "label": "$string:EntryAbility_label", + "startWindowIcon": "$media:startIcon", + "startWindowBackground": "$color:start_window_background", + "exported": true, + "skills": [ + { + "entities": [ + "entity.system.home" + ], + "actions": [ + "ohos.want.action.home" + ] + } + ] + } + ], + "extensionAbilities": [ + { + "name": "EntryBackupAbility", + "srcEntry": "./ets/entrybackupability/EntryBackupAbility.ets", + "type": "backup", + "exported": false, + "metadata": [ + { + "name": "ohos.extension.backup", + "resource": "$profile:backup_config" + } + ], + } + ] + } +} \ No newline at end of file diff --git a/entry/src/main/resources/base/element/color.json b/entry/src/main/resources/base/element/color.json new file mode 100644 index 0000000000000000000000000000000000000000..3c712962da3c2751c2b9ddb53559afcbd2b54a02 --- /dev/null +++ b/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/entry/src/main/resources/base/element/float.json b/entry/src/main/resources/base/element/float.json new file mode 100644 index 0000000000000000000000000000000000000000..33ea22304f9b1485b5f22d811023701b5d4e35b6 --- /dev/null +++ b/entry/src/main/resources/base/element/float.json @@ -0,0 +1,8 @@ +{ + "float": [ + { + "name": "page_text_font_size", + "value": "50fp" + } + ] +} diff --git a/entry/src/main/resources/base/element/string.json b/entry/src/main/resources/base/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..2b3d7cdab92b5d4087e148c3a77b49be3096b183 --- /dev/null +++ b/entry/src/main/resources/base/element/string.json @@ -0,0 +1,20 @@ +{ + "string": [ + { + "name": "module_desc", + "value": "module description" + }, + { + "name": "EntryAbility_desc", + "value": "description" + }, + { + "name": "EntryAbility_label", + "value": "KnockFileShare" + }, + { + "name": "app_title", + "value": "Tap to share files" + } + ] +} \ No newline at end of file diff --git a/entry/src/main/resources/base/media/background.png b/entry/src/main/resources/base/media/background.png new file mode 100644 index 0000000000000000000000000000000000000000..923f2b3f27e915d6871871deea0420eb45ce102f Binary files /dev/null and b/entry/src/main/resources/base/media/background.png differ diff --git a/entry/src/main/resources/base/media/foreground.png b/entry/src/main/resources/base/media/foreground.png new file mode 100644 index 0000000000000000000000000000000000000000..97014d3e10e5ff511409c378cd4255713aecd85f Binary files /dev/null and b/entry/src/main/resources/base/media/foreground.png differ diff --git a/entry/src/main/resources/base/media/layered_image.json b/entry/src/main/resources/base/media/layered_image.json new file mode 100644 index 0000000000000000000000000000000000000000..fb49920440fb4d246c82f9ada275e26123a2136a --- /dev/null +++ b/entry/src/main/resources/base/media/layered_image.json @@ -0,0 +1,7 @@ +{ + "layered-image": + { + "background" : "$media:background", + "foreground" : "$media:foreground" + } +} \ No newline at end of file diff --git a/entry/src/main/resources/base/media/startIcon.png b/entry/src/main/resources/base/media/startIcon.png new file mode 100644 index 0000000000000000000000000000000000000000..205ad8b5a8a42e8762fbe4899b8e5e31ce822b8b Binary files /dev/null and b/entry/src/main/resources/base/media/startIcon.png differ diff --git a/entry/src/main/resources/base/media/video_cover_0.png b/entry/src/main/resources/base/media/video_cover_0.png new file mode 100644 index 0000000000000000000000000000000000000000..65b36e53f9d57a0e6db7ae333ece7b11213d9392 Binary files /dev/null and b/entry/src/main/resources/base/media/video_cover_0.png differ diff --git a/entry/src/main/resources/base/media/video_cover_1.png b/entry/src/main/resources/base/media/video_cover_1.png new file mode 100644 index 0000000000000000000000000000000000000000..d29f0e50c55814c75f95ee3258ed06f817a97b6a Binary files /dev/null and b/entry/src/main/resources/base/media/video_cover_1.png differ diff --git a/entry/src/main/resources/base/media/video_cover_2.png b/entry/src/main/resources/base/media/video_cover_2.png new file mode 100644 index 0000000000000000000000000000000000000000..25fe99d5f7d1025d4ab9ac6636a0633d78bbe6ec Binary files /dev/null and b/entry/src/main/resources/base/media/video_cover_2.png differ diff --git a/entry/src/main/resources/base/media/video_cover_3.png b/entry/src/main/resources/base/media/video_cover_3.png new file mode 100644 index 0000000000000000000000000000000000000000..947ac1fffe1f768f1d847986adeb398e038b988b Binary files /dev/null and b/entry/src/main/resources/base/media/video_cover_3.png differ diff --git a/entry/src/main/resources/base/profile/backup_config.json b/entry/src/main/resources/base/profile/backup_config.json new file mode 100644 index 0000000000000000000000000000000000000000..78f40ae7c494d71e2482278f359ec790ca73471a --- /dev/null +++ b/entry/src/main/resources/base/profile/backup_config.json @@ -0,0 +1,3 @@ +{ + "allowToBackupRestore": true +} \ No newline at end of file diff --git a/entry/src/main/resources/base/profile/main_pages.json b/entry/src/main/resources/base/profile/main_pages.json new file mode 100644 index 0000000000000000000000000000000000000000..1898d94f58d6128ab712be2c68acc7c98e9ab9ce --- /dev/null +++ b/entry/src/main/resources/base/profile/main_pages.json @@ -0,0 +1,5 @@ +{ + "src": [ + "pages/Index" + ] +} diff --git a/entry/src/main/resources/dark/element/color.json b/entry/src/main/resources/dark/element/color.json new file mode 100644 index 0000000000000000000000000000000000000000..79b11c2747aec33e710fd3a7b2b3c94dd9965499 --- /dev/null +++ b/entry/src/main/resources/dark/element/color.json @@ -0,0 +1,8 @@ +{ + "color": [ + { + "name": "start_window_background", + "value": "#000000" + } + ] +} \ No newline at end of file diff --git a/entry/src/main/resources/en_US/element/string.json b/entry/src/main/resources/en_US/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..2b3d7cdab92b5d4087e148c3a77b49be3096b183 --- /dev/null +++ b/entry/src/main/resources/en_US/element/string.json @@ -0,0 +1,20 @@ +{ + "string": [ + { + "name": "module_desc", + "value": "module description" + }, + { + "name": "EntryAbility_desc", + "value": "description" + }, + { + "name": "EntryAbility_label", + "value": "KnockFileShare" + }, + { + "name": "app_title", + "value": "Tap to share files" + } + ] +} \ No newline at end of file diff --git a/entry/src/main/resources/rawfile/camera-intro-popup.mp4 b/entry/src/main/resources/rawfile/camera-intro-popup.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..db6de750bea8656e74b7a8315efe5dc2cb12beeb Binary files /dev/null and b/entry/src/main/resources/rawfile/camera-intro-popup.mp4 differ diff --git a/entry/src/main/resources/rawfile/kv-intro-pop.mp4 b/entry/src/main/resources/rawfile/kv-intro-pop.mp4 new file mode 100644 index 0000000000000000000000000000000000000000..868c5d630ab209715ac2c4e325c886206ddfb6b1 Binary files /dev/null and b/entry/src/main/resources/rawfile/kv-intro-pop.mp4 differ diff --git a/entry/src/main/resources/rawfile/video_cover_0.png b/entry/src/main/resources/rawfile/video_cover_0.png new file mode 100644 index 0000000000000000000000000000000000000000..65b36e53f9d57a0e6db7ae333ece7b11213d9392 Binary files /dev/null and b/entry/src/main/resources/rawfile/video_cover_0.png differ diff --git a/entry/src/main/resources/rawfile/video_cover_1.png b/entry/src/main/resources/rawfile/video_cover_1.png new file mode 100644 index 0000000000000000000000000000000000000000..d29f0e50c55814c75f95ee3258ed06f817a97b6a Binary files /dev/null and b/entry/src/main/resources/rawfile/video_cover_1.png differ diff --git a/entry/src/main/resources/zh_CN/element/string.json b/entry/src/main/resources/zh_CN/element/string.json new file mode 100644 index 0000000000000000000000000000000000000000..d6fb6114dd838b40953f7e03b9e62f5fa4adac3a --- /dev/null +++ b/entry/src/main/resources/zh_CN/element/string.json @@ -0,0 +1,20 @@ +{ + "string": [ + { + "name": "module_desc", + "value": "module description" + }, + { + "name": "EntryAbility_desc", + "value": "description" + }, + { + "name": "EntryAbility_label", + "value": "KnockFileShare" + }, + { + "name": "app_title", + "value": "碰一碰文件分享" + } + ] +} \ No newline at end of file diff --git a/hvigor/hvigor-config.json5 b/hvigor/hvigor-config.json5 new file mode 100644 index 0000000000000000000000000000000000000000..7a7ab8914d8db6ab89758e185df5855dffe88d04 --- /dev/null +++ b/hvigor/hvigor-config.json5 @@ -0,0 +1,23 @@ +{ + "modelVersion": "6.0.0", + "dependencies": { + }, + "execution": { + // "analyze": "normal", /* Define the build analyze mode. Value: [ "normal" | "advanced" | "ultrafine" | false ]. Default: "normal" */ + // "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 */ + // "optimizationStrategy": "memory" /* Define the optimization strategy. Value: [ "memory" | "performance" ]. Default: "memory" */ + }, + "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": 8192 /* Enable nodeOptions maxOldSpaceSize compilation. Unit M. Used for the daemon process. Default: 8192*/ + // "exposeGC": true /* Enable to trigger garbage collection explicitly. Default: true*/ + } +} diff --git a/hvigorfile.ts b/hvigorfile.ts new file mode 100644 index 0000000000000000000000000000000000000000..47113e2e36ecefde41c136272a0bd6ff745cffe4 --- /dev/null +++ b/hvigorfile.ts @@ -0,0 +1,6 @@ +import { appTasks } from '@ohos/hvigor-ohos-plugin'; + +export default { + system: appTasks, /* Built-in plugin of Hvigor. It cannot be modified. */ + plugins: [] /* Custom plugin to extend the functionality of Hvigor. */ +} \ No newline at end of file diff --git a/oh-package.json5 b/oh-package.json5 new file mode 100644 index 0000000000000000000000000000000000000000..d5b3f0c6e0e4d7b87fe979c8d56e4b86226eef48 --- /dev/null +++ b/oh-package.json5 @@ -0,0 +1,10 @@ +{ + "modelVersion": "6.0.0", + "description": "Please describe the basic information.", + "dependencies": { + }, + "devDependencies": { + "@ohos/hypium": "1.0.21", + "@ohos/hamock": "1.0.0" + } +} diff --git a/screenshots/device/phone.png b/screenshots/device/phone.png new file mode 100644 index 0000000000000000000000000000000000000000..d8ccea9d7f25f4aa07a04cf84ab170c0df0301a2 Binary files /dev/null and b/screenshots/device/phone.png differ diff --git a/screenshots/device/phone_en.png b/screenshots/device/phone_en.png new file mode 100644 index 0000000000000000000000000000000000000000..7bad1d73794014311b4b8681d1c18509a93f7d5b Binary files /dev/null and b/screenshots/device/phone_en.png differ