diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..d2ff20141ceed86d87c0ea5d99481973005bab2b
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,12 @@
+/node_modules
+/oh_modules
+/local.properties
+/.idea
+**/build
+/.hvigor
+.cxx
+/.clangd
+/.clang-format
+/.clang-tidy
+**/.test
+/.appanalyzer
\ No newline at end of file
diff --git a/AppScope/app.json5 b/AppScope/app.json5
new file mode 100644
index 0000000000000000000000000000000000000000..0b4fe98693fed9ec6c218036c970046b139269b2
--- /dev/null
+++ b/AppScope/app.json5
@@ -0,0 +1,10 @@
+{
+ "app": {
+ "bundleName": "com.example.crossDeviceFileOperation",
+ "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..6030b4d442410b1240b8ba2f0b5740845fabf266
--- /dev/null
+++ b/AppScope/resources/base/element/string.json
@@ -0,0 +1,8 @@
+{
+ "string": [
+ {
+ "name": "app_name",
+ "value": "crossDeviceFileOperation"
+ }
+ ]
+}
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/README.en.md b/README.en.md
index 7eae4bc00b1fe99a215d67f3d1236867487536ca..f92fdd91f470978cde71b9f4e107c8931450884a 100644
--- a/README.en.md
+++ b/README.en.md
@@ -1,36 +1,82 @@
-# CrossDeviceFileOperation
+# Implementing cross device file operations based on Core File Kit (File Basic Service)
-#### Description
-跨设备文件操作
+## Project Overview
-#### Software Architecture
-Software architecture description
+This example demonstrates how to access and copy files across multiple devices.
-#### Installation
+## Effect Preview
-1. xxxx
-2. xxxx
-3. xxxx
+
-#### Instructions
-1. xxxx
-2. xxxx
-3. xxxx
+## Instructions for use
-#### Contribution
+1. Fill in the file name and content on the homepage, click the "OK" button to create the file, and if you need to modify the filled content, click the "Clear" button.
+2. After successful creation, click the "Remote Files" button to view the created files.
+3. Remote file list:
+ - Open the editing status in the upper right corner, select a file, and you can delete or copy it at the bottom.
+ The editing status can be cancelled in the upper left corner.
+ - Click on any file to enter the preview interface.
+4. Local file list: The page function is roughly the same as the remote file list, with the difference being:
+ - Local files need to be copied and replicated locally from the remote file list.
+ - There is no copy button in editing mode.
+5. Preview interface:
+ - Click on the editing area to automatically enter the editing mode.
+ - The hook in the upper right corner is the save button after editing.
+ - Cross in the upper left corner, if entering editing mode but not edited, it will directly return to the
+ previous page; If editing has been done, a pop-up window will ask if you want to save it. If you cancel, the previously edited content will be recalled. If you confirm, the content will be saved.
-1. Fork the repository
-2. Create Feat_xxx branch
-3. Commit your code
-4. Create Pull Request
+## Engineering Catalog
-#### Gitee Feature
+```
+├──entry/src/main/ets // Code Area
+│ ├──entryability
+│ │ └──EntryAbility.ets // Program entrance class
+│ ├──components // Common Components
+│ │ ├──DeleteDialog.ets // Delete pop-up component
+│ │ ├──EditTitleBar.ets // Top component of editing page
+│ │ ├──ListComp.ets // List component
+│ │ ├──Loading.ets // Load pop-up component
+│ │ ├──ProgressDialog.ets // Copy progress pop-up component
+│ │ ├──TitleBar.ets // Universal Top Bar Component
+│ │ └──TitleBarDeleteDialog.ets // Universal Top Bar Delete Pop up Component
+│ ├──pages
+│ │ └──Index.ets // Application main interface
+│ ├──utils // Tool Category
+│ │ └──CommonUtils.ets // Public tools category
+│ └──view
+│ ├──LocalFileList.ets // Accessing the Local File List View
+│ ├──Preview.ets // Preview interface
+│ └──RemoteFileList.ets // Access Remote File List View
+└──entry/src/main/resources // Application static resource directory
+```
-1. You can use Readme\_XXX.md to support different languages, such as Readme\_en.md, Readme\_zh.md
-2. Gitee blog [blog.gitee.com](https://blog.gitee.com)
-3. Explore open source project [https://gitee.com/explore](https://gitee.com/explore)
-4. The most valuable open source project [GVP](https://gitee.com/gvp)
-5. The manual of Gitee [https://gitee.com/help](https://gitee.com/help)
-6. The most popular members [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)
+## Specific Implementation
+
+1. Obtain the sandbox path of the current application's distributed shared directory using [getUIContext()](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-custom-component-api#getuicontext)Then obtain [getHostContext()](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-arkui-uicontext#gethostcontext12)
+ Subsequently, access the distributedFilesDir distributed shared directory.
+2. Create files through [fs.openSync()](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-file-fs#fsopensync)Open files or directories using synchronization method, and then use [fs.riteSync()](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-file-fs#fswritesync )Write data to a file using a synchronous method, and finally use [fs.closeSync()](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-file-fs#fsclosesync)Close the file or directory using the synchronization method to create it successfully.
+3. Access local files through [fs.listFile()](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-file-fs#fslistfile)List all files in the local filesDir sandbox path directory.
+4. Accessing remote files:
+ - Firstly, through the [Device Management Interface](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-distributeddevicemanager)Get the device networkId.
+ - Through [fs.connectDfs()](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-file-fs#fsconnectdfs12)Enable cross device file access.
+ - Subsequently, [fs.listFile()](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-file-fs#fslistfile)List all files in the distributedFilesDir directory of the remote sandbox path.
+5. Preview interface:
+ - By using [fs.readTextSync()](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-file-fs#fsreadtextsync)Read a file from the sandbox path in the format of fs.readTextSync+ File name).
+6. Save function:
+ - Through [fs.openSync()](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-file-fs#fsopensync)
+ Open the corresponding file path using synchronization method, and then use [fs.riteSync()](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-file-fs#fswritesync)Write data to a file using a synchronous method, and finally use [fs.closeSync()](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-file-fs#fsclosesync)Close the file using the synchronization method to save successfully.
+
+## Related permissions
+
+* Ohos.permission.DISTRIBUTED_DATASYNC: Allow data exchange between different devices.
+
+## Constraints and limitations
+
+1. This example only supports running on standard systems and supports devices such as Huawei phones.
+2. HarmonyOS system: HarmonyOS 5.1.0 Release and above.
+3. DevEco Studio version: DevEco Studio 5.1.0 Release and above.
+4. HarmonyOS SDK version: HarmonyOS 5.1.0 Release SDK or above.
+5. Dual end devices need to log in to the same Huawei account.
+6. Dual end devices require Wi Fi and Bluetooth switches to be turned on. When conditions permit, it is recommended that both devices be connected to the same local area network to improve data transmission speed.
\ No newline at end of file
diff --git a/README.md b/README.md
index 759390ff31bd40acd276bf79a722ed1e4f92c61c..a0a38298b9c2da99471bdedc2803e80bac14a2ff 100644
--- a/README.md
+++ b/README.md
@@ -1,37 +1,79 @@
-# CrossDeviceFileOperation
+# 基于Core File Kit(文件基础服务) 实现跨设备文件操作
-#### 介绍
-跨设备文件操作
+## 项目简介
-#### 软件架构
-软件架构说明
+本示例介绍了如何在多设备之间实现跨设备文件访问和拷贝的功能。
+## 效果预览
-#### 安装教程
+
-1. xxxx
-2. xxxx
-3. xxxx
+## 使用说明
-#### 使用说明
+1. 首页填写文件名和文件内容,点击“确定”按钮创建文件,若需要修改填写内容,点击“清空”按钮。
+2. 创建成功后,点击“远端文件”按钮,查看已创建好的文件。
+3. 远端文件列表列表:
+ - 右上角打开编辑状态,选择某一项文件,可在底部进行删除,或拷贝复制操作。左上角可取消编辑状态。
+ - 点击任意一项文件,进入预览界面。
+4. 本地文件列表列表:页面功能和远端文件列表大致相同,区别在于:
+ - 本地文件需要在远端文件列表中进行拷贝复制到本地。
+ - 编辑状态下无拷贝按钮。
+5. 预览界面:
+ - 点击编辑区域,自动进入编辑状态。
+ - 右上角对钩为编辑后保存按钮。
+ - 左上角叉号,如果进入编辑状态但未编辑,则直接返回上一页;如果进行了编辑,则弹窗询问是否保存,取消则撤回刚刚编辑内容,确定则保存内容。
-1. xxxx
-2. xxxx
-3. xxxx
-#### 参与贡献
+## 工程目录
-1. Fork 本仓库
-2. 新建 Feat_xxx 分支
-3. 提交代码
-4. 新建 Pull Request
+```
+├──entry/src/main/ets // 代码区
+│ ├──entryability
+│ │ └──EntryAbility.ets // 程序入口类
+│ ├──components // 公共组件
+│ │ ├──DeleteDialog.ets // 删除弹窗组件
+│ │ ├──EditTitleBar.ets // 编辑页顶部组件
+│ │ ├──ListComp.ets // 列表组件
+│ │ ├──Loading.ets // 加载弹窗组件
+│ │ ├──ProgressDialog.ets // 拷贝进度弹窗组件
+│ │ ├──TitleBar.ets // 通用顶部栏组件
+│ │ └──TitleBarDeleteDialog.ets // 通用顶部栏删除弹窗组件
+│ ├──pages
+│ │ └──Index.ets // 应用主界面
+│ ├──utils // 工具类
+│ │ └──CommonUtils.ets // 公共工具类
+│ └──view
+│ ├──LocalFileList.ets // 访问本地文件列表视图
+│ ├──Preview.ets // 预览界面
+│ └──RemoteFileList.ets // 访问远端文件列表视图
+└──entry/src/main/resources // 应用静态资源目录
+```
+## 具体实现
-#### 特技
+1. 获取当前应用分布式共享目录沙箱路径,通过[getUIContext()](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-custom-component-api#getuicontext)然后获取[getHostContext()](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-arkui-uicontext#gethostcontext12)
+ ,随后访问distributedFilesDir分布式共享目录。
+2. 创建文件通过[fs.openSync()](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-file-fs#fsopensync)以同步方法打开文件或目录,然后通过[fs.writeSync()](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-file-fs#fswritesync)以同步方法将数据写入文件,最后通过[fs.closeSync()](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-file-fs#fsclosesync)以同步方法关闭文件或目录,即可创建成功。
+3. 访问本地文件,通过[fs.listFile()](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-file-fs#fslistfile)列出本地filesDir沙箱路径目录下所有文件。
+4. 访问远端文件:
+ - 首先通过[设备管理接口](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-distributeddevicemanager)获取设备networkId。
+ - 通过[fs.connectDfs()](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-file-fs#fsconnectdfs12)开启跨设备文件访问。
+ - 随后通过[fs.listFile()](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-file-fs#fslistfile)列出远端沙箱路径distributedFilesDir目录下所有文件。
+5. 预览界面:
+ - 通过[fs.readTextSync()](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-file-fs#fsreadtextsync)读取沙箱路径下的某一项文件,格式为:fs.readTextSync(沙箱路径 + 文件名)。
+6. 保存功能:
+ - 通过[fs.openSync()](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-file-fs#fsopensync)以同步方法打开相应文件路径,随后通过[fs.writeSync()](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-file-fs#fswritesync)以同步方法将数据写入文件,最后通过[fs.closeSync()](https://developer.huawei.com/consumer/cn/doc/harmonyos-references/js-apis-file-fs#fsclosesync)以同步方法关闭文件,即可保存成功。
-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/)
+
+## 相关权限
+
+* ohos.permission.DISTRIBUTED_DATASYNC:允许不同设备间的数据交换。
+
+## 约束与限制
+
+1. 本示例仅支持标准系统上运行,支持设备:华为手机。
+2. HarmonyOS系统:HarmonyOS 5.1.0 Release及以上。
+3. DevEco Studio版本:DevEco Studio 5.1.0 Release及以上。
+4. HarmonyOS SDK版本:HarmonyOS 5.1.0 Release SDK及以上。
+5. 双端设备需要登录同一华为账号。
+6. 双端设备需要打开Wi-Fi和蓝牙开关。条件允许时,建议双端设备接入同一个局域网,可提升数据传输的速度。
diff --git a/build-profile.json5 b/build-profile.json5
new file mode 100644
index 0000000000000000000000000000000000000000..9a99d7b8fe6a3646328b983b10844efc25ec25ac
--- /dev/null
+++ b/build-profile.json5
@@ -0,0 +1,42 @@
+{
+ "app": {
+ "signingConfigs": [
+ ],
+ "products": [
+ {
+ "name": "default",
+ "signingConfig": "default",
+ "compatibleSdkVersion": "5.1.1(19)",
+ "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/code-linter.json5 b/code-linter.json5
new file mode 100644
index 0000000000000000000000000000000000000000..eaa4bb5eb40a6bccd365319fa01a5da9907b3efa
--- /dev/null
+++ b/code-linter.json5
@@ -0,0 +1,33 @@
+{
+ "files": [
+ "**/*.ets"
+ ],
+ "ignore": [
+ "**/src/ohosTest/**/*",
+ "**/src/test/**/*",
+ "**/src/mock/**/*",
+ "**/node_modules/**/*",
+ "**/oh_modules/**/*",
+ "**/build/**/*",
+ "**/.preview/**/*"
+ ],
+ "ruleSet": [
+ "plugin:@performance/recommended",
+ "plugin:@typescript-eslint/recommended"
+ ],
+ "rules": {
+ "@security/no-unsafe-aes": "error",
+ "@security/no-unsafe-hash": "error",
+ "@security/no-unsafe-mac": "warn",
+ "@security/no-unsafe-dh": "error",
+ "@security/no-unsafe-dsa": "error",
+ "@security/no-unsafe-ecdsa": "error",
+ "@security/no-unsafe-rsa-encrypt": "error",
+ "@security/no-unsafe-rsa-sign": "error",
+ "@security/no-unsafe-rsa-key": "error",
+ "@security/no-unsafe-dsa-key": "error",
+ "@security/no-unsafe-dh-key": "error",
+ "@security/no-unsafe-3des": "error",
+ "@typescript-eslint/semi": "error"
+ }
+}
\ No newline at end of file
diff --git a/entry/.gitignore b/entry/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..e2713a2779c5a3e0eb879efe6115455592caeea5
--- /dev/null
+++ b/entry/.gitignore
@@ -0,0 +1,6 @@
+/node_modules
+/oh_modules
+/.preview
+/build
+/.cxx
+/.test
\ No newline at end of file
diff --git a/entry/build-profile.json5 b/entry/build-profile.json5
new file mode 100644
index 0000000000000000000000000000000000000000..4d611879c7913fb0610c686e2399258ab3a6dad1
--- /dev/null
+++ b/entry/build-profile.json5
@@ -0,0 +1,28 @@
+{
+ "apiType": "stageMode",
+ "buildOption": {
+ },
+ "buildOptionSet": [
+ {
+ "name": "release",
+ "arkOptions": {
+ "obfuscation": {
+ "ruleOptions": {
+ "enable": false,
+ "files": [
+ "./obfuscation-rules.txt"
+ ]
+ }
+ }
+ }
+ },
+ ],
+ "targets": [
+ {
+ "name": "default"
+ },
+ {
+ "name": "ohosTest",
+ }
+ ]
+}
\ 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/components/DeleteDialog.ets b/entry/src/main/ets/components/DeleteDialog.ets
new file mode 100644
index 0000000000000000000000000000000000000000..b3269a5ba3ebe746d6a56285451ca15b3ba29676
--- /dev/null
+++ b/entry/src/main/ets/components/DeleteDialog.ets
@@ -0,0 +1,73 @@
+/*
+ * 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.
+ */
+
+@CustomDialog
+export struct DeleteDialog {
+ controller?: CustomDialogController;
+ confirmBtn: () => void = () => {
+ };
+ confirmCancel: () => void = () => {
+ };
+
+ build() {
+ Column() {
+ Text($r('app.string.delete_file'))
+ .fontSize(20)
+ .fontWeight(700)
+ .margin({
+ bottom: 23
+ })
+ Text($r('app.string.confirm_to_delete_the_file'))
+ .fontWeight(500)
+ .margin({
+ bottom: 8
+ })
+ Row() {
+ Button($r('app.string.cancel'),
+ { buttonStyle: ButtonStyleMode.TEXTUAL, role: ButtonRole.NORMAL, stateEffect: false })
+ .fontSize(16)
+ .fontColor('#0A59F7')
+ .onClick(() => {
+ this.confirmCancel();
+ })
+ Divider()
+ .vertical(true)
+ .height(22)
+ .color('#33000000')
+ .opacity(0.6)
+ .margin({ left: 50, right: 50 })
+ Button($r('app.string.confirm'),
+ { buttonStyle: ButtonStyleMode.TEXTUAL, role: ButtonRole.NORMAL, stateEffect: false })
+ .fontSize(16)
+ .fontColor('#0A59F7')
+ .onClick(() => {
+ this.confirmBtn();
+ })
+ }
+ .width('100%')
+ .justifyContent(FlexAlign.Center)
+ .alignItems(VerticalAlign.Center)
+
+ }
+ .margin({
+ left: 16,
+ right: 16
+ })
+ .justifyContent(FlexAlign.Center)
+ .backgroundColor(Color.White)
+ .borderRadius(32)
+ .padding(16)
+ }
+}
diff --git a/entry/src/main/ets/components/EditTitleBar.ets b/entry/src/main/ets/components/EditTitleBar.ets
new file mode 100644
index 0000000000000000000000000000000000000000..2c0e06a2f1b1e49f9b298967ce3258ba02eba85a
--- /dev/null
+++ b/entry/src/main/ets/components/EditTitleBar.ets
@@ -0,0 +1,116 @@
+/*
+ * 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.
+ */
+
+@Component
+export struct EditTitleBar {
+ @State uiContext: UIContext | undefined = AppStorage.get('uiContext');
+ @Link isEdit: boolean;
+ @Link editTile: Resource;
+ @Link selectedValue: string | null;
+ @Link fileListArr: string[];
+ @Consume('pageInfo') pageStack: NavPathStack;
+ @Consume('isDeleteChange') isDeleteChange: boolean;
+
+ build() {
+ Row() {
+ Row() {
+ if (!this.isEdit) {
+ Row() {
+ SymbolGlyph($r('sys.symbol.chevron_backward'))
+ .fontColor(['rgba(0,0,0,0.9)'])
+ .fontSize(24)
+ }
+ .width(40)
+ .height(40)
+ .borderRadius('50%')
+ .backgroundColor('rgba(0,0,0,0.05)')
+ .alignItems(VerticalAlign.Center)
+ .justifyContent(FlexAlign.Center)
+ .onClick(() => {
+ this.pageStack.pop();
+ })
+ } else {
+ Row() {
+ SymbolGlyph($r('sys.symbol.xmark'))
+ .fontColor(['rgba(0,0,0,0.9)'])
+ .fontSize(24)
+ }
+ .width(40)
+ .height(40)
+ .borderRadius('50%')
+ .backgroundColor('rgba(0,0,0,0.05)')
+ .alignItems(VerticalAlign.Center)
+ .justifyContent(FlexAlign.Center)
+ .onClick(() => {
+ this.isEdit = false;
+ this.selectedValue = null;
+ })
+ }
+
+ Text(this.isEdit ? $r('app.string.edit') : this.editTile)
+ .fontSize(20)
+ .fontWeight(700)
+ .margin({
+ left: 8
+ })
+ }
+ .width('50%')
+
+ if (this.isEdit) {
+ Row() {
+ Row() {
+ SymbolGlyph($r('sys.symbol.checkmark'))
+ .fontColor(['rgba(0,0,0,0.9)'])
+ .fontSize(24)
+ }
+ .width(40)
+ .height(40)
+ .borderRadius('50%')
+ .backgroundColor('rgba(0,0,0,0.05)')
+ .alignItems(VerticalAlign.Center)
+ .justifyContent(FlexAlign.Center)
+ }
+ .width('50%')
+ .justifyContent(FlexAlign.End)
+ .onClick(() => {
+ this.isEdit = false;
+ this.selectedValue = null;
+ })
+ } else {
+ if (this.fileListArr.length > 0) {
+ Row() {
+ SymbolGlyph($r('sys.symbol.square_and_pencil'))
+ .fontColor(['rgba(0,0,0,0.9)'])
+ .fontSize(24)
+ }
+ .width(40)
+ .height(40)
+ .borderRadius('50%')
+ .backgroundColor('rgba(0,0,0,0.05)')
+ .alignItems(VerticalAlign.Center)
+ .justifyContent(FlexAlign.Center)
+ .onClick(() => {
+ this.isEdit = true;
+ })
+ }
+ }
+ }
+ .margin({
+ bottom: 28
+ })
+ .width('100%')
+ .justifyContent(FlexAlign.SpaceBetween)
+ }
+}
\ No newline at end of file
diff --git a/entry/src/main/ets/components/ListComp.ets b/entry/src/main/ets/components/ListComp.ets
new file mode 100644
index 0000000000000000000000000000000000000000..d3b9b70a9f5e294a1a603953ed6c392716bf2b30
--- /dev/null
+++ b/entry/src/main/ets/components/ListComp.ets
@@ -0,0 +1,109 @@
+/*
+ * 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.
+ */
+
+interface Param {
+ fileName: string
+ path: string
+}
+
+@Component
+export struct ListComp {
+ confirmBtn: () => void = () => {
+ };
+ confirmCancel: () => void = () => {
+ };
+ @Consume('pageInfo') pageStack: NavPathStack;
+ @Link fileListArr: string[];
+ @Link isEdit: boolean;
+ @Link selectedValue: string | null;
+ @Link pathDir: string;
+
+ build() {
+ Column() {
+ Row() {
+ Text($r('app.string.file_list'))
+ .fontSize(14)
+ .fontWeight(500)
+ .fontColor('rgba(0,0,0,0.6)')
+ .width('100%')
+ .margin({ left: 12, bottom: 8 })
+ }
+ .width('100%')
+ .justifyContent(FlexAlign.SpaceAround)
+
+ List({ space: 12, initialIndex: 0 }) {
+ ForEach(this.fileListArr, (item: string) => {
+ ListItem() {
+ Row() {
+ Text(item)
+ .fontWeight(500)
+ if (this.isEdit) {
+ Radio({
+ value: item, group: 'localRadioGroup',
+ indicatorType: RadioIndicatorType.TICK
+ })
+ .width(20)
+ .height(20)
+ .checked(this.selectedValue === item)
+ .onChange((isChecked: boolean) => {
+ if (isChecked) {
+ this.selectedValue = item;
+ }
+ })
+ .onClick(() => {
+ this.selectedValue = item;
+ })
+ } else {
+ SymbolGlyph($r('sys.symbol.chevron_right'))
+ .fontColor(['rgba(0,0,0,0.2)'])
+ .fontSize(24)
+ .width(12)
+ .height(24)
+ }
+ }
+ .width('100%')
+ .height(56)
+ .borderRadius(16)
+ .backgroundColor(Color.White)
+ .justifyContent(FlexAlign.SpaceBetween)
+ .padding({
+ top: 17,
+ right: 12,
+ bottom: 17,
+ left: 12
+ })
+ .onClick(() => {
+ this.selectedValue = item;
+ const param: Param = {
+ fileName: this.selectedValue,
+ path: this.pathDir
+ };
+ if (!this.isEdit) {
+ this.pageStack.pushPathByName('Preview', param);
+ }
+ })
+ }
+ }, (item: string) => item)
+ }
+ .width('100%')
+ .height('100%')
+ .scrollBar(BarState.Off)
+ }
+ .width('100%')
+ .margin({
+ bottom: this.isEdit ? 48 : 0
+ })
+ }
+}
diff --git a/entry/src/main/ets/components/Loading.ets b/entry/src/main/ets/components/Loading.ets
new file mode 100644
index 0000000000000000000000000000000000000000..f5aef628433442295bc6f58eba8c2f0cc59aad6a
--- /dev/null
+++ b/entry/src/main/ets/components/Loading.ets
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ */
+@CustomDialog
+struct Dialog {
+ controller?: CustomDialogController;
+
+ build() {
+ Column() {
+ LoadingProgress()
+ .color('#666666')
+ .width(72)
+ .height(72)
+ .scale({ x: 1.3, y: 1.3 })
+ Text($r('app.string.loading'))
+ .fontSize(14)
+ .fontWeight(400)
+ .fontColor('rgba(0,0,0,0.6)')
+ .margin({
+ top: 24
+ })
+ }
+ .padding({
+ bottom: 112
+ })
+ .justifyContent(FlexAlign.Center)
+ .alignItems(HorizontalAlign.Center)
+ .width('100%')
+ .height('100%')
+ .backgroundColor('rgb(241,243,245)')
+ }
+}
+
+@Component
+export struct Loading {
+ deviceListDialogController: CustomDialogController = new CustomDialogController({
+ builder: Dialog(),
+ alignment: DialogAlignment.Center,
+ autoCancel: false,
+ customStyle: true
+ });
+
+ build() {
+ Column() {
+ Dialog();
+ }
+ }
+}
\ No newline at end of file
diff --git a/entry/src/main/ets/components/ProgressDialog.ets b/entry/src/main/ets/components/ProgressDialog.ets
new file mode 100644
index 0000000000000000000000000000000000000000..5357e9ef8176c4f97e3bdda26d4ce3c7a99e18c8
--- /dev/null
+++ b/entry/src/main/ets/components/ProgressDialog.ets
@@ -0,0 +1,78 @@
+/*
+ * 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.
+ */
+
+@CustomDialog
+export struct ProgressDialog {
+ controller?: CustomDialogController;
+ @Link value: number;
+ @Link total: number;
+
+ build() {
+ Column() {
+ Row() {
+ Text($r('app.string.file_copying'))
+ .fontSize(14)
+ .fontWeight(400)
+ .fontColor('rgba(0,0,0,0.9)')
+ .width('50%')
+ Text(this.value / this.total * 100 + '%')
+ .fontSize(14)
+ .fontWeight(400)
+ .fontColor('rgba(0,0,0,0.6)')
+ .textAlign(TextAlign.End)
+ .margin({
+ right: 36
+ })
+ }
+ .margin({
+ bottom: 4
+ })
+ .width('100%')
+ .justifyContent(FlexAlign.SpaceBetween)
+ .alignItems(VerticalAlign.Center)
+
+ Row() {
+ Progress({ value: this.value, total: this.total, type: ProgressType.Linear })
+ .color('#0A59F7')
+ .height(4)
+ .margin({
+ right: 36
+ })
+ SymbolGlyph($r('sys.symbol.xmark_circle_fill'))
+ .fontColor(['rgba(0,0,0,0.4)'])
+ .width(24)
+ .height(24)
+ .margin({
+ left: -36
+ })
+ .onClick(() => {
+ this.controller?.close();
+ })
+ }
+ .width('100%')
+ .justifyContent(FlexAlign.SpaceBetween)
+ .alignItems(VerticalAlign.Center)
+ }
+ .margin({
+ left: 16,
+ right: 16
+ })
+ .height(96)
+ .justifyContent(FlexAlign.End)
+ .backgroundColor(Color.White)
+ .borderRadius(32)
+ .padding(24)
+ }
+}
diff --git a/entry/src/main/ets/components/TitleBar.ets b/entry/src/main/ets/components/TitleBar.ets
new file mode 100644
index 0000000000000000000000000000000000000000..97817a784630bab7b38e4e9b5e10893995ca673c
--- /dev/null
+++ b/entry/src/main/ets/components/TitleBar.ets
@@ -0,0 +1,150 @@
+/*
+ * 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 as fs, WriteOptions } from '@kit.CoreFileKit';
+import CommonUtils from '../utils/CommonUtils';
+import { TitleBarDeleteDialog } from './TitleBarDeleteDialog';
+import { hilog } from '@kit.PerformanceAnalysisKit';
+
+@Component
+export struct TitleBar {
+ @State uiContext: UIContext | undefined = AppStorage.get('uiContext');
+ @Consume('pageInfo') pageStack: NavPathStack;
+ @Link isEdit: boolean;
+ @Link filePath: string;
+ @Link fileTile: string;
+ @Link fileContent: string;
+ @State oldFileContent: string = '';
+ stopEdit: () => void = () => {
+ };
+ deleteDialogController: CustomDialogController = new CustomDialogController({
+ builder: TitleBarDeleteDialog({
+ confirmCancel: () => {
+ this.deleteDialogController.close();
+ this.fileContent = this.oldFileContent;
+ this.isEdit = false;
+ },
+ confirmBtn: () => {
+ this.saveFile();
+ this.deleteDialogController.close();
+ },
+ }),
+ alignment: DialogAlignment.Center,
+ autoCancel: false,
+ customStyle: true
+ });
+ @Consume('isDeleteChange') isDeleteChange: boolean;
+
+ aboutToAppear(): void {
+ this.oldFileContent = this.fileContent;
+ }
+
+ saveFile() {
+ try {
+ const file = fs.openSync(this.filePath + `/${this.fileTile}`,
+ fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE | fs.OpenMode.TRUNC);
+ const writeOptions: WriteOptions = {
+ offset: 0, // Key point: Reset write position
+ length: this.fileContent.length
+ };
+ let writeLen = fs.writeSync(file.fd, this.fileContent, writeOptions);
+ fs.fsyncSync(file.fd);
+ if (writeLen) {
+ fs.closeSync(file);
+ CommonUtils.showToast($r('app.string.successfully_saved'), this.uiContext!);
+ this.pageStack.pop();
+ this.isDeleteChange = !this.isDeleteChange;
+ }
+ } catch (error) {
+ hilog.error(0xFF00, 'error', '%{public}s', 'have errors', `${JSON.stringify(error)}`);
+ }
+ }
+
+ build() {
+ Row() {
+ Row() {
+ Row() {
+ if (!this.isEdit) {
+ Row() {
+ SymbolGlyph($r('sys.symbol.chevron_backward'))
+ .fontColor(['rgba(0,0,0,0.9)'])
+ .fontSize(24)
+ }
+ .width(40)
+ .height(40)
+ .borderRadius('50%')
+ .backgroundColor('rgba(0,0,0,0.05)')
+ .alignItems(VerticalAlign.Center)
+ .justifyContent(FlexAlign.Center)
+ .onClick(() => {
+ this.pageStack.pop();
+ })
+ } else {
+ Row() {
+ SymbolGlyph($r('sys.symbol.xmark'))
+ .fontColor(['rgba(0,0,0,0.9)'])
+ .fontSize(24)
+ }
+ .width(40)
+ .height(40)
+ .borderRadius('50%')
+ .backgroundColor('rgba(0,0,0,0.05)')
+ .alignItems(VerticalAlign.Center)
+ .justifyContent(FlexAlign.Center)
+ .onClick(() => {
+ if (this.oldFileContent !== this.fileContent) {
+ this.stopEdit();
+ this.deleteDialogController.open();
+ } else {
+ this.isEdit = false;
+ this.pageStack.pop();
+ }
+ })
+ }
+
+ Text(this.isEdit ? $r('app.string.edit') : $r('app.string.file_preview'))
+ .fontSize(20)
+ .fontWeight(700)
+ .margin({
+ left: 8
+ })
+ }
+ .width('60%')
+
+ if (this.isEdit) {
+ Row() {
+ Row() {
+ SymbolGlyph($r('sys.symbol.checkmark'))
+ .fontColor(['rgba(0,0,0,0.9)'])
+ .fontSize(24)
+ }
+ .width(40)
+ .height(40)
+ .borderRadius('50%')
+ .backgroundColor('rgba(0,0,0,0.05)')
+ .alignItems(VerticalAlign.Center)
+ .justifyContent(FlexAlign.Center)
+ }
+ .onClick(() => {
+ this.saveFile();
+ })
+ .width('40%')
+ .justifyContent(FlexAlign.End)
+ }
+ }
+ }
+ .width('100%')
+ .justifyContent(FlexAlign.SpaceBetween)
+ }
+}
\ No newline at end of file
diff --git a/entry/src/main/ets/components/TitleBarDeleteDialog.ets b/entry/src/main/ets/components/TitleBarDeleteDialog.ets
new file mode 100644
index 0000000000000000000000000000000000000000..9c2b4ba857bdff6c395bff8ed7cddc1c26d37f76
--- /dev/null
+++ b/entry/src/main/ets/components/TitleBarDeleteDialog.ets
@@ -0,0 +1,72 @@
+/*
+ * 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.
+ */
+
+@CustomDialog
+export struct TitleBarDeleteDialog {
+ controller?: CustomDialogController;
+ confirmBtn: () => void = () => {
+ };
+ confirmCancel: () => void = () => {
+ };
+
+ build() {
+ Column() {
+ Text($r('app.string.do_you_want_to_save_it'))
+ .fontSize(20)
+ .fontWeight(700)
+ .margin({
+ bottom: 23
+ })
+ Text($r('app.string.confirm_to_save_the_file'))
+ .fontWeight(500)
+ .margin({
+ bottom: 8
+ })
+ Row() {
+ Button($r('app.string.cancel'),
+ { buttonStyle: ButtonStyleMode.TEXTUAL, role: ButtonRole.NORMAL, stateEffect: false })
+ .fontSize(16)
+ .fontColor('#0A59F7')
+ .onClick(() => {
+ this.confirmCancel();
+ })
+ Divider()
+ .vertical(true)
+ .height(22)
+ .color('#33000000')
+ .opacity(0.6)
+ .margin({ left: 50, right: 50 })
+ Button($r('app.string.confirm'),
+ { buttonStyle: ButtonStyleMode.TEXTUAL, role: ButtonRole.NORMAL, stateEffect: false })
+ .fontSize(16)
+ .fontColor('#0A59F7')
+ .onClick(() => {
+ this.confirmBtn();
+ })
+ }
+ .width('100%')
+ .justifyContent(FlexAlign.Center)
+ .alignItems(VerticalAlign.Center)
+ }
+ .margin({
+ left: 16,
+ right: 16
+ })
+ .justifyContent(FlexAlign.Center)
+ .backgroundColor(Color.White)
+ .borderRadius(32)
+ .padding(16)
+ }
+}
diff --git a/entry/src/main/ets/entryability/EntryAbility.ets b/entry/src/main/ets/entryability/EntryAbility.ets
new file mode 100644
index 0000000000000000000000000000000000000000..6da9648479ca325a1afc48c710e792507abc6f45
--- /dev/null
+++ b/entry/src/main/ets/entryability/EntryAbility.ets
@@ -0,0 +1,95 @@
+/*
+ * 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 { abilityAccessCtrl, AbilityConstant, ConfigurationConstant, UIAbility, Want } from '@kit.AbilityKit';
+import { hilog } from '@kit.PerformanceAnalysisKit';
+import { window } from '@kit.ArkUI';
+
+const DOMAIN = 0x0000;
+let uiContext: UIContext | undefined = undefined;
+
+export default class EntryAbility extends UIAbility {
+ onCreate(_want: Want, _launchParam: AbilityConstant.LaunchParam): void {
+ this.permissions();
+ try {
+ this.context.getApplicationContext().setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET);
+ hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onCreate');
+ } catch (error) {
+ hilog.error(0xFF00, 'error', '%{public}s', 'have errors', `${JSON.stringify(error)}`);
+ }
+
+ }
+
+ onNewWant(_want: Want, _launchParam: AbilityConstant.LaunchParam): void {
+ this.permissions();
+ }
+
+ 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;
+ }
+ hilog.info(DOMAIN, 'testTag', 'Succeeded in loading the content.');
+ uiContext = windowStage.getMainWindowSync().getUIContext();
+ AppStorage.setOrCreate('uiContext', windowStage.getMainWindowSync().getUIContext());
+ });
+ }
+
+ 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');
+ }
+
+ /**
+ * Apply for the permission to exchange data between different devices.
+ */
+ async permissions() {
+ try {
+ let atManager = abilityAccessCtrl.createAtManager();
+ const result = await atManager.requestPermissionsFromUser(this.context, ['ohos.permission.DISTRIBUTED_DATASYNC']);
+
+ if (result.authResults[0] !== -1) {
+ uiContext!.getPromptAction().showToast({ message: $r('app.string.authorization_successful') });
+ }
+
+ const resultAgain =
+ await atManager.requestPermissionOnSetting(this.context, ['ohos.permission.DISTRIBUTED_DATASYNC']);
+ if (resultAgain[0] === 0) {
+ uiContext!.getPromptAction().showToast({ message: $r('app.string.authorization_successful') });
+ }
+ uiContext!.getPromptAction().showToast({ message: $r('app.string.reauthorization') });
+ } catch (error) {
+ hilog.error(0xFF00, 'error', '%{public}s', 'have errors', `${JSON.stringify(error)}`);
+ }
+ }
+}
\ 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..8e4de99282050bad799ac892eb85ac5449364a51
--- /dev/null
+++ b/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets
@@ -0,0 +1,16 @@
+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/pages/Index.ets b/entry/src/main/ets/pages/Index.ets
new file mode 100644
index 0000000000000000000000000000000000000000..08408bdc2949354609110acc2888da5d28dc51e0
--- /dev/null
+++ b/entry/src/main/ets/pages/Index.ets
@@ -0,0 +1,176 @@
+/*
+ * 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 as fs } from '@kit.CoreFileKit';
+import CommonUtils from '../utils/CommonUtils';
+import { hilog } from '@kit.PerformanceAnalysisKit';
+
+@Entry
+@Component
+struct Index {
+ @Provide('pageInfo') pageStack: NavPathStack = new NavPathStack();
+ @Provide('isDeleteChange') isDeleteChange: boolean = false;
+ @State uiContext: UIContext | undefined = AppStorage.get('uiContext');
+ @State context: Context = this.getUIContext().getHostContext() as common.UIAbilityContext;
+ @State fileTile: string = '';
+ @State fileContent: string = '';
+
+ createFile() {
+ if (this.fileTile === '' && this.fileContent === '') {
+ CommonUtils.showToast($r('app.string.file_name_and_file_content_cannot_be_empty'), this.uiContext!);
+ return;
+ }
+ // Get the file path of the distributed directory
+ let pathDir: string = this.context.distributedFilesDir;
+ let filePath: string = pathDir + `/${this.fileTile}.txt`;
+ try {
+ // Create files in a distributed directory
+ let file = fs.openSync(filePath, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);
+ hilog.info(0x0000, 'Index', '%{public}s', 'Succeeded in creating.');
+ // Write content to a file
+ fs.writeSync(file.fd, this.fileContent);
+ // close file
+ fs.closeSync(file.fd);
+ CommonUtils.showToast($r('app.string.created_successfully'), this.uiContext!);
+ this.fileTile = '';
+ this.fileContent = '';
+ } catch (error) {
+ hilog.error(0x0000, 'Index', '%{public}s',
+ 'Failed to openSync / writeSync / closeSync. Code: $\{error.code}, message: $\{error.message}');
+ }
+ }
+
+ clear() {
+ this.fileTile = '';
+ this.fileContent = '';
+ }
+
+ build() {
+ Navigation(this.pageStack) {
+ Column({ space: 12 }) {
+ Column({ space: 12 }) {
+ Text($r('app.string.create_a_file'))
+ .padding({
+ top: 9,
+ bottom: 0
+ })
+ .fontSize(18)
+ .fontWeight(700)
+ .fontColor('rgba(0,0,0,0.9)')
+ TextInput({ text: $$this.fileTile, placeholder: $r('app.string.please_enter_a_file_name') })
+ .width('100%')
+ .height(56)
+ .borderRadius(16)
+ .backgroundColor(Color.White)
+ TextArea({ text: $$this.fileContent, placeholder: $r('app.string.please_enter_the_file_content') })
+ .backgroundColor(Color.White)
+ .lineBreakStrategy(LineBreakStrategy.GREEDY)
+ .layoutWeight(1)
+ .borderRadius(16)
+ Row({ space: 12 }) {
+ Button($r('app.string.clean'), { buttonStyle: ButtonStyleMode.NORMAL })
+ .layoutWeight(1)
+ .margin({ right: 6 })
+ .onClick(() => {
+ this.clear();
+ });
+
+ Button($r('app.string.sure'))
+ .layoutWeight(1)
+ .enabled(!!(this.fileContent && this.fileTile))
+ .onClick(() => {
+ this.createFile();
+ });
+ }
+ .width('100%')
+ .justifyContent(FlexAlign.SpaceBetween)
+ }
+ .alignItems(HorizontalAlign.Start)
+ .width('100%')
+ .margin({
+ bottom: 236
+ })
+
+ Column({ space: 12 }) {
+ Text($r('app.string.view_file'))
+ .padding({
+ top: 24,
+ bottom: 0
+ })
+ .width('100%')
+ .textAlign(TextAlign.Start)
+ .fontSize(18)
+ .fontWeight(700)
+ .fontColor('rgba(0,0,0,0.9)')
+ Row() {
+ Text($r('app.string.local_file'))
+ .fontWeight(500)
+ SymbolGlyph($r('sys.symbol.chevron_right'))
+ .fontColor(['rgba(0,0,0,0.2)'])
+ .fontSize(24)
+ .width(12)
+ .height(24)
+ }
+ .padding({
+ left: 12,
+ right: 12
+ })
+ .width('100%')
+ .height(56)
+ .borderRadius(16)
+ .backgroundColor(Color.White)
+ .justifyContent(FlexAlign.SpaceBetween)
+ .onClick(() => {
+ this.pageStack.replacePathByName('LocalFileList', '');
+ });
+
+ Row() {
+ Text($r('app.string.remote_file'))
+ .fontWeight(500)
+ SymbolGlyph($r('sys.symbol.chevron_right'))
+ .fontColor(['rgba(0,0,0,0.2)'])
+ .fontSize(24)
+ .width(12)
+ .height(24)
+ }
+ .padding({
+ left: 12,
+ right: 12
+ })
+ .width('100%')
+ .height(56)
+ .borderRadius(16)
+ .backgroundColor(Color.White)
+ .justifyContent(FlexAlign.SpaceBetween)
+ .onClick(() => {
+ this.pageStack.replacePathByName('RemoteFileList', '');
+ });
+ }
+ .margin({
+ top: -200
+ })
+ .width('100%')
+ }
+ .padding(16)
+ .width('100%')
+ .height('100%')
+ .justifyContent(FlexAlign.Start)
+ }
+ .backgroundColor('rgb(241,243,245)')
+ .title($r('app.string.EntryAbility_label'))
+ .height('100%')
+ .width('100%')
+ }
+}
\ No newline at end of file
diff --git a/entry/src/main/ets/utils/CommonUtils.ets b/entry/src/main/ets/utils/CommonUtils.ets
new file mode 100644
index 0000000000000000000000000000000000000000..701165020496688ce037dd38a92caa196f815a4f
--- /dev/null
+++ b/entry/src/main/ets/utils/CommonUtils.ets
@@ -0,0 +1,43 @@
+/*
+ * 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 { fileIo as fs } from '@kit.CoreFileKit';
+import { BusinessError } from "@kit.BasicServicesKit";
+
+class CommonUtils {
+ public showToast(message: ResourceStr, uiContext: UIContext) {
+ try {
+ uiContext.getPromptAction().showToast({ message });
+ } catch (error) {
+ hilog.error(0xFF00, 'error', '%{public}s', 'have errors', `${JSON.stringify(error)}`);
+ }
+ };
+
+ public delete(selectedValue: string, pathDir: string, uiContext: UIContext, callback: (result: boolean) => void) {
+ const srcUri = pathDir + `/${selectedValue}`;
+ fs.unlink(srcUri, (err: BusinessError) => {
+ if (err) {
+ hilog.error(0x0000, 'RemoteFile', '%{public}s',
+ ("remove file failed with error message: " + err.message + ", error code: " + err.code));
+ callback(false);
+ } else {
+ this.showToast($r('app.string.delete_successfully'), uiContext!);
+ callback(true);
+ }
+ });
+ }
+}
+
+export default new CommonUtils();
diff --git a/entry/src/main/ets/view/LocalFileList.ets b/entry/src/main/ets/view/LocalFileList.ets
new file mode 100644
index 0000000000000000000000000000000000000000..da5cf050c09b36274bfa4f23281c5643a834f966
--- /dev/null
+++ b/entry/src/main/ets/view/LocalFileList.ets
@@ -0,0 +1,214 @@
+/*
+ * 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 as fs } from '@kit.CoreFileKit';
+import { common } from '@kit.AbilityKit';
+import CommonUtils from '../utils/CommonUtils';
+import { BusinessError } from '@kit.BasicServicesKit';
+import { ListComp } from '../components/ListComp';
+import { Loading } from '../components/Loading';
+import { EditTitleBar } from '../components/EditTitleBar';
+import { DeleteDialog } from '../components/DeleteDialog';
+import { hilog } from '@kit.PerformanceAnalysisKit';
+
+@Builder
+export function LocalFileListBuild() {
+ LocalFileList();
+}
+
+@Component
+export struct LocalFileList {
+ @Consume('pageInfo') pageStack: NavPathStack;
+ @State uiContext: UIContext | undefined = AppStorage.get('uiContext');
+ @State context: Context = this.getUIContext().getHostContext() as common.UIAbilityContext;
+ @State isEdit: boolean = false;
+ @State isShowDialog: boolean = false;
+ @State isLocalFileChecked: boolean = false;
+ @State selectedValue: string | null = null;
+ @State localFileListArr: string[] = [];
+ @State pathDir: string = '';
+ @State editTile: Resource = $r('app.string.local_file');
+ @Consume('isDeleteChange') @Watch('handleGetList') isDeleteChange: boolean;
+ DeleteDialogController: CustomDialogController = new CustomDialogController({
+ builder: DeleteDialog({
+ confirmBtn: () => {
+ this.delete();
+ },
+ confirmCancel: () => {
+ this.DeleteDialogController.close();
+ },
+ }),
+ alignment: DialogAlignment.Center,
+ autoCancel: false,
+ customStyle: true
+ });
+
+ aboutToAppear() {
+ this.getFileList();
+ }
+
+ handleGetList() {
+ this.getFileList();
+ }
+
+ async getFileList() {
+ this.isShowDialog = true;
+ // Get the file path of the local directory
+ let pathDir: string = this.context.filesDir;
+ this.pathDir = pathDir;
+ try {
+ this.localFileListArr = await fs.listFile(pathDir);
+ } catch (error) {
+ hilog.error(0xFF00, 'error', '%{public}s', 'have errors', `${JSON.stringify(error)}`);
+ }
+ if (this.localFileListArr.length > 0) {
+ this.isShowDialog = false;
+ } else {
+ this.isEdit = false;
+ this.isShowDialog = false;
+ }
+ }
+
+ delete() {
+ if (!this.selectedValue) {
+ CommonUtils.showToast($r('app.string.Please_select_a_file'), this.uiContext!);
+ } else {
+ CommonUtils.delete(this.selectedValue, this.pathDir, this.uiContext!, (result) => {
+ if (result) {
+ this.DeleteDialogController.close();
+ this.isShowDialog = true;
+ this.selectedValue = null;
+ this.getFileList();
+ }
+ });
+ }
+ }
+
+ build() {
+ NavDestination() {
+ Column({ space: 12 }) {
+ EditTitleBar({
+ isEdit: this.isEdit,
+ editTile: this.editTile,
+ selectedValue: this.selectedValue,
+ fileListArr: this.localFileListArr
+ })
+ if (!this.isShowDialog) {
+ Column({ space: 12 }) {
+ Column({ space: 12 }) {
+ if (this.localFileListArr.length > 0) {
+ ListComp(
+ {
+ fileListArr: this.localFileListArr,
+ isEdit: this.isEdit,
+ selectedValue: this.selectedValue,
+ pathDir: this.pathDir
+ }
+ );
+ } else {
+ Column() {
+ Image($r('app.media.NoInstallationPackage'))
+ .width(120)
+ .height(120)
+ Text($r('app.string.please_copy_the_file_first'))
+ .fontSize(14)
+ .fontWeight(400)
+ .fontColor('#434343')
+ }
+ .alignItems(HorizontalAlign.Center)
+ .justifyContent(FlexAlign.Center)
+ .width('100%')
+ .height('100%')
+ }
+ }
+ .width('100%')
+ .height('100%')
+ }
+ .width('100%')
+ .margin({
+ bottom: 78
+ })
+ .justifyContent(FlexAlign.SpaceBetween)
+ .alignItems(HorizontalAlign.Start)
+
+ if (this.isEdit) {
+ Row() {
+ Column() {
+ SymbolGlyph($r('sys.symbol.trash'))
+ .fontColor(['rgba(0,0,0,0.9)'])
+ .fontSize(24)
+ .margin({
+ bottom: 6
+ })
+ Text($r('app.string.delete'))
+ .fontSize(12)
+ .fontWeight(400)
+ .fontColor('rgba(0,0,0,0.9)')
+ }
+ .width('40%')
+ .onClick(() => {
+ if (this.selectedValue) {
+ this.DeleteDialogController.open();
+ } else {
+ CommonUtils.showToast($r('app.string.Please_select_a_file'), this.uiContext!);
+ }
+ })
+ }
+ .width('100%')
+ .height(48)
+ .justifyContent(FlexAlign.Center)
+ .margin({
+ top: -94
+ })
+ .backgroundColor('rgb(241,243,245)')
+ } else {
+ if (this.localFileListArr.length === 0) {
+ Button($r('app.string.return_to_the_previous_page'), { buttonStyle: ButtonStyleMode.NORMAL })
+ .width('100%')
+ .height(40)
+ .fontColor('#0A59F7')
+ .margin({
+ top: -94
+ })
+ .onClick(async () => {
+ this.pageStack.pop();
+ });
+ } else {
+ Row() {
+ }.width('100%')
+ .height(40)
+ }
+ }
+ } else {
+ Loading();
+ }
+ }
+ .backgroundColor('rgb(241,243,245)')
+ .padding({
+ top: 8,
+ right: 16,
+ bottom: 16,
+ left: 16
+ })
+ .width('100%')
+ .height('100%')
+ .justifyContent(FlexAlign.SpaceBetween)
+
+ }
+ .mode(NavDestinationMode.DIALOG)
+ .systemTransition(NavigationSystemTransitionType.SLIDE_RIGHT)
+ .title(this.isEdit ? $r('app.string.edit') : $r('app.string.local_file'))
+ .hideTitleBar(true)
+ }
+}
\ No newline at end of file
diff --git a/entry/src/main/ets/view/Preview.ets b/entry/src/main/ets/view/Preview.ets
new file mode 100644
index 0000000000000000000000000000000000000000..0a7c814ca8324d5563537273c4734487d04667cd
--- /dev/null
+++ b/entry/src/main/ets/view/Preview.ets
@@ -0,0 +1,113 @@
+/*
+ * 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 as fs } from '@kit.CoreFileKit';
+import { TitleBar } from '../components/TitleBar';
+import { hilog } from '@kit.PerformanceAnalysisKit';
+
+interface Param {
+ fileName: string
+ path: string
+}
+
+@Builder
+export function PreviewBuild() {
+ Preview();
+}
+
+
+@Component
+export struct Preview {
+ @State uiContext: UIContext | undefined = AppStorage.get('uiContext');
+ @Consume('pageInfo') pageStack: NavPathStack;
+ controller: TextInputController = new TextInputController();
+ @State fileContent: string = '';
+ @State targetPath: string = '';
+ @State filePath: string = '';
+ @State fileTile: string = '';
+ @State isEdit: boolean = false;
+ @Consume('isDeleteChange') isDeleteChange: boolean;
+
+ aboutToAppear(): void {
+ const param = this.pageStack.getParamByName('Preview')[0] as Param;
+ this.fileTile = param.fileName;
+ this.filePath = param.path;
+ this.targetPath = this.filePath + `/${this.fileTile}`;
+ try {
+ this.fileContent = fs.readTextSync(this.targetPath);
+ } catch (error) {
+ hilog.error(0xFF00, 'error', '%{public}s', 'have errors', `${JSON.stringify(error)}`);
+ }
+ }
+
+ stopEdit() {
+ this.controller.stopEditing();
+ }
+
+ build() {
+ NavDestination() {
+ Column({ space: 12 }) {
+ TitleBar({
+ isEdit: this.isEdit,
+ filePath: this.filePath,
+ fileTile: this.fileTile,
+ fileContent: this.fileContent,
+ stopEdit: () => {
+ this.stopEdit();
+ }
+ })
+
+ Column({ space: 12 }) {
+ Text(this.fileTile)
+ .fontSize(24)
+ .fontWeight(500)
+ .margin({
+ top: 8
+ })
+ Column({ space: 12 }) {
+ TextArea({ text: $$this.fileContent, controller: this.controller })
+ .lineBreakStrategy(LineBreakStrategy.GREEDY)
+ .borderRadius(0)
+ .layoutWeight(1)
+ .width('100%')
+ .height('100%')
+ .backgroundColor(Color.White)
+ .padding(0)
+ .onClick(() => {
+ this.isEdit = true;
+ })
+ }
+ .width('100%')
+ .height('100%')
+ }
+ .width('100%')
+ .margin({
+ bottom: 84
+ })
+ .alignItems(HorizontalAlign.Start)
+ }
+ .padding({
+ top: 8,
+ right: 16,
+ bottom: 16,
+ left: 16
+ })
+ .width('100%')
+ .height('100%')
+
+ .justifyContent(FlexAlign.Start)
+ }
+ .hideTitleBar(true)
+ }
+}
diff --git a/entry/src/main/ets/view/RemoteFileList.ets b/entry/src/main/ets/view/RemoteFileList.ets
new file mode 100644
index 0000000000000000000000000000000000000000..aaa0ba907d8e21050f4063eced0f38367fdb266f
--- /dev/null
+++ b/entry/src/main/ets/view/RemoteFileList.ets
@@ -0,0 +1,319 @@
+/*
+ * 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 { distributedDeviceManager } from "@kit.DistributedServiceKit";
+import { fileIo as fs, fileUri } from '@kit.CoreFileKit';
+import { common } from "@kit.AbilityKit";
+import { BusinessError } from "@kit.BasicServicesKit";
+import CommonUtils from '../utils/CommonUtils';
+import { ProgressDialog } from "../components/ProgressDialog";
+import { ListComp } from "../components/ListComp";
+import { Loading } from "../components/Loading";
+import { EditTitleBar } from "../components/EditTitleBar";
+import { DeleteDialog } from "../components/DeleteDialog";
+import { hilog } from "@kit.PerformanceAnalysisKit";
+
+
+@Builder
+export function RemoteFileListBuild() {
+ RemoteFileList();
+}
+
+@Component
+export struct RemoteFileList {
+ @Consume('pageInfo') pageStack: NavPathStack;
+ @State uiContext: UIContext | undefined = AppStorage.get('uiContext');
+ @State context: Context = this.getUIContext().getHostContext() as common.UIAbilityContext;
+ @State isEdit: boolean = false;
+ @State isShowDialog: boolean = false;
+ @State editTile: Resource = $r('app.string.remote_file');
+ @State remoteFileListArr: string[] = [];
+ @State isRemoteFileChecked: boolean = false;
+ @State selectedValue: string | null = null;
+ @State value: number = 0;
+ @State total: number = 0;
+ @State networkId: string = '';
+ ProgressDialog: CustomDialogController = new CustomDialogController({
+ builder: ProgressDialog({
+ value: this.value,
+ total: this.total,
+ }),
+ alignment: DialogAlignment.Center,
+ autoCancel: false,
+ customStyle: true
+ });
+ DeleteDialogController: CustomDialogController = new CustomDialogController({
+ builder: DeleteDialog({
+ confirmBtn: () => {
+ this.delete();
+ },
+ confirmCancel: () => {
+ this.DeleteDialogController.close();
+ },
+ }),
+ alignment: DialogAlignment.Center,
+ autoCancel: false,
+ customStyle: true
+ });
+ @State pathDir: string = '';
+ @Consume('isDeleteChange') @Watch('handleGetList') isDeleteChange: boolean;
+
+ aboutToAppear() {
+ this.getRemoteFileList();
+ }
+
+ handleGetList() {
+ this.getRemoteFileList();
+ }
+
+ aboutToDisappear(): void {
+ fs.disconnectDfs(this.networkId).then(() => {
+ hilog.info(0x0000, 'RemoteFile', '%{public}s', 'Success to disconnect dfs');
+ }).catch((error: BusinessError) => {
+ let err: BusinessError = error as BusinessError;
+ hilog.error(0x0000, 'RemoteFile', '%{public}s',
+ `Failed to disconnect dfs. Code: ${err.code}, message: ${err.message}`);
+ });
+ }
+
+ // Retrieve the file list in the remote distributed directory
+ async getRemoteFileList() {
+ this.isShowDialog = true;
+ let dmInstance = distributedDeviceManager.createDeviceManager("com.example.crossDeviceFileOperation");
+ try {
+ let deviceInfoList: Array = dmInstance.getAvailableDeviceListSync();
+ if (deviceInfoList && deviceInfoList.length > 0) {
+ this.networkId = deviceInfoList[0].networkId!;
+ // Define callbacks for accessing public file directories
+ let listeners: fs.DfsListeners = {
+ onStatus: (_networkId: string, _status: number): void => {
+ hilog.info(0x0000, 'RemoteFile', '%{public}s', 'Failed to access public directory');
+ }
+ };
+
+ // Start cross device file access
+ await fs.connectDfs(this.networkId, listeners).then(async () => {
+ this.pathDir = this.context.distributedFilesDir;
+ this.remoteFileListArr = await fs.listFile(this.pathDir);
+
+ if (this.remoteFileListArr.length > 0) {
+ this.isShowDialog = false;
+ } else {
+ this.isShowDialog = false;
+ this.isEdit = false;
+ }
+ }).catch((error: BusinessError) => {
+ let err: BusinessError = error as BusinessError;
+ hilog.error(0x0000, 'RemoteFile', '%{public}s',
+ `Failed to connect dfs. Code: ${err.code}, message: ${err.message}`);
+ });
+ } else {
+ CommonUtils.showToast($r('app.string.no_devices_currently_available'), this.uiContext!);
+ this.isShowDialog = false;
+ }
+ } catch (error) {
+ hilog.error(0xFF00, 'error', '%{public}s', 'have errors', `${JSON.stringify(error)}`);
+ }
+ }
+
+ // Copy files
+ copyFile() {
+ if (!this.selectedValue) {
+ CommonUtils.showToast($r('app.string.Please_select_a_file'), this.uiContext!);
+ } else {
+ this.ProgressDialog.open();
+ const srcUri = fileUri.getUriFromPath(this.pathDir + `/${this.selectedValue}`);
+ const destUri = fileUri.getUriFromPath(this.context.filesDir + `/${this.selectedValue}`);
+
+ let progressListener: fs.ProgressListener = (progress: fs.Progress) => {
+ this.value = progress.processedSize;
+ this.total = progress.totalSize;
+ if ((this.value / this.total * 100) > 99) {
+ CommonUtils.showToast($r('app.string.Success_copy'), this.uiContext!);
+ this.ProgressDialog.close();
+ this.pageStack.pop();
+ }
+ };
+ let copyOption: fs.CopyOptions = {
+ "progressListener": progressListener
+ };
+ try {
+ fs.copy(srcUri, destUri, copyOption).then(() => {
+ hilog.info(0x0000, 'RemoteFile', '%{public}s', 'Success to copy.');
+ }).catch((err: BusinessError) => {
+ hilog.error(0x0000, 'RemoteFile', '%{public}s', `Failed to copy. Code: ${err.code}, message: ${err.message}`);
+ });
+ } catch (err) {
+ hilog.error(0x0000, 'RemoteFile', '%{public}s',
+ `Failed to copy.Code try: ${err.code}, message: ${err.message}`);
+
+ }
+ }
+ }
+
+ delete() {
+ if (!this.selectedValue) {
+ CommonUtils.showToast($r('app.string.Please_select_a_file'), this.uiContext!);
+ } else {
+ CommonUtils.delete(this.selectedValue, this.pathDir, this.uiContext!, (result) => {
+ if (result) {
+ this.DeleteDialogController.close();
+ this.isShowDialog = true;
+ this.selectedValue = null;
+ this.getRemoteFileList();
+ }
+ });
+ }
+ }
+
+ build() {
+ NavDestination() {
+ Column({ space: 12 }) {
+ EditTitleBar({
+ isEdit: this.isEdit,
+ editTile: this.editTile,
+ selectedValue: this.selectedValue,
+ fileListArr: this.remoteFileListArr
+ })
+ if (!this.isShowDialog) {
+ Column({ space: 12 }) {
+ Column({ space: 12 }) {
+ if (this.remoteFileListArr.length > 0) {
+ ListComp(
+ {
+ fileListArr: this.remoteFileListArr,
+ isEdit: this.isEdit,
+ selectedValue: this.selectedValue,
+ pathDir: this.pathDir
+ }
+ );
+ } else {
+ Column() {
+ Image($r('app.media.NoInstallationPackage'))
+ .width(120)
+ .height(120)
+ Text($r('app.string.please_create_the_file_first'))
+ .fontSize(14)
+ .fontWeight(400)
+ .fontColor('#434343')
+ }
+ .alignItems(HorizontalAlign.Center)
+ .justifyContent(FlexAlign.Center)
+ .width('100%')
+ .height('100%')
+ }
+
+ }
+ .width('100%')
+ .height('100%')
+ }
+ .width('100%')
+ .margin({
+ bottom: 78
+ })
+ .justifyContent(FlexAlign.SpaceBetween)
+ .alignItems(HorizontalAlign.Start)
+
+ if (this.isEdit) {
+ Row() {
+ Column() {
+ SymbolGlyph($r('sys.symbol.trash'))
+ .fontColor(['rgba(0,0,0,0.9)'])
+ .fontSize(24)
+ .margin({
+ bottom: 6
+ })
+ Text($r('app.string.delete'))
+ .fontSize(12)
+ .fontWeight(400)
+ .fontColor('rgba(0,0,0,0.9)')
+ }
+ .width('40%')
+ .onClick(() => {
+ if (this.selectedValue) {
+ this.DeleteDialogController.open();
+ } else {
+ CommonUtils.showToast($r('app.string.Please_select_a_file'), this.uiContext!);
+ }
+ })
+ .justifyContent(FlexAlign.Center)
+ .alignItems(HorizontalAlign.Center)
+
+ Column() {
+ SymbolGlyph($r('sys.symbol.plus_square_on_square'))
+ .fontColor(['rgba(0,0,0,0.9)'])
+ .fontSize(24)
+ .margin({
+ bottom: 6
+ })
+ Text($r('app.string.copy'))
+ .fontSize(12)
+ .fontWeight(400)
+ .fontColor('rgba(0,0,0,0.9)')
+ }
+ .width('40%')
+ .justifyContent(FlexAlign.Center)
+ .alignItems(HorizontalAlign.Center)
+ .onClick(() => {
+ this.copyFile();
+ })
+ }
+ .width('100%')
+ .height(48)
+ .margin({
+ top: -94
+ })
+ .justifyContent(FlexAlign.SpaceAround)
+ .backgroundColor('rgb(241,243,245)')
+ } else {
+ if (this.remoteFileListArr.length === 0) {
+ Button($r('app.string.return_to_the_previous_page'), { buttonStyle: ButtonStyleMode.NORMAL })
+ .width('100%')
+ .height(40)
+ .fontColor('#0A59F7')
+ .margin({
+ bottom: 16,
+ top: -94
+ })
+ .onClick(async () => {
+ this.pageStack.pop();
+ })
+ } else {
+ Row() {
+ }.width('100%')
+ .height(40)
+ }
+ }
+ } else {
+ Loading();
+ }
+ }
+ .backgroundColor('rgb(241,243,245)')
+ .padding({
+ top: 8,
+ right: 16,
+ bottom: 16,
+ left: 16
+ })
+ .width('100%')
+ .height('100%')
+ .justifyContent(FlexAlign.SpaceBetween)
+
+ }
+ .mode(NavDestinationMode.DIALOG)
+ .systemTransition(NavigationSystemTransitionType.SLIDE_RIGHT)
+ .title(this.isEdit ? $r('app.string.edit') : $r('app.string.remote_file'))
+ .hideTitleBar(true)
+ }
+}
\ No newline at end of file
diff --git a/entry/src/main/module.json5 b/entry/src/main/module.json5
new file mode 100644
index 0000000000000000000000000000000000000000..80ba5343da84e59f0189680c06b320d91504d0c0
--- /dev/null
+++ b/entry/src/main/module.json5
@@ -0,0 +1,63 @@
+{
+ "module": {
+ "name": "entry",
+ "type": "entry",
+ "description": "$string:module_desc",
+ "mainElement": "EntryAbility",
+ "deviceTypes": [
+ "phone"
+ ],
+ "deliveryWithInstall": true,
+ "installationFree": false,
+ "pages": "$profile:main_pages",
+ "routerMap": "$profile:route_map",
+ "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"
+ }
+ ],
+ }
+ ],
+ "requestPermissions": [
+ {
+ "name": "ohos.permission.DISTRIBUTED_DATASYNC",
+ "reason": "$string:distributed_data_sync_reason",
+ "usedScene": {
+ "abilities": [
+ "EntryAbility"
+ ],
+ "when": "inuse"
+ }
+ }
+ ]
+ }
+}
\ 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..2a605b6136418135a4907c55569cccf41d43ecf8
--- /dev/null
+++ b/entry/src/main/resources/base/element/string.json
@@ -0,0 +1,180 @@
+{
+ "string": [
+ {
+ "name": "module_desc",
+ "value": "module description"
+ },
+ {
+ "name": "EntryAbility_desc",
+ "value": "description"
+ },
+ {
+ "name": "EntryAbility_label",
+ "value": "Cross device file operation"
+ },
+ {
+ "name": "create_a_file",
+ "value": "create a file"
+ },
+ {
+ "name": "display_local_file_list",
+ "value": "Display local file list"
+ },
+ {
+ "name": "display_remote_file_list",
+ "value": "Display remote file list"
+ },
+ {
+ "name": "please_enter_a_file_name",
+ "value": "Please enter a file name"
+ },
+ {
+ "name": "please_enter_the_file_content",
+ "value": "Please enter the file content"
+ },
+ {
+ "name": "local_file",
+ "value": "Local file"
+ },
+ {
+ "name": "preview_area",
+ "value": "Preview Area"
+ },
+ {
+ "name": "modify_file",
+ "value": "Modify file"
+ },
+ {
+ "name": "remote_file",
+ "value": "Remote file"
+ },
+ {
+ "name": "copy_files",
+ "value": "Copy files"
+ },
+ {
+ "name": "file_preview",
+ "value": "file preview"
+ },
+ {
+ "name": "Save_modifications",
+ "value": "Save modifications"
+ },
+ {
+ "name": "Success_copy",
+ "value": "Success copy"
+ },
+ {
+ "name": "Please_select_a_file",
+ "value": "Please select a file"
+ },
+ {
+ "name": "successfully_saved",
+ "value": "Successfully saved"
+ },
+ {
+ "name": "distributed_data_sync_reason",
+ "value": "Allow data exchange between different devices"
+ },
+ {
+ "name": "authorization_successful",
+ "value": "Authorization successful"
+ },
+ {
+ "name": "reauthorization",
+ "value": "Authorization failed, please reauthorize"
+ },
+ {
+ "name": "created_successfully",
+ "value": "Created successfully"
+ },
+ {
+ "name": "file_name_and_file_content_cannot_be_empty",
+ "value": "The file name and file content cannot be empty"
+ },
+ {
+ "name": "no_data_available_at_the_moment",
+ "value": "No data available at the moment"
+ },
+ {
+ "name": "no_devices_currently_available",
+ "value": "No devices currently available"
+ },
+ {
+ "name": "clean",
+ "value": "clean"
+ },
+ {
+ "name": "sure",
+ "value": "sure"
+ },
+ {
+ "name": "view_file",
+ "value": "view file"
+ },
+ {
+ "name": "return_to_the_previous_page",
+ "value": "Return to the previous page"
+ },
+ {
+ "name": "please_copy_the_file_first",
+ "value": "Please copy the file first"
+ },
+ {
+ "name": "file_list",
+ "value": "file list"
+ },
+ {
+ "name": "edit",
+ "value": "edit"
+ },
+ {
+ "name": "delete",
+ "value": "delete"
+ },
+ {
+ "name": "copy",
+ "value": "copy"
+ },
+ {
+ "name": "delete_successfully",
+ "value": "Delete successfully"
+ },
+ {
+ "name": "delete_file",
+ "value": "delete file"
+ },
+ {
+ "name": "confirm_to_delete_the_file",
+ "value": "Confirm to delete the file"
+ },
+ {
+ "name": "cancel",
+ "value": "cancel"
+ },
+ {
+ "name": "confirm",
+ "value": "confirm"
+ },
+ {
+ "name": "file_copying",
+ "value": "File copying"
+ },
+ {
+ "name": "loading",
+ "value": "loading..."
+ },
+ {
+ "name": "do_you_want_to_save_it",
+ "value": "Do you want to save it"
+ },
+ {
+ "name": "confirm_to_save_the_file",
+ "value": "Confirm to save the file"
+ },
+ {
+ "name": "please_create_the_file_first",
+ "value": "Please create the file first"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/entry/src/main/resources/base/media/NoInstallationPackage.svg b/entry/src/main/resources/base/media/NoInstallationPackage.svg
new file mode 100644
index 0000000000000000000000000000000000000000..acf743d60d8097593c987f878208dc60886e0e7a
--- /dev/null
+++ b/entry/src/main/resources/base/media/NoInstallationPackage.svg
@@ -0,0 +1,13 @@
+
+
\ 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/plus_square_on_square_fill.svg b/entry/src/main/resources/base/media/plus_square_on_square_fill.svg
new file mode 100644
index 0000000000000000000000000000000000000000..aa70585336a0aab86901e97fecda6b1fd97ee375
--- /dev/null
+++ b/entry/src/main/resources/base/media/plus_square_on_square_fill.svg
@@ -0,0 +1,19 @@
+
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/trash.svg b/entry/src/main/resources/base/media/trash.svg
new file mode 100644
index 0000000000000000000000000000000000000000..056b47d17834a48cb79cb94d7ceec07dca642c2a
--- /dev/null
+++ b/entry/src/main/resources/base/media/trash.svg
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
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/base/profile/route_map.json b/entry/src/main/resources/base/profile/route_map.json
new file mode 100644
index 0000000000000000000000000000000000000000..5f9fbe0ad463b58ef566bb0562fecbbf1d0ff41f
--- /dev/null
+++ b/entry/src/main/resources/base/profile/route_map.json
@@ -0,0 +1,28 @@
+{
+ "routerMap": [
+ {
+ "name": "LocalFileList",
+ "pageSourceFile": "src/main/ets/view/LocalFileList.ets",
+ "buildFunction": "LocalFileListBuild",
+ "data": {
+ "description": "this is LocalFileList"
+ }
+ },
+ {
+ "name": "RemoteFileList",
+ "pageSourceFile": "src/main/ets/view/RemoteFileList.ets",
+ "buildFunction": "RemoteFileListBuild",
+ "data": {
+ "description": "this is RemoteFileList"
+ }
+ },
+ {
+ "name": "Preview",
+ "pageSourceFile": "src/main/ets/view/Preview.ets",
+ "buildFunction": "PreviewBuild",
+ "data": {
+ "description": "this is Preview"
+ }
+ }
+ ]
+}
\ No newline at end of file
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..efbc58f76034085ff3f1309998dc42355d632f6c
--- /dev/null
+++ b/entry/src/main/resources/en_US/element/string.json
@@ -0,0 +1,180 @@
+{
+ "string": [
+ {
+ "name": "module_desc",
+ "value": "Module description"
+ },
+ {
+ "name": "EntryAbility_desc",
+ "value": "EntryAbility description"
+ },
+ {
+ "name": "EntryAbility_label",
+ "value": "Cross device file operation"
+ },
+ {
+ "name": "create_a_file",
+ "value": "create a file"
+ },
+ {
+ "name": "display_local_file_list",
+ "value": "Display local file list"
+ },
+ {
+ "name": "display_remote_file_list",
+ "value": "Display remote file list"
+ },
+ {
+ "name": "please_enter_a_file_name",
+ "value": "Please enter a file name"
+ },
+ {
+ "name": "please_enter_the_file_content",
+ "value": "Please enter the file content"
+ },
+ {
+ "name": "local_file",
+ "value": "Local file list"
+ },
+ {
+ "name": "preview_area",
+ "value": "Preview Area"
+ },
+ {
+ "name": "modify_file",
+ "value": "Modify file"
+ },
+ {
+ "name": "remote_file",
+ "value": "Remote file list"
+ },
+ {
+ "name": "copy_files",
+ "value": "Copy files"
+ },
+ {
+ "name": "file_preview",
+ "value": "file preview"
+ },
+ {
+ "name": "Save_modifications",
+ "value": "Save modifications"
+ },
+ {
+ "name": "Success_copy",
+ "value": "Success copy"
+ },
+ {
+ "name": "Please_select_a_file",
+ "value": "Please select a file"
+ },
+ {
+ "name": "successfully_saved",
+ "value": "Successfully saved"
+ },
+ {
+ "name": "distributed_data_sync_reason",
+ "value": "Allow data exchange between different devices"
+ },
+ {
+ "name": "authorization_successful",
+ "value": "Authorization successful"
+ },
+ {
+ "name": "reauthorization",
+ "value": "Authorization failed, please reauthorize"
+ },
+ {
+ "name": "created_successfully",
+ "value": "Created successfully"
+ },
+ {
+ "name": "file_name_and_file_content_cannot_be_empty",
+ "value": "The file name and file content cannot be empty"
+ },
+ {
+ "name": "no_data_available_at_the_moment",
+ "value": "No data available at the moment"
+ },
+ {
+ "name": "no_devices_currently_available",
+ "value": "No devices currently available"
+ },
+ {
+ "name": "clean",
+ "value": "clean"
+ },
+ {
+ "name": "sure",
+ "value": "sure"
+ },
+ {
+ "name": "view_file",
+ "value": "view file"
+ },
+ {
+ "name": "return_to_the_previous_page",
+ "value": "Return to the previous page"
+ },
+ {
+ "name": "please_copy_the_file_first",
+ "value": "Please copy the file first"
+ },
+ {
+ "name": "file_list",
+ "value": "file list"
+ },
+ {
+ "name": "edit",
+ "value": "edit"
+ },
+ {
+ "name": "delete",
+ "value": "delete"
+ },
+ {
+ "name": "copy",
+ "value": "copy"
+ },
+ {
+ "name": "delete_successfully",
+ "value": "Delete successfully"
+ },
+ {
+ "name": "delete_file",
+ "value": "delete file"
+ },
+ {
+ "name": "confirm_to_delete_the_file",
+ "value": "Confirm to delete the file"
+ },
+ {
+ "name": "cancel",
+ "value": "cancel"
+ },
+ {
+ "name": "confirm",
+ "value": "confirm"
+ },
+ {
+ "name": "file_copying",
+ "value": "File copying"
+ },
+ {
+ "name": "loading",
+ "value": "loading..."
+ },
+ {
+ "name": "do_you_want_to_save_it",
+ "value": "Do you want to save it"
+ },
+ {
+ "name": "confirm_to_save_the_file",
+ "value": "Confirm to save the file"
+ },
+ {
+ "name": "please_create_the_file_first",
+ "value": "Please create the file first"
+ }
+ ]
+}
\ No newline at end of file
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..43e7b4b96e1d5a366bf76a40c6a2428b5b7ec256
--- /dev/null
+++ b/entry/src/main/resources/zh_CN/element/string.json
@@ -0,0 +1,180 @@
+{
+ "string": [
+ {
+ "name": "module_desc",
+ "value": "模板描述"
+ },
+ {
+ "name": "EntryAbility_desc",
+ "value": "EntryAbility描述"
+ },
+ {
+ "name": "EntryAbility_label",
+ "value": "跨设备文件操作"
+ },
+ {
+ "name": "create_a_file",
+ "value": "创建文件"
+ },
+ {
+ "name": "display_local_file_list",
+ "value": "显示本地文件列表"
+ },
+ {
+ "name": "display_remote_file_list",
+ "value": "显示远端文件列表"
+ },
+ {
+ "name": "please_enter_a_file_name",
+ "value": "请输入文件名"
+ },
+ {
+ "name": "please_enter_the_file_content",
+ "value": "请输入文件内容"
+ },
+ {
+ "name": "local_file",
+ "value": "本地文件"
+ },
+ {
+ "name": "preview_area",
+ "value": "预览文件"
+ },
+ {
+ "name": "modify_file",
+ "value": "修改文件"
+ },
+ {
+ "name": "remote_file",
+ "value": "远端文件"
+ },
+ {
+ "name": "copy_files",
+ "value": "拷贝文件"
+ },
+ {
+ "name": "file_preview",
+ "value": "文件预览"
+ },
+ {
+ "name": "Save_modifications",
+ "value": "保存修改"
+ },
+ {
+ "name": "Success_copy",
+ "value": "拷贝成功"
+ },
+ {
+ "name": "Please_select_a_file",
+ "value": "请选择文件"
+ },
+ {
+ "name": "successfully_saved",
+ "value": "保存成功"
+ },
+ {
+ "name": "distributed_data_sync_reason",
+ "value": "允许不同设备间的数据交换"
+ },
+ {
+ "name": "authorization_successful",
+ "value": "授权成功"
+ },
+ {
+ "name": "reauthorization",
+ "value": "授权失败,请重新授权"
+ },
+ {
+ "name": "created_successfully",
+ "value": "创建成功"
+ },
+ {
+ "name": "file_name_and_file_content_cannot_be_empty",
+ "value": "文件名和文件内容不能为空"
+ },
+ {
+ "name": "no_data_available_at_the_moment",
+ "value": "暂无数据"
+ },
+ {
+ "name": "no_devices_currently_available",
+ "value": "暂无设备"
+ },
+ {
+ "name": "clean",
+ "value": "清除"
+ },
+ {
+ "name": "sure",
+ "value": "确定"
+ },
+ {
+ "name": "view_file",
+ "value": "查看文件"
+ },
+ {
+ "name": "return_to_the_previous_page",
+ "value": "返回上一页"
+ },
+ {
+ "name": "please_copy_the_file_first",
+ "value": "请先复制文件"
+ },
+ {
+ "name": "file_list",
+ "value": "文件列表"
+ },
+ {
+ "name": "edit",
+ "value": "编辑"
+ },
+ {
+ "name": "delete",
+ "value": "删除"
+ },
+ {
+ "name": "copy",
+ "value": "复制"
+ },
+ {
+ "name": "delete_successfully",
+ "value": "删除成功"
+ },
+ {
+ "name": "delete_file",
+ "value": "删除文件"
+ },
+ {
+ "name": "confirm_to_delete_the_file",
+ "value": "确定删除该文件"
+ },
+ {
+ "name": "cancel",
+ "value": "取消"
+ },
+ {
+ "name": "confirm",
+ "value": "确定"
+ },
+ {
+ "name": "file_copying",
+ "value": "文件复制"
+ },
+ {
+ "name": "loading",
+ "value": "正在加载..."
+ },
+ {
+ "name": "do_you_want_to_save_it",
+ "value": "是否保存"
+ },
+ {
+ "name": "confirm_to_save_the_file",
+ "value": "确定保存该文件"
+ },
+ {
+ "name": "please_create_the_file_first",
+ "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..c63e910373e5ead86612270e605a391acdc32ec9
--- /dev/null
+++ b/hvigor/hvigor-config.json5
@@ -0,0 +1,23 @@
+{
+ "modelVersion": "5.1.1",
+ "dependencies": {
+ },
+ "execution": {
+ // "analyze": "normal", /* Define the build analyze mode. Value: [ "normal" | "advanced" | 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..052cc24d6e7b3f754ab5557652fd9db52c4c2549
--- /dev/null
+++ b/oh-package.json5
@@ -0,0 +1,10 @@
+{
+ "modelVersion": "5.1.1",
+ "description": "Please describe the basic information.",
+ "dependencies": {
+ },
+ "devDependencies": {
+ "@ohos/hypium": "1.0.21",
+ "@ohos/hamock": "1.0.0"
+ }
+}
diff --git a/screenshots/device/preview.en.gif b/screenshots/device/preview.en.gif
new file mode 100644
index 0000000000000000000000000000000000000000..41e777fcfd0500da6f6962d093949cb6f72a58dc
Binary files /dev/null and b/screenshots/device/preview.en.gif differ
diff --git a/screenshots/device/preview.gif b/screenshots/device/preview.gif
new file mode 100644
index 0000000000000000000000000000000000000000..b7f7adbfebf0cef3575614098859d5fcef7894b4
Binary files /dev/null and b/screenshots/device/preview.gif differ