!32 更新相机应用代码

Merge pull request !32 from Jasper Zhao/master
This commit is contained in:
openharmony_ci
2022-03-11 07:38:16 +00:00
committed by Gitee
314 changed files with 11169 additions and 2946 deletions
+22 -2
View File
@@ -1,2 +1,22 @@
.gitee
local.properties
*.iml
.gradle
/local.properties
/.idea/caches
/.idea/previewer
/.idea/libraries
/.idea/modules.xml
/.idea/workspace.xml
/.idea/navEditor.xml
/.idea/assetWizardSettings.xml
.DS_Store
/build
/captures
.externalNativeBuild
/entry/.preview
.cxx
/node_modules
/product/phone/build
/product/tablet/build
/product/wearable/build
/product/phone/.preview
/product/tablet/.preview
-37
View File
@@ -1,37 +0,0 @@
# Copyright (c) 2021 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("//build/ohos.gni")
ohos_hap("ark_camera") {
hap_profile = "entry/src/main/config.json"
deps = [
":camera_js_assets",
":camera_resources",
]
js2abc = false
shared_libraries = [ "//third_party/libpng:libpng" ]
certificate_profile = "signature/camera.p7b"
hap_name = "ark_camera"
part_name = "prebuilt_hap"
subsystem_name = "applications"
}
ohos_js_assets("camera_js_assets") {
source_dir = "entry/src/main/js/default"
}
ohos_resources("camera_resources") {
sources = [ "entry/src/main/resources" ]
hap_profile = "entry/src/main/config.json"
}
-176
View File
@@ -1,176 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
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:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) 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
(d) 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
-64
View File
@@ -1,64 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Copyright (c) 2021 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.
This is the configuration file template for OpenHarmony OSS Audit Tool, please copy it to your project root dir and modify it refer to OpenHarmony/tools_oat/README.
All configurations in this file will be merged to OAT-Default.xml, if you have any questions or concerns, please create issue in OpenHarmony/tools_oat and @jalenchen or chenyaxun.
licensefile:
1.If the project don't have "LICENSE" in root dir, please define all the license files in this project in , OAT will check license files according to this rule.
policylist:
1. policy: If the OAT-Default.xml policies do not meet your requirements, please add policies here.
2. policyitem: The fields type, name, path, desc is required, and the fields rule, group, filefilter is optional,the default value is:
<policyitem type="" name="" path="" desc="" rule="may" group="defaultGroup" filefilter="defaultPolicyFilter"/>
3. policyitem type:
"compatibility" is used to check license compatibility in the specified path;
"license" is used to check source license header in the specified path;
"copyright" is used to check source copyright header in the specified path;
"import" is used to check source dependency in the specified path, such as import ... ,include ...
"filetype" is used to check file type in the specified path, supported file types: archive, binary
"filename" is used to check whether the specified file exists in the specified path(projectroot means the root dir of the project), supported file names: LICENSE, README, README.OpenSource
4. policyitem name: This field is used for define the license, copyright, "*" means match all, the "!" prefix means could not match this value. For example, "!GPL" means can not use GPL license.
5. policyitem path: This field is used for define the source file scope to apply this policyitem, the "!" prefix means exclude the files. For example, "!.*/lib/.*" means files in lib dir will be exclude while process this policyitem.
6. policyitem rule and group: These two fields are used together to merge policy results. "may" policyitems in the same group means any one in this group passed, the result will be passed.
7. policyitem filefilter: Used to bind filefilter which define filter rules.
7. policyitem desc: Used to describe the reason of this policy item, committers will check this while merging the code.
8. filefilter: Filter rules, the type filename is used to filter file name, the type filepath is used to filter file path.
Note:If the text contains special characters, please escape them according to the following rules:
" == &gt;
& == &gt;
' == &gt;
< == &gt;
> == &gt;
-->
<configuration>
<oatconfig>
<policylist>
<policy name="projectPolicy" desc="">
<policyitem type="copyright" name="Copyright 2015 the original author or authors." path="gradlew" rule="may" group="defaultGroup" filefilter="copyrightPolicyFilter" desc="file generated by development tool"/>
<policyitem type="copyright" name="Copyright 2015 the original author or authors." path="gradlew.bat" rule="may" group="defaultGroup" filefilter="copyrightPolicyFilter" desc="file generated by development tool"/>
</policy>
</policylist>
<filefilterlist>
<filefilter name="binaryFileTypePolicyFilter" desc="Filters for binary file policies">
<filteritem type="filepath" name="entry/src/main/resources/base/media/.*.png" desc="self developed image"/>
<filteritem type="filepath" name="entry/src/main/js/default/common/media/.*.svg" desc="self developed image"/>
<filteritem type="filepath" name="figures/.*.png" desc="self developed image"/>
</filefilter>
</filefilterlist>
</oatconfig>
</configuration>
-54
View File
@@ -1,54 +0,0 @@
# Camera<a name="ZH-CN_TOPIC_0000001103554544"></a>
- [Introduction](#section11660541593)
- [Architecture](#section78574815486)
- [Directory Structure](#section161941989596)
- [Repositories Involved](#section1371113476307)
## Introduction<a name="section11660541593"></a>
The Camera app is a system app pre-installed in the OpenHarmony standard system. It enables users to shoot photos with the local or a remote device, preview the shooting effect, view photo thumbnails, and open the camera album.
### Architecture<a name="section78574815486"></a>
![](figures/camera.png)
## Directory Structure<a name="section161941989596"></a>
```
/applications/standard/camera/
├── figures # Architecture figures
├── entry # Camera main ability
│ └── src
│ └── main
│ ├── config.json # App configuration file
│ └── js # JavaScript code
│ └──default
│ ├──common # Public resources
│ ├──component # Custom components
│ └──PreviewDialog # Dialog component for displaying the remote device list
│ ├──media # Media resources
│ └──utils # Public utility classes
│ ├──i18n # Character strings for globalization
│ ├──model # Models
│ ├──KvStoreModel # Distributed data model
│ ├──PreviewModel # Model for the camera home screen
│ └──RemoteDeviceModel # Model for the remote device list
│ ├──pages # Pages
│ ├──DistributedView # Page for distributed multi-device collaboration
│ └──PreviewView # Page for the camera home screen
│ ├──presenter # Presenters
│ ├──DistributedPresenter # Encapsulates the logic for interaction between the distributed multi-device collaboration page and data.
│ └──DreviewPresenter # Encapsulates the logic for interaction between the camera home screen and data.
│ └──app.js # File used for global JavaScript logic and app lifecycle management
│ └── resources # Resource files
├── signature # Certificate file
├── LICENSE # License file
```
## Repositories Involved<a name="section1371113476307"></a>
System apps
**applications\_camera**
+356 -47
View File
@@ -1,54 +1,363 @@
# 相机<a name="ZH-CN_TOPIC_0000001103554544"></a>
- [简介](#section11660541593)
- [架构图](#section78574815486)
- [目录](#section161941989596)
- [相关仓](#section1371113476307)
## 简介<a name="section11660541593"></a>
相机应用是OpenHarmony标准系统中预置的系统应用,为用户提供基础的相机拍摄功能,包括预览、拍照、缩略图显示、跳转相册、分布式多端协同。
### 架构图<a name="section78574815486"></a>
![](figures/camera.png)
## 目录<a name="section161941989596"></a>
# Camera 源码开发说明
## 1. 项目介绍
相机应用是OpenHarmony标准系统中预置的系统应用,为用户提供基础的相机拍摄功能,包括预览、拍照、摄像、缩略图显示、跳转相册、多机位协同。
Camera 采用纯 arkui-ts 语言开发,开发过程中不涉及任何 Java 部分的代码。
## 2. 工程结构
### 目录结构
```
/applications/standard/camera/
├── figures # 架构图目录
├── entry # 相机主Ability
/applications
├── common # 公共模块目录
│ └── src
│ └── main
│ ├── config.json # 应用配置文件
└── js # js代码目录
└──default
├──common # 公共资源文件目录
├──component # 自定义组件目录
└──DeviceListDialog # 分布式设备列表弹框组件
├──media # 图片和音频资源目录
└──utils # 公共工具类目录
│ ├──i18n # 全球化字符串资源目录
├──model # Model层
├──KvStoreModel # 分布式数据Model
├──PreviewModel # 相机主界面Model
└──RemoteDeviceModel # 分布式设备列表Model
├──pages # View层
├──DistributedView # 分布式协同界面
──PreviewView # 相机主界面
├──presenter # Presenter层
├──DistributedPresenter # 分布式协同界面与数据的交互逻辑封装
└──PreviewPresenter # 相机主界面与数据的交互逻辑封装
└──app.js # 文件用于全局JavaScript逻辑和应用生命周期管理
└── resources # 资源文件目录
├── signature # 证书文件目录
├── LICENSE # 许可文件
│ ├── ets # ets代码目录
├── default
├── Camera # Camera组件管理目录
├── model # Model层代码目录
├── redux # 应用的状态容器
├── utils # 工具类代码目录
├── resources # 资源目录
├── config.json # 项目配置信息
├── feature # feature层模块目录
└── featurecommon # 主Camera模块目录
└── src
└── main
├── ets # ets代码目录
├── com
├── ohos # ets代码目录
── featurecommon # ets代码目录
├── animate # 动画目录
├── cameraswitcher # 前后置切换目录
├── customDialog # 弹窗目录
├── featureservice # feature服务
├── shutterbutton # 拍照目录
├── thumbnail # 缩略图目录
├── Mode.ets # 模式切换mode
│ ├── resources # 资源目录
│ ├── config.json # 项目配置信息
│ └── photo # 拍照模块目录
│ └── src
│ └── main
│ ├── ets # ets代码目录
│ ├── com
│ ├── ohos
│ ├── photo # 拍照ets代码目录
│ ├── resources # 资源目录
│ ├── config.json # 项目配置信息
│ └── video # 摄像模块目录
│ └── src
│ └── main
│ ├── ets # ets代码目录
│ ├── com
│ ├── ohos
│ ├── video # 摄像ets代码目录
│ ├── resources # 资源目录
│ ├── config.json # 项目配置信息
├── product # 产品层模块目录
│ └── phone # phone模式模块目录
│ └── src
│ └── main
│ ├── ets # ets代码目录
│ ├── MainAbility
│ ├── common # ets代码目录
│ ├── pages # 业务特性的View层目录
│ ├── res # 业务特性涉及的图片目录
│ ├── workers # worker多线程处理
│ ├── resources # 资源目录
│ ├── config.json # 项目配置信息
│ └── tablet # tablet模式模块目录
│ └── src
│ └── main
│ ├── ets # ets代码目录
│ ├── MainAbility
│ ├── common # ets代码目录
│ ├── pages # 业务特性的View层目录
│ ├── res # 业务特性涉及的图片目录
│ ├── workers # worker多线程处理
│ ├── resources # 资源目录
│ ├── config.json # 项目配置信息
```
### 整体架构
![](./figures/camera-en.png)
Camera的Common层以Redux框架和Camera Worker为基础,向上扩展出Feature和Product层。
应用整体采用了多模块的设计方式,每个模块都遵循上述架构原则。
各层的作用分别如下:
- Product层:区分不同产品,不同屏幕的各形态,含有应用窗口、个性化业务,组件的配置以及个性化资源包。
- Feature层:抽象的公共特性组件集合,每个特性解耦独立可打包为har,可以被每个业务态所引用。
- Common层:负责数据服务、UI组件、工具组、数据持久层、动效层、外部交互层等部件内公共能力,每个应用形态都必须要依赖的模块。
应用各层中重要类及其功能如下表所示
|模块|层级|模块名|作用|
|-|-|-|-|
|camera|Product层|Phone|手机模块。|
|camera|Product层|Tablet|平板模块。|
|camera|Product层|Watch|智能穿戴模块。|
|camera|Product层|PC|电脑模块。|
|camera|Feature层|Photo mode|拍照模式。|
|camera|Feature层|Video mode|录像模式。|
|camera|Feature层|分布式 mode|分布式模式。|
|camera|Common层|Common Function|公共能力模块。|
|camera|Common层|Common UI Components|公共UI组件。|
|camera|Common层|Redux frame|Redux框架。|
|camera|Common层|Utils|工具类合集。|
|camera|Common层|AsyncManager|异步通信管理。|
|camera|Common层|Camera worker|相机后台线程。|
## 3 典型接口的使用
1. 获取Camera能力
```ets
import camera from '@ohos.multimedia.camera'
getCameras() {
cameras = camera.getCameraManager(null).getCameras()
if (cameras) {
console.info(`getCameras success.`)
for (let i = 0; i < cameras.length; i++) {
console.info(`--------------Camera Info-------------`)
console.info(`camera_id: ${cameras[i].cameraId}`)
console.info(`cameraPosition: ${cameras[i].cameraPosition}`)
console.info(`cameraType: ${cameras[i].cameraType}`)
console.info(`connectionType: ${cameras[i].cameraType}`)
}
} else {
console.info(`getCameras failed.`)
}
}
```
## 相关仓<a name="section1371113476307"></a>
2. 启动相机
```ets
startPreview() {
cameraInput = await cameraManager.createCameraInput(cameraId)
captureSession = await camera.createCaptureSession(null)
if (captureSession) {
console.info(`createCaptureSession success.`)
this.previewOutput = await camera.createPreviewOutput(this.previewId)
await this.captureSession.beginConfig()
await this.captureSession.addInput(this.cameraInput)
await this.captureSession.addOutput(this.previewOutput)
console.info(`startPreview success.`)
} else {
console.info(`createCaptureSession failed.`)
}
```
3. 拍照
```ets
import image from '@ohos.multimedia.image'
takePicture() {
let mReceiver = image.createImageReceiver(imageWidth, imageHeight, 4, 8)
let mSurfaceId = await mReceiver.getReceivingSurfaceId()
await camera.createPhotoOutput(mSurfaceId).then((picture) => {
console.info(`createPhotoOutput called: ${picture}`)
})
}
```
4. 切换镜头
```ets
import camera from '@ohos.multimedia.camera'
switchCamera(cameraId) {
await captureSession.stop()
await cameraInput.release()
await captureSession.release()
cameraInput = await cameraManager.createCameraInput(cameraId)
captureSession = await camera.createCaptureSession(null)
if (captureSession) {
console.info(`createCaptureSession success.`)
this.previewOutput = await camera.createPreviewOutput(this.previewId)
await this.captureSession.beginConfig()
await this.captureSession.addInput(this.cameraInput)
await this.captureSession.addOutput(this.previewOutput)
console.info(`startPreview success.`)
} else {
console.info(`createCaptureSession failed.`)
}
```
## 4. 签名打包
### 签名
#### 签名文件的获取
1. 拷贝 OpenHarmony 标准版的 prebuilts\signcenter 目录到操作目录。
2. 拷贝 Camera 工程的 signature\Camera.p7b 到该目录下。
备注:如果需要生成并使用自己的签名文件可参考https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/configuring-openharmony-app-signature.md
#### 签名文件的配置
打开项目工程,选择 File → Project Structure
![](./figures/signature_1.png)
选择 Modules → Signing Configs,将对应的签名文件配置如下,完成后点击Apply,再点击OK。
密码为生成签名文件时的密码,如果使用默认的签名文件,则使用默认密码123456。
![](./figures/signature_2.png)
配置完成后,对应的build.gradle文件中会出现如下内容
![](./figures/signature_3.png)
### 打包
DevEco Studio 支持 debug 与 release 两种打包类型。可以在 OhosBuild Variants 窗口中进行切换。
![](./figures/ds_ohosbuild_variants.png)
#### release打包
1. 代码准备完成后,在 OhosBuild Variants 窗口的 Selected Variant 中选择 release
![](./figures/ds_ohosbuild_variants_release.png)
2. 选择Build → Build Haps(s)/APP(s) → Build Hap(s)
![](./figures/ds_build_haps.png)
3. 编译完成后,hap包会生成在工程目录下的 `\build\outputs\hap\release\`路径下(如果没有配置签名,则只会生成未签名的hap包)
![](./figures/ds_ohosbuild_output_dir_release.png)
## 5. 安装、运行、调试
### 应用安装
配置 hdc
进入SDK目录中的toolchains文件夹下,获取文件路径:
![](./figures/sdk_catalogue.png)
并将此路径配置到环境变量中:
![](./figures/sdk_environment_variable.png)
连接开发板,打开一个新的cmd命令窗口,执行`hdc list targets`,弹出窗口如下:
![](./figures/cmd1.png)
等待一段时间后,窗口出现如下打印,可回到输入 hdc list targets 的命令窗口继续操作:
![](./figures/cmd2.png)
再次输入hdc list targets,出现如下结果,说明hdc连接成功
![](./figures/cmd3.png)
获取 root 权限与读写权限:
```
hdc target mount
```
***T.B.D smode 不执行的情况下,hdc target mount 能否正常执行?***
将签名好的 hap 包放入设备的 `/system/app` 目录下,并修改hap包的权限。发送文件命令如下:
```
hdc file send 本地路径 /system/app/hap包名称
```
例:将当前本地目录的 `Camera.hap` 文件放入到 `system/app/Camera.hap` 文件中。
```
hdc file send Camera.hap /system/app/Camera.hap
```
> 注意,如果设备不存在 `/system/app` 目录,则需要手动创建该目录并修改权限。
> ```
> hdc shell
> cd system
> mkdir app
> chmod 777 app
> ```
> `/system/app` 目录放置系统应用,例如:CameraSystemUISettings 等。
>
> 但hap包需要在该目录下手动设置权限
> ```
> chmod 666 hap包名
> ```
> 此目录应用不用手动安装,系统自动拉起。
### 应用运行
Camera 属于系统应用,在将签名的 hap 包放入 `/system/app` 目录后,重启系统,应用会自动拉起。
```
hdc shell
reboot
(不可以直接执行hdc reboot,命令是无效的)
```
***T.B.D 直接执行 `reboot`,还是执行`hdc shell reboot`***
> 注意,如果设备之前安装过系统应用,则需要执行如下两条命令清除设备中存储的应用信息才能够在设备重启的时候将我们装入设备的新 hap 包正常拉起。
> ```
> hdc shell rm -rf /data/accounts/
> hdc shell rm -rf /data/misc_de/0/mdds/0/default/bundle_manager_service
> ```
### 应用调试
#### log打印
- 在程序中添加 log
```JS
console.info("Camera log info");
```
可以在DevEco Studio中查看log
![](./figures/ds_hilog_window.png)
#### log获取及过滤
- log获取
将log输出至文件
```
hdc shell hilog > 输出文件名称
```
例:
在真实环境查看log,将全log输出到当前目录的hilog.log文件中
```
hdc shell hilog > hilog.log
```
- log过滤
在命令行窗口中过滤log
```
hilog | grep 过滤信息
```
例:过滤包含信息 Label 的 hilog
```
hilog | grep Label
```
## 6. 贡献代码
### Fork 代码仓库
1. 在码云上打开 Camera 代码仓库([仓库地址](https://gitee.com/openharmony/applications_camera))。
2. 点击仓库右上角的 Forked 按钮
![](./figures/commit_source_fork_button.png)
3. 在弹出的画面中,选择将仓库 fork 到哪里,点击确认。
![](./figures/commit_source_fork_confirm.png)
4. Fork 成功之后,会在自己的账号下看见 fork 的代码仓库。
![](./figures/commit_source_forked_repo.png)
### 提交代码
1. 访问我们自己在码云账号上 fork 的代码仓库,点击“克隆/下载”按钮,选择 SSH,点击“复制”按钮。
![](./figures/commit_source_clone_page.png)
2. 在本地新建 Camera 目录,在 Camera 目录中执行如下命令
```
git clone 步骤1中复制的地址
```
3. 修改代码。
> 将代码引入工程,以及编译工程等相关内容请参见 **3. 代码使用** 部分的相关内容。
4. 提交代码到 fork 仓库。
> 修改后的代码,首先执行 `git add` 命令,然后执行 `git commit` 命令与 `git push` 命令,将代码 push 到我们自己的 fork 仓中。
> 关于代码提交的这部分内容涉及 git 的使用,可以参照 [git官网](https://git-scm.com/) 的内容,在此不再赘述。
### 发起 Pull Request (PR)
在将代码提交到 fork 仓之后,我们可以通过发起 Pull RequestPR)的方式来为 OpenHarmony 的相关项目贡献代码。
1. 打开 fork 仓库。选择 `Pull Requests` → `新建 Pull Request`
![](./figures/commit_source_new_pull_request.png)
2. 在 `新建 Pull Request` 画面填入标题与说明,点击 `创建` 按钮。
![](./figures/commit_source_new_pull_request_confirm.png)
3. 创建 Pull Request 完成。 PR 创建完成后,会有专门的代码审查人员对代码进行评审,评审通过之后会合入相应的代码库。
![](./figures/commit_source_new_pr_done.png)
系统应用
**applications\_camera**
+8 -14
View File
@@ -1,39 +1,33 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
apply plugin: 'com.huawei.ohos.app'
//For instructions on signature configuration, see https://developer.harmonyos.com/cn/docs/documentation/doc-guides/ide_debug_device-0000001053822404#section1112183053510
ohos {
compileSdkVersion 6
defaultConfig {
compatibleSdkVersion 6
}
compileSdkVersion 8
supportSystem "standard"
}
buildscript {
repositories {
maven {
url 'https://mirrors.huaweicloud.com/repository/maven/'
url 'https://repo.huaweicloud.com/repository/maven/'
}
maven {
url 'https://developer.huawei.com/repo/'
}
maven {
url 'http://repo.ark.tools.huawei.com/artifactory/maven-public/'
}
jcenter()
}
dependencies {
classpath 'com.huawei.ohos:hap:2.4.4.3-RC'
classpath 'com.huawei.ohos:hap:3.0.5.2'
}
}
allprojects {
repositories {
maven {
url 'https://mirrors.huaweicloud.com/repository/maven/'
url 'https://repo.huaweicloud.com/repository/maven/'
}
maven {
url 'https://developer.huawei.com/repo/'
}
jcenter()
}
}
}
+23
View File
@@ -0,0 +1,23 @@
{
"app": {
"bundleName": "com.ohos.camera",
"vendor": "ohos",
"version": {
"code": 1000000,
"name": "1.0.0"
}
},
"deviceConfig": {
},
"module": {
"package": "com.ohos.camera.common",
"deviceType": [
"phone"
],
"distro": {
"deliveryWithInstall": true,
"moduleName": "common",
"moduleType": "har"
}
}
}
@@ -0,0 +1,30 @@
/*
* Copyright (c) 2022 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 class CameraManager {
public picture: any
public focus(): void {
}
public capture(): void {
}
public save(): void {
this.picture = 'picture test'
}
}
@@ -0,0 +1,633 @@
/*
* Copyright (c) 2022 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 camera from '@ohos.multimedia.camera'
import media from '@ohos.multimedia.media'
import image from '@ohos.multimedia.image'
import SaveCameraAsset from './SaveCameraAsset'
import GetPixelMap from './GetPixelMap'
import deviceManager from '@ohos.distributedHardware.deviceManager'
export class CameraService {
private TAG = '[camera]: '
private curCameraName: string = '本地(后置)'
public SaveCameraAsset = new SaveCameraAsset()
public getPixelMap = new GetPixelMap()
public previewOutput: any
public cameraInfo: any = undefined
public cameraInput: any
public cameraManager: any = undefined
public cameraId: any
public photoOutPut: any
public captureSession: any
public videoOutput: any
public videoRecorder: any
public thumbnailCallBack: any
public captureSuccessCallBack: any
public previewId: any
public curMode: any
public photoResolution: any
public videoResolution: any
private isSessionRelease: boolean = true
private fileAsset: any
public cameraListInfo: any
private previewSize = [
{ width: 2048, height: 1536 },
{ width: 720, height: 720 },
{ width: 1920, height: 1080 },
{ width: 1920, height: 1080 },
{ width: 1920, height: 1080 },
{ width: 1920, height: 1080 }
]
private imageSize = [
{ width: 2048, height: 1536 },
{ width: 3120, height: 3120 },
{ width: 1920, height: 1080 }
]
private videoFrameSize = [
{ width: 1280, height: 720 },
{ width: 1920, height: 1080 },
{ width: 3840, height: 2160 }
]
private videoProfile = {
audioBitrate: 48000,
audioChannels: 2,
audioCodec: 'audio/mp4a-latm',
audioSampleRate: 48000,
durationTime: 1000,
fileFormat: 'mp4',
videoBitrate: 48000,
videoCodec: 'video/mp4v-es',
videoFrameWidth: 640,
videoFrameHeight: 480,
videoFrameRate: 30
}
private videoConfig = {
audioSourceType: 1,
videoSourceType: 0,
profile: this.videoProfile,
url: '',
orientationHint: 0,
location: { latitude: 30, longitude: 130 },
maxSize: 100,
maxDuration: 500
}
public static getInstance(): CameraService {
if (!AppStorage.Has('app_key_camera_service')) {
AppStorage.SetOrCreate('app_key_camera_service', new CameraService())
console.info('build new CameraService.')
}
return AppStorage.Get('app_key_camera_service');
}
public async initCamera(surfaceId, previewImage) {
console.info(`${this.TAG} initCamera is called.`)
this.previewId = surfaceId
if (this.cameraManager == undefined) {
this.cameraManager = await camera.getCameraManager(null)
console.info(`${this.TAG} getCameraManager success.`)
}
if (this.cameraInfo == undefined) {
this.cameraInfo = await this.cameraManager.getCameras()
console.info(`${this.TAG} getCameras success.`)
for (let i = 0; i < this.cameraInfo.length; i++) {
console.info(`${this.TAG} --------------Camera Info-------------`)
console.info(`${this.TAG} camera_id: ${this.cameraInfo[i].cameraId}`)
console.info(`${this.TAG} cameraPosition: ${this.cameraInfo[i].cameraPosition}`)
console.info(`${this.TAG} cameraType: ${this.cameraInfo[i].cameraType}`)
console.info(`${this.TAG} connectionType: ${this.cameraInfo[i].connectionType}`)
}
this.cameraId = this.cameraInfo[0].cameraId
await this.calcSupportedSizes()
}
await this.changeMode_(previewImage, this.previewId)
}
public async startPreview(surfaceId: any, mode) {
this.previewId = surfaceId
await this.changeMode_(mode, this.previewId)
}
public getPhotoUri() {
console.info('getPhotoUri called')
return this.SaveCameraAsset.getPhotoUri()
}
public async switchCamera(surfaceId, cameraPosition) {
this.previewId = surfaceId
console.info('switchCamera called')
await this.captureSession.stop()
console.info('switchCamera captureSession.stop')
await this.cameraInput.release()
await this.captureSession.release()
this.isSessionRelease = true
console.info('switchCamera captureSession.release')
if (cameraPosition === 'FRONT') {
this.cameraId = this.cameraInfo[1].cameraId
this.previewSize = [
{ width: 2048, height: 1536 },
{ width: 720, height: 720 },
{ width: 1920, height: 1080 },
{ width: 1920, height: 1080 },
{ width: 1920, height: 1080 },
{ width: 1920, height: 1080 }
]
this.imageSize = [
{ width: 2048, height: 1536 },
{ width: 2448, height: 2448 },
{ width: 1920, height: 1080 }
]
this.videoFrameSize = [
{ width: 1280, height: 720 },
{ width: 1920, height: 1080 },
{ width: 1920, height: 1080 }
]
} else if (cameraPosition === 'BACK') {
this.cameraId = this.cameraInfo[0].cameraId
this.previewSize = [
{ width: 2048, height: 1536 },
{ width: 720, height: 720 },
{ width: 1920, height: 1080 },
{ width: 1920, height: 1080 },
{ width: 1920, height: 1080 },
{ width: 1920, height: 1080 }
]
this.imageSize = [
{ width: 2048, height: 1536 },
{ width: 3120, height: 3120 },
{ width: 1920, height: 1080 }
]
this.videoFrameSize = [
{ width: 1280, height: 720 },
{ width: 1920, height: 1080 },
{ width: 3840, height: 2160 }
]
} else if (cameraPosition === 'MatePad Pro(前置)') {
this.cameraId = this.cameraInfo[6].cameraId
this.previewSize = [
{ width: 1920, height: 1080 },
{ width: 1920, height: 1080 },
{ width: 1920, height: 1080 },
{ width: 1920, height: 1080 },
{ width: 1920, height: 1080 },
{ width: 1920, height: 1080 }
]
this.imageSize = [
{ width: 1920, height: 1080 },
{ width: 1920, height: 1080 },
{ width: 1920, height: 1080 }
]
this.videoFrameSize = [
{ width: 1920, height: 1080 },
{ width: 1920, height: 1080 },
{ width: 1920, height: 1080 }
]
} else if (cameraPosition === 'MatePad Pro(后置)') {
this.cameraId = this.cameraInfo[5].cameraId
this.previewSize = [
{ width: 1920, height: 1080 },
{ width: 1920, height: 1080 },
{ width: 1920, height: 1080 },
{ width: 1920, height: 1080 },
{ width: 1920, height: 1080 },
{ width: 1920, height: 1080 }
]
this.imageSize = [
{ width: 1920, height: 1080 },
{ width: 1920, height: 1080 },
{ width: 1920, height: 1080 }
]
this.videoFrameSize = [
{ width: 1920, height: 1080 },
{ width: 1920, height: 1080 },
{ width: 1920, height: 1080 }
]
}
console.info(`get cameraId= ${this.cameraId}`)
this.cameraInput = await this.cameraManager.createCameraInput(this.cameraId)
await this.calcSupportedSizes()
console.info('switchCamera cameraManager.createCameraInput')
await this.changeMode_(this.curMode, this.previewId)
}
public getThumbnail(callback) {
this.getPixelMap.getThumbnailInfo(40, 40).then((thumbnail) => {
console.info('getPixelMap.getThumbnailInfo called')
this.thumbnailCallBack = callback
this.thumbnailCallBack(thumbnail)
})
}
public changeMode(mode, id) {
console.info(`${this.TAG} changeMode() called.`)
this.changeMode_(mode, id)
}
public async changeMode_(mode, id) {
console.info(`${this.TAG} changeMode_ called.`)
this.curMode = mode
this.previewId = id
if (!this.isSessionRelease) {
await this.captureSession.stop()
if (this.cameraInput) {
await this.cameraInput.release()
}
console.info(`${this.TAG} captureSession.release() called.`)
await this.captureSession.release()
console.info(`${this.TAG} captureSession.release() done.`)
this.isSessionRelease = true
}
this.captureSession = await camera.createCaptureSession(null)
if (this.captureSession) {
console.info(`${this.TAG} createCaptureSession success.`)
this.isSessionRelease = false
console.info(`${this.TAG} this.previewId ${this.previewId}`)
this.previewOutput = await camera.createPreviewOutput(this.previewId)
this.cameraInput = await this.cameraManager.createCameraInput(this.cameraId)
console.info(`${this.TAG} beginConfig called.`)
await this.captureSession.beginConfig()
await this.captureSession.addInput(this.cameraInput)
await this.captureSession.addOutput(this.previewOutput)
switch (mode) {
case 'PHOTO':
console.info(`${this.TAG} now is PHOTO mode.`)
console.info(`${this.TAG} start.`)
let imageWidth = this.imageSize[this.photoResolution].width
let imageHeight = this.imageSize[this.photoResolution].height
let mReceiver = image.createImageReceiver(imageWidth, imageHeight, 4, 8)
console.info(`${this.TAG} end.`)
let mSurfaceId = await mReceiver.getReceivingSurfaceId()
await camera.createPhotoOutput(mSurfaceId).then((res) => {
console.info(`${this.TAG} createPhotoOutput called.`)
this.photoOutPut = res
})
this.SaveCameraAsset.saveImage(mReceiver, 40, 40, this.thumbnailCallBack,
this.getPixelMap,
(() => {
this.captureSuccessCallBack()
}))
await this.captureSession.addOutput(this.photoOutPut)
break;
case 'VIDEO':
console.info(`${this.TAG} now is VIDEO mode.`)
break;
case 'MULTI':
console.info(`${this.TAG} now is MULTI mode.`)
let multiImageWidth = this.imageSize[this.photoResolution].width
let multiImageHeight = this.imageSize[this.photoResolution].height
let multiReceiver = image.createImageReceiver(multiImageWidth, multiImageHeight, 4, 8)
let multiSurfaceId = await multiReceiver.getReceivingSurfaceId()
await camera.createPhotoOutput(multiSurfaceId).then((res) => {
console.info(`${this.TAG} createPhotoOutput called.`)
this.photoOutPut = res
})
this.SaveCameraAsset.saveImage(multiReceiver, 40, 40, this.thumbnailCallBack,
this.getPixelMap,
(() => {
this.captureSuccessCallBack()
}))
await this.captureSession.addOutput(this.photoOutPut)
break;
default:
break;
}
await this.captureSession.commitConfig()
await this.captureSession.start()
console.info(`${this.TAG} changeMode_ finished.`)
} else {
console.info(`${this.TAG} createCaptureSession failed.`)
}
}
public async takePicture(callback) {
this.captureSuccessCallBack = callback
let photoSettings = {
rotation: 0,
quality: 1,
location: {
latitude: 12.9698,
longitude: 77.7500
},
mirror: false
}
console.info(`${this.TAG} takePicture photoSettings ${photoSettings}`)
await this.photoOutPut.capture(photoSettings)
console.info(`${this.TAG} capture done.`)
}
public async releaseCamera() {
console.info(`${this.TAG} releaseCamera called.`)
await this.captureSession.stop()
console.info(`${this.TAG} cameraInput.release called.`)
await this.cameraInput.release()
console.info(`${this.TAG} captureSession.release called.`)
await this.captureSession.release()
this.isSessionRelease = true
console.info(`${this.TAG} releaseCamera done.`)
}
public async releaseCameraInput() {
await this.cameraInput.release()
console.info(`${this.TAG} releaseCameraInput done.`)
}
public async releasePreviewOutput() {
await this.previewOutput.release()
console.info(`${this.TAG} releasePreviewOutput done.`)
}
public async releasePhotoOutPut() {
await this.photoOutPut.release()
console.info(`${this.TAG} releasePhotoOutPut done.`)
}
public async startVideo(id) {
this.previewId = id
let videoId
if (!this.isSessionRelease) {
await this.captureSession.stop()
await this.cameraInput.release()
console.info(`${this.TAG} captureSession.release() called.`)
await this.captureSession.release().then(() => {
this.SaveCameraAsset.getVideoFd().then(async (fileAssets) => {
console.info(`getFileAssets fileAssets: ${fileAssets}`);
this.fileAsset = fileAssets[0]
let fdNumber = await this.fileAsset.open('Rw')
this.videoConfig.url = `fd://${fdNumber.toString()}`
console.info(`${this.TAG} videoRecorder.prepare videoConfig.url: ${this.videoConfig.url}`)
this.captureSession = await camera.createCaptureSession(null)
this.cameraInput = await this.cameraManager.createCameraInput(this.cameraId)
if (this.captureSession != null) {
console.info(`${this.TAG} createCaptureSession success.`)
this.isSessionRelease = false
console.info(`${this.TAG} this.previewId ${this.previewId}`)
this.previewOutput = await camera.createPreviewOutput(this.previewId)
if (this.videoRecorder) {
await this.videoRecorder.release()
}
await media.createVideoRecorder().then((recorder) => {
console.info(`${this.TAG} createVideoRecorder called.`)
this.videoRecorder = recorder
})
if (this.videoRecorder != null) {
console.info(`${this.TAG} videoRecorder.prepare called.`)
this.videoConfig.profile.videoFrameWidth = this.videoFrameSize[this.videoResolution].width
this.videoConfig.profile.videoFrameHeight = this.videoFrameSize[this.videoResolution].height
await this.videoRecorder.prepare(this.videoConfig)
console.info(`${this.TAG} videoRecorder.prepare succeed.`)
} else {
console.info(`${this.TAG} createVideoRecorder failed.`)
}
await this.videoRecorder.getInputSurface().then((resultId) => {
console.info(`${this.TAG} getInputSurface called`)
videoId = resultId
console.info(`${this.TAG} getInputSurface surfaceId: ${JSON.stringify(videoId)}`)
})
this.videoOutput = await camera.createVideoOutput(videoId)
await this.captureSession.beginConfig()
await this.captureSession.addInput(this.cameraInput)
await this.captureSession.addOutput(this.previewOutput)
await this.captureSession.addOutput(this.videoOutput)
await this.captureSession.commitConfig()
await this.captureSession.start().then(async () => {
await this.videoOutput.start().then(() => {
console.info(`${this.TAG} videoOutput.start()`)
})
await this.videoRecorder.start().then(() => {
console.info(`${this.TAG} videoRecorder.start()`)
})
})
} else {
console.info(`${this.TAG} createCaptureSession failed.`)
}
})
})
this.isSessionRelease = true
}
}
public async stopVideo() {
console.info(`${this.TAG} stopVideo called.`)
try {
await this.videoRecorder.stop()
} catch (err) {
console.info(`${this.TAG} stop videoRecorder ${err}`)
}
try {
await this.videoOutput.stop()
} catch (err) {
console.info(`${this.TAG} stop videoOutput ${err}`)
}
if (this.fileAsset != undefined) {
this.fileAsset.close()
this.fileAsset = undefined
console.info(`${this.TAG} fileAsset.close().`)
}
}
public async pauseVideo() {
await this.videoOutput.stop()
await this.videoRecorder.pause()
}
public async releaseVideo() {
console.info(`${this.TAG} releaseVideo called.`)
await this.stopVideo()
await this.videoRecorder.release().then(() => {
console.info(`${this.TAG} videoRecorder.release() success.`)
this.videoRecorder = undefined
})
await this.videoOutput.release()
}
public async resumeVideo() {
await this.videoOutput.start().then(() => {
console.info(`${this.TAG} videoOutput.start()`)
})
await this.videoRecorder.resume()
}
public async setZoomRatio(zoomRatio) {
console.info(`setZoomRatio called zoomRatio= ${zoomRatio}`)
await this.cameraInput.setZoomRatio(zoomRatio)
}
public async getZoomRatio() {
console.info('getZoomRatio called')
let zoomRatioValue = await this.cameraInput.getZoomRatio()
console.info(`ZoomRatio= ${zoomRatioValue}`)
return zoomRatioValue
}
public async getZoomRatioRange() {
console.info('getZoomRatioRange called')
let zoomRatioRange = await this.cameraInput.getZoomRatioRange()
console.info(`zoomRatioRange= ${zoomRatioRange}`)
return zoomRatioRange
}
public async calcSupportedSizes() {
return;
let photoSize = await this.cameraInput.getSupportedSizes(2000)
console.info("calcSupportedSizes photoSize" + JSON.stringify(photoSize))
this.imageSize[0] = this.getMaxSize(photoSize, 4, 3)
this.imageSize[1] = this.getMaxSize(photoSize, 1, 1)
this.imageSize[2] = this.getMaxSize(photoSize, 16, 9)
this.previewSize[0] = this.imageSize[0]
this.previewSize[1] = this.imageSize[1]
this.previewSize[2] = this.imageSize[2]
let previewCurSize = await this.cameraInput.getSupportedSizes(1003)
console.info("calcSupportedSizes previewCurSize" + JSON.stringify(previewCurSize))
this.videoFrameSize[0] = this.getSpecifiedSize(previewCurSize, 1280, 720)
this.videoFrameSize[1] = this.getSpecifiedSize(previewCurSize, 1920, 1080)
this.videoFrameSize[2] = this.getSpecifiedSize(previewCurSize, 3840, 2160)
this.previewSize[3] = this.videoFrameSize[0]
this.previewSize[4] = this.videoFrameSize[1]
this.previewSize[5] = this.videoFrameSize[2]
}
public getSpecifiedSize(sizeList, width, height) {
let specifiedSize = { width: 0, height: 0 }
for (let i = 0; i < sizeList.length; i++) {
let widthError = sizeList[i].width - width
let heightError = sizeList[i].height - height
if (widthError <= 4 && widthError >= -4 && heightError <= 4 && heightError >= -4) {
if (sizeList[i].width > specifiedSize.width) {
specifiedSize = sizeList[i]
}
}
}
console.log("getSpecifiedSize specifiedSize = " + JSON.stringify(specifiedSize))
return specifiedSize
}
public getMaxSize(sizeList, width, height) {
let maxSize = { width: 0, height: 0 }
for (let i = 0; i < sizeList.length; i++) {
let errorValue = sizeList[i].width * height - sizeList[i].height * width
if (errorValue <= 64 && errorValue >= -64) {
if (sizeList[i].width > maxSize.width) {
maxSize = sizeList[i]
}
}
}
return maxSize
}
public getPreviewSize(mode) {
let previewSize
switch (mode) {
case 'PHOTO':
previewSize = this.previewSize[this.photoResolution]
break;
case 'VIDEO':
previewSize = this.previewSize[this.videoResolution + 3]
break;
default:
break;
}
console.log("getPreviewSize" + JSON.stringify(previewSize));
return previewSize;
}
public setAspectRatio(aspectRatio) {
switch (aspectRatio) {
case '4:3':
this.photoResolution = 0
break;
case '1:1':
this.photoResolution = 1
break;
case '16:9':
this.photoResolution = 2
break;
default:
this.photoResolution = 0
break;
}
}
public setVideoResolution(videoResolution) {
switch (videoResolution) {
case '[16:9] 720p':
this.videoResolution = 0
break;
case '[16:9] 1080p':
this.videoResolution = 1
break;
case '[16:9] 4k':
this.videoResolution = 2
break;
default:
this.videoResolution = 0
break;
}
}
getDeviceInfo() {
console.info(`${this.TAG} getDeviceInfo called.`)
return ['MatePad Pro(前置)', 'MatePad Pro(后置)']
let deviceNames = []
deviceManager.createDeviceManager('com.ohos.camera', (err, manager) => {
if (err) {
console.info(`${this.TAG} deviceManager.createDeviceManager failed.`)
return
}
console.info(`${this.TAG} deviceManager.createDeviceManager success.`)
let deviceInfoList = manager.getTrustedDeviceListSync()
console.info(`${this.TAG} deviceManager.deviceInfoList: ${JSON.stringify(deviceInfoList)}`)
if (typeof (deviceInfoList) != undefined && typeof (deviceInfoList.length) != undefined) {
deviceInfoList.forEach(item => {
deviceNames.push(item.deviceName)
})
}
})
return deviceNames
}
async getCameraLists() {
console.info(`${this.TAG} getCameraLists called.`)
let cameras = await this.cameraManager.getCameras()
this.cameraListInfo = cameras
if (cameras) {
this.cameraInfo = cameras
console.info(`${this.TAG} getCameraLists success.`)
for (let i = 0; i < cameras.length; i++) {
console.info(`${this.TAG} -----------------CameraInfo--------------`)
console.info(`${this.TAG} camera_id: ${cameras[i].cameraId}`)
console.info(`${this.TAG} cameraPosition: ${cameras[i].cameraPosition}`)
console.info(`${this.TAG} cameraType: ${cameras[i].cameraType}`)
console.info(`${this.TAG} connectionType: ${cameras[i].connectionType}`)
}
}
}
getCameraName() {
return this.curCameraName
}
setCameraName(name: string) {
console.info(this.TAG + 'setCameraName ' + name)
this.curCameraName = name
}
}
@@ -0,0 +1,46 @@
/*
* Copyright (c) 2022 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 mediaLibrary from '@ohos.multimedia.mediaLibrary';
export default class GetPixelMap {
public async getThumbnailInfo(width: number, height: number, uri?: string): Promise<string> {
console.log("getThumbnailInfoA start")
let thumbnail
let fileKeyObj = mediaLibrary.FileKey;
let fetchOp: any
const media = mediaLibrary.getMediaLibrary(globalThis.cameraAbilityContext);
if (uri != undefined) {
return uri
}
fetchOp = {
selections: `${fileKeyObj.RELATIVE_PATH}=?`,
selectionArgs: ["Pictures/Camera/"],
order: fileKeyObj.DATE_ADDED,
}
console.log(`fetchOp ${JSON.stringify(fetchOp)}`);
let fetchFileResult = await media.getFileAssets(fetchOp);
let count = fetchFileResult.getCount()
console.log(`getThumbnailInfo fetchFileResult.getCount: ${count}`)
if (count == 0) {
return ''
}
let lastFileAsset = await fetchFileResult.getLastObject()
thumbnail = lastFileAsset.uri
console.info(`getThumbnailInfo fileAsset.uri: ${thumbnail}`)
return thumbnail;
}
}
@@ -0,0 +1,141 @@
/*
* Copyright (c) 2022 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 mediaLibrary from '@ohos.multimedia.mediaLibrary';
import fileio from '@ohos.fileio';
import DateTimeUtil from '../Utils/DateTimeUtil';
let photoUri;
export default class SaveCameraAsset {
constructor() {
}
private TAG = 'image: '
private lastSaveTime: string = ''
private saveIndex : number = 0
public getPhotoUri() {
console.log(`getPhotoUri= ${photoUri}`)
return photoUri
}
public saveImage(mReceiver, thumbWidth, thumbHeight, thumbCallback, getPixelMap, captureSuccessCallBack) {
let mDateTimeUtil = new DateTimeUtil();
let fileKeyObj = mediaLibrary.FileKey
let mediaType = mediaLibrary.MediaType.IMAGE;
let buffer = new ArrayBuffer(4096)
const media = mediaLibrary.getMediaLibrary(globalThis.cameraAbilityContext);
console.log("mediaLibrary.getMediaLibrary success")
mReceiver.on('imageArrival', async () => {
console.log("ImageReceiver on called")
let displayName = this.checkName(`IMG_${mDateTimeUtil.getDate()}_${mDateTimeUtil.getTime()}`) + '.jpg'
console.log(`saveImage displayName== ${displayName}`)
mReceiver.readNextImage((err, image) => {
if (image === undefined) {
console.info(`${this.TAG} failed to get valid image`)
return
}
image.getComponent(4, async (errMsg, img) => {
if (img === undefined) {
console.info(`${this.TAG} failed to get valid buffer`)
return
}
if (img.byteBuffer) {
buffer = img.byteBuffer
} else {
console.info(`${this.TAG} img.byteBuffer is undefined`)
}
await image.release()
})
})
let publicPath: string = await media.getPublicDirectory(mediaLibrary.DirectoryType.DIR_IMAGE);
publicPath = `${publicPath}Camera/`
let dataUri = await media.createAsset(mediaType, displayName, publicPath)
photoUri = dataUri.uri
console.info(`${this.TAG} SaveCameraAsset photoUri: ${photoUri}`)
if (dataUri !== undefined) {
let args = dataUri.id.toString()
let fetchOp = {
selections: `${fileKeyObj.ID} = ? `,
selectionArgs: [args],
}
console.log(`fetchOp${JSON.stringify(fetchOp)}`)
let fetchFileResult = await media.getFileAssets(fetchOp);
let fileAsset = await fetchFileResult.getAllObject();
if (fileAsset != undefined) {
console.info("fileAsset is not undefined")
fileAsset.forEach((dataInfo) => {
console.info("fileAsset.forEach called")
dataInfo.open('Rw').then((fd) => {
console.info("dataInfo.open called")
fileio.write(fd, buffer).then(() => {
console.info("fileio.write called")
dataInfo.close(fd).then(() => {
console.info("ataInfo.close called")
captureSuccessCallBack()
getPixelMap.getThumbnailInfo(thumbWidth, thumbHeight, photoUri).then(thumbnail => {
console.info(`${this.TAG} getThumbnailInfo thumbnailInfo: ${thumbnail}`)
thumbCallback(thumbnail)
})
console.info("==========================fileAsset.close success=======================>");
}).catch(error => {
console.info(`close is error ${JSON.stringify(error)}`)
})
})
})
});
}
}
})
}
public async getVideoFd(): Promise<any> {
let mDateTimeUtil = new DateTimeUtil();
let displayName = this.checkName(`VID_${mDateTimeUtil.getDate()}_${mDateTimeUtil.getTime()}`) + '.mp4'
const media = mediaLibrary.getMediaLibrary(globalThis.cameraAbilityContext);
let fileKeyObj = mediaLibrary.FileKey;
let mediaType = mediaLibrary.MediaType.VIDEO;
let publicPath: string = await media.getPublicDirectory(mediaLibrary.DirectoryType.DIR_VIDEO);
publicPath = `${publicPath}Camera/`
let dataUri = await media.createAsset(mediaType, displayName, publicPath)
if (dataUri !== undefined) {
let args = dataUri.id.toString()
let fetchOp = {
selections: `${fileKeyObj.ID} = ? `,
selectionArgs: [args],
}
console.log(`fetchOp= ${JSON.stringify(fetchOp)}`)
let fetchFileResult = await media.getFileAssets(fetchOp);
let fileAssets = await fetchFileResult.getAllObject();
return fileAssets;
}
}
private checkName(name: string): string {
if (this.lastSaveTime == name) {
this.saveIndex++
return `${name}_${this.saveIndex}`
}
this.lastSaveTime = name
this.saveIndex = 0
return name
}
}
@@ -0,0 +1,55 @@
/*
* Copyright (c) 2022 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 {EventBus} from './EventBus.ets'
import {EventBusManager} from './EventBusManager.ets'
import {Constants} from './Constants.ets'
export class AsyncManager {
appEventBus: EventBus = EventBusManager.getMainInstance().getEventBus()
constructor() {
}
public static getInstance(): AsyncManager {
if (!AppStorage.Has(Constants.APP_KEY_ASYNC_MANAGER)) {
AppStorage.SetOrCreate(Constants.APP_KEY_ASYNC_MANAGER, new AsyncManager())
console.info('build new AsyncManager.')
}
return AppStorage.Get(Constants.APP_KEY_ASYNC_MANAGER);
}
public postMessage(msg: any): AsyncManager {
return this
}
public onMessage(msg: any): void {
console.info(`AsyncManager onMessage uidata: ${JSON.stringify(msg.data)}`)
}
public onmessageerror(msg: any): void {
}
public onerror(msg: any): void {
}
public onexit(msg: any): void {
}
}
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Copyright (c) 2022 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
@@ -13,9 +13,8 @@
* limitations under the License.
*/
var PageData = {
PREVIEW_PAGE: 'pages/PreviewView/PreviewView',
DISTRIBUTED_PAGE: 'pages/DistributedView/DistributedView'
};
export class Constants {
export default PageData;
static readonly APP_KEY_ASYNC_MANAGER = "app_key_async_manager"
}
@@ -0,0 +1,81 @@
/*
* Copyright (c) 2022 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.
*/
/**
* @file: 日期工具
*/
export default class DateTimeUtil {
/**
* 时分秒
*
* @return {string} - 返回时分秒
*/
getTime() {
const DATETIME = new Date();
const HOURS = DATETIME.getHours();
const MINUTES = DATETIME.getMinutes();
const SECONDS = DATETIME.getSeconds();
return this.concatTime(HOURS, MINUTES, SECONDS);
}
/**
* 年月日
*
* @return {string} - 返回年月日
*/
getDate() {
const DATETIME = new Date();
const YEAR = DATETIME.getFullYear();
const MONTH = DATETIME.getMonth() + 1;
const DAY = DATETIME.getDate();
return this.concatDate(YEAR, MONTH, DAY);
}
/**
* 日期不足两位补 0
*
* @param {string} value - 数据值
* @return {string} - 日期不足两位补 0
*/
fill(value) {
return (value > 9 ? '' : '0') + value;
}
/**
* 年月日格式修饰
*
* @param {string} year - 年
* @param {string} month - 月
* @param {string} date - 日
* @return {string} - 年月日格式修饰
*/
concatDate(year, month, date) {
return `${year}${month}${date}`;
}
/**
* 时分秒格式修饰
*
* @param {string} hours - 时
* @param {string} minutes - 分
* @param {string} seconds - 秒
* @return {string} - 时分秒格式修饰
*/
concatTime(hours, minutes, seconds) {
return `${this.fill(hours)}${this.fill(minutes)}${this.fill(seconds)}`;
}
}
@@ -0,0 +1,106 @@
/*
* Copyright (c) 2022 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 class EventBus {
_events = []
constructor() {
}
/**
* Register events and handlers
* @param event
* @param fn
*/
public on(event, fn) {
if (Array.isArray(event)) {
for (let i = 0, l = event.length; i < l; i++) {
this.on(event[i], fn)
}
} else {
(this._events[event] || (this._events[event] = [])).push(fn)
}
}
/**
* Register events and processing functions, and destroy them after triggering once
* @param event
* @param fn
*/
public once(event, fn) {
let _self = this;
function handler() {
_self.off(event, handler);
fn.apply(null, [event, fn]);
}
handler.fn = fn;
_self.on(event, handler);
}
/**
* Destroy events and handlers
* @param event
* @param fn
*/
public off(event, fn) {
if (event == null) {
this._events = [];
}
if (Array.isArray(event)) {
for (let i = 0, l = event.length; i < l; i++) {
this.off(event[i], fn)
}
}
const cbs = this._events[event];
if (!cbs) {
return;
}
if (fn == null) {
this._events[event] = null
}
let cb, i = cbs.length
while (i--) {
cb = cbs[i]
if (cb === fn || cb.fn === fn) {
cbs.splice(i, 1)
break
}
}
}
/**
* Trigger all callbacks of an event with parameters
* @param event
*/
public emit(event, argument: any[]) {
let _self = this
if (!_self._events[event]) {
return
}
let cbs = [..._self._events[event]];
if (cbs) {
for (let i = 0, l = cbs.length; i < l; i++) {
try {
cbs[i].apply(_self, argument)
} catch (e) {
new Error(e)
}
}
}
}
}
@@ -0,0 +1,45 @@
/*
* Copyright (c) 2022 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 {EventBus} from "./EventBus"
export class EventBusManager {
private appEventBus: EventBus;
static sInstance: EventBusManager = undefined;
static mInstance: EventBusManager = undefined;
private constructor() {
this.appEventBus = new EventBus();
}
public static getInstance(): EventBusManager {
if (EventBusManager.sInstance == null) {
EventBusManager.sInstance = new EventBusManager();
}
return EventBusManager.sInstance;
}
public static getMainInstance(): EventBusManager {
if (EventBusManager.mInstance == null) {
EventBusManager.mInstance = new EventBusManager();
}
return EventBusManager.mInstance;
}
public getEventBus(): EventBus {
return this.appEventBus;
}
}
@@ -0,0 +1,135 @@
/*
* Copyright (c) 2022 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 dataRdb from '@ohos.data.rdb';
import SettingItemInfo from './SettingItemInfo.ets'
const TAG = 'RdbStoreManager ';
const DB_NAME = 'Camera.db'
const DB_VERSION = 1
const TABLE_NAME = 'SETTING'
const CREATE_TABLE = 'CREATE TABLE IF NOT EXISTS SETTING ' +
'(id INTEGER PRIMARY KEY AUTOINCREMENT, ' +
'item_name TEXT, ' +
'item_value TEXT)'
/**
* @file db manager
*/
export default class RdbStoreManager {
private mRdbStore;
private constructor() {
}
/**
* db manager instance
*
* @return rdbStoreManager instance
*/
public static getInstance() {
if (globalThis.RdbStoreManagerInstance == null) {
globalThis.RdbStoreManagerInstance = new RdbStoreManager();
}
return globalThis.RdbStoreManagerInstance;
}
public async initRdbConfig() {
console.info(TAG + 'initRdbConfig start');
const promise = dataRdb.getRdbStore(globalThis.cameraAbilityContext,
{
name: DB_NAME
}, DB_VERSION);
promise.then(async (rdbStore) => {
console.info(TAG + 'initRdbConfig dataRdb.getRdbStore:' + rdbStore);
this.mRdbStore = rdbStore;
this.createTable();
}).catch((error) => {
console.error('RdbStoreManager.initRdbConfig Failed to obtain the rdbStore. Cause: ' + error.message);
});
console.info(TAG + 'initRdbConfig end');
}
private async createTable() {
console.info(TAG + 'create table start');
console.info(TAG + `RdbStoreConfig.CREATE_TABLE: ${CREATE_TABLE}`);
await this.mRdbStore.executeSql(CREATE_TABLE, []);
console.info(TAG + 'create table end');
}
public async getSettingByItem(itemName: string) {
console.info(TAG + 'getSettingByItem start');
const resultList: SettingItemInfo[] = [];
if (this.ifStringIsNull(itemName)) {
return resultList;
}
try {
const predicates = new dataRdb.RdbPredicates(TABLE_NAME);
predicates.equalTo('item_name', itemName);
const resultSet = await this.mRdbStore.query(predicates, []);
let isLast = resultSet.goToFirstRow();
console.info(TAG + `getSettingByItem before isLast: ${isLast}`);
while (isLast) {
const itemInfo: SettingItemInfo = new SettingItemInfo()
itemInfo.itemName = resultSet.getString(resultSet.getColumnIndex('item_name'));
itemInfo.itemValue = resultSet.getString(resultSet.getColumnIndex('item_value'));
resultList.push(itemInfo);
isLast = resultSet.goToNextRow();
console.info(TAG + `getSettingByItem while isLast: ${isLast}`);
}
} catch (e) {
console.info(TAG + 'getSettingByItem error:' + e);
}
return resultList;
}
public async updateValue(settingItemInfo: SettingItemInfo) {
console.info(TAG + 'updateValue start');
let result = false;
try {
const predicates = new dataRdb.RdbPredicates(TABLE_NAME);
predicates.equalTo('item_name', settingItemInfo.itemName);
const updateBucket = {
'item_value': settingItemInfo.itemValue,
};
console.info(TAG + 'updateValue predicates: ' + JSON.stringify(predicates))
console.info(TAG + 'mRdbStore.update called.')
let changeRows = await this.mRdbStore.update(updateBucket, predicates);
console.info(TAG + 'mRdbStore.update finished.')
if (changeRows == 1) {
console.info(TAG + `updateValue updated ok: ${changeRows}`);
result = true;
} else {
console.info(TAG + `updateValue updated not effect: ${changeRows}`);
const insertBucket = {
'item_name': settingItemInfo.itemName,
'item_value': settingItemInfo.itemValue,
};
changeRows = await this.mRdbStore.insert(TABLE_NAME, insertBucket);
console.info(TAG + `updateValue insert: ${changeRows}`);
result = (changeRows != -1);
}
} catch (e) {
console.info(TAG + 'updateValue error:' + e);
}
return result;
}
private ifStringIsNull(str) {
if (str == undefined || str == '' || str == null) {
return true;
}
return false;
}
}
@@ -0,0 +1,27 @@
/*
* Copyright (c) 2022 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 default class SettingItemInfo {
/**
* itemName
*/
public itemName: string;
/**
* itemValue
*/
public itemValue: string;
}
@@ -0,0 +1,55 @@
/*
* Copyright (c) 2022 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 RdbStoreManager from './RdbStoreManager.ets'
import SettingItemInfo from './SettingItemInfo.ets'
export class SettingsUtil {
public photoValue: any = '4:3'
public videoValue: any = '[16:9] 720p'
private rdbStoreManager: RdbStoreManager = RdbStoreManager.getInstance()
public static getInstance(): SettingsUtil {
if (!AppStorage.Has('app_key_settings_util')) {
AppStorage.SetOrCreate('app_key_settings_util', new SettingsUtil())
console.info('build new SettingsUtil.')
}
return AppStorage.Get('app_key_settings_util');
}
public async setSettingValue(settingAlias, itemValue) {
console.info('SettingsUtil.setSettingValue settingAlias: ' + settingAlias)
console.info('SettingsUtil.setSettingValue itemValue: ' + itemValue)
let settingItemInfo: SettingItemInfo = new SettingItemInfo();
settingItemInfo.itemName = settingAlias;
settingItemInfo.itemValue = itemValue;
await this.rdbStoreManager.updateValue(settingItemInfo)
}
public async getSettingValue(settingAlias) {
console.info('SettingsUtil.getSettingValue settingAlias: ' + settingAlias)
let resultList: SettingItemInfo[] = await this.rdbStoreManager.getSettingByItem(settingAlias)
console.info('SettingsUtil.getSettingValue resultList: ' + JSON.stringify(resultList))
if (resultList.length == 0) {
console.info('SettingsUtil.getSettingValue none.')
return settingAlias == 'Aspect ratio' ? '4:3' : '[16:9] 720p'
} else {
for (let i = 0; i < resultList.length; i++) {
console.info('SettingsUtil.getSettingValue' + i + ': ' + resultList[i].itemValue)
}
}
return resultList[0].itemValue
}
}
@@ -0,0 +1,24 @@
/*
* Copyright (c) 2022 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 {AsyncManager} from '../../Utils/AsyncManager.ets'
export const ReduxWorkerMiddle = store => next => action => {
let asyncManager = AsyncManager.getInstance()
asyncManager.postMessage(action)
let result = next(action)
console.info(`logger: new state ${JSON.stringify(store.getState())}`)
return result
}
@@ -0,0 +1,21 @@
/*
* Copyright (c) 2022 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 const logger = store => next => action => {
console.info(`logger: dispatch ${JSON.stringify(action)}, store: ${JSON.stringify(store.getState())}`)
let result = next(action)
console.info(`logger: new state ${JSON.stringify(store.getState())}`)
return result
}
@@ -0,0 +1,96 @@
/**
* Copyright (c) 2022 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 BaseConfModel from '../../model/common/BaseConfModel.ets'
/**
* @file app setting homepage service class
*/
const FILE_URI = '/data/accounts/account_0/applications/com.ohos.camera'
+ '/com.ohos.camera/assets/tablet/resources/rawfile/';
export class SettingListModel {
constructor() {
}
setSettingDetialListener() {
console.info('settings SettingListModel start');
BaseConfModel.getJsonDataBase(FILE_URI.concat('settingdetaillist.json'), baseData => {
console.info(`settings SettingListModel getAbilityInfoListener getJsonDataBase: ${JSON.stringify(baseData)}`)
let settingsDetailList = this.setTitleDetailValue(baseData);
AppStorage.SetOrCreate('settingsDetailList', settingsDetailList);
console.info('settings SettingListModel end');
});
}
async setSettingListener() {
console.info('settings SettingListModel start');
BaseConfModel.getJsonDataBase(FILE_URI.concat('settingdetaillist.json'), baseData => {
console.info(`settings SettingListModel getAbilityInfoListener getJsonDataBase: ${JSON.stringify(baseData)}`)
let settingsList = this.setTitleValue(baseData);
AppStorage.SetOrCreate('settingsList', settingsList);
console.info('settings SettingListModel end');
});
}
setTitleDetailValue(settingsDetailList) {
console.info("setTitleValue start")
for (let key in settingsDetailList) {
let settingAlias = settingsDetailList[key].settingAlias;
console.info(`settingAlias ${settingAlias}`)
console.info(`key = ${key}`)
let value;
if ('photoScale' === settingAlias || 'Aspect ratio' === settingAlias) {
value = $r('app.string.aspect_ratio')
} else if ('videoResolution' === settingAlias || 'Video resolution' === settingAlias) {
value = $r('app.string.video_resolution');
} else if ('dateAndTimeTab' === settingAlias) {
} else {
value = ""
}
settingsDetailList[key].settingTitle = value;
}
console.info(`settings setTitleValue end ==: ${JSON.stringify(settingsDetailList)}`);
return settingsDetailList;
}
setTitleValue(settingsList) {
for (let index = 0; index < settingsList.length; index++) {
if (settingsList[index].subtitle === 'PHOTO') {
settingsList[index].subtitle = $r('app.string.photo_mode')
} else if (settingsList[index].subtitle === 'VIDEO') {
settingsList[index].subtitle = $r('app.string.video_mode')
}
for (let pro = 0; pro < settingsList[index].length; pro++) {
if (settingsList[index][pro].settingName === 'Aspect ratio') {
settingsList[index][pro].settingName = $r('app.string.aspect_ratio')
} else if (settingsList[index][pro].settingName === 'Video resolution') {
settingsList[index][pro].settingName = $r('app.string.video_resolution')
}
}
}
console.info(`settings setTitleValue ==: ${JSON.stringify(settingsList)}`);
return settingsList;
}
}
let settingListModel = new SettingListModel();
export default settingListModel as SettingListModel;
@@ -0,0 +1,66 @@
/*
* Copyright (c) 2022 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 '@ohos.fileio';
import settings from '@ohos.settings';
/**
* @file read local file
*/
const DFAULT_SIZE = 4096;
const CHAR_CODE_AT_INDEX = 0;
export class BaseConfModel {
constructor() {
}
public getJsonData(fileName: string): any[]{
console.info('settings BaseConfModel getJsonData start');
return this.readLocalFile(fileName);
console.info('settings BaseConfModel getJsonData end');
}
public getJsonDataBase(fileName, callback) {
console.info('settings BaseParseConfModel getJsonDataBase in');
callback(this.readLocalFile(fileName));
console.info('settings BaseParseConfModel getJsonDataBase end');
}
readLocalFile(fileName): any[]{
try {
let stream = FileIo.createStreamSync(fileName, 'r');
console.info(`settings BaseConfModel getJsonData try stream: ${stream}`);
let buf = new ArrayBuffer(DFAULT_SIZE);
let len = stream.readSync(buf);
console.info(`settings BaseConfModel getJsonData try len: ${len}`);
let arr = new Uint8Array(buf);
let charAt = ' '.charCodeAt(CHAR_CODE_AT_INDEX);
for (let i = len;i < DFAULT_SIZE; i++) {
arr[i] = charAt;
}
let content = String.fromCharCode.apply(null, arr);
stream.closeSync();
console.info(`settings BaseConfModel getJsonData try content: ${JSON.stringify(content)}`);
return JSON.parse(content);
} catch (jsonError) {
console.info(`settings BaseConfModel getJsonData catch jsonError: ${jsonError}`);
}
}
}
let baseConfModel = new BaseConfModel();
export default baseConfModel as BaseConfModel;
@@ -0,0 +1,39 @@
/**
* Copyright (c) 2022 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 const ACTION_CHANGE_PREVIEW_SIZE = 'changePreviewSize'
export const ACTION_CHANGE_SHUTTER_BUTTON = 'changeShutterButton'
export const ACTION_CHANGE_TAB_ITEM = 'changeTabItem'
export function changePreviewSize(size) {
return {
type: ACTION_CHANGE_PREVIEW_SIZE,
data: { size: size }
}
}
export function changeShutterButton(res) {
return {
type: ACTION_CHANGE_SHUTTER_BUTTON,
data: { res: res }
}
}
export function changeTabItem(mode: string) {
return {
type: ACTION_CHANGE_TAB_ITEM,
data: mode
}
}
@@ -0,0 +1,23 @@
/**
* Copyright (c) 2022 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 const UIDATA_TAB_ITEM = 'tabItem'
export function uiDataTabItem(tabItem) {
return {
type: UIDATA_TAB_ITEM,
data: tabItem
}
}
@@ -0,0 +1,24 @@
/**
* Copyright (c) 2022 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 {AsyncManager} from '../../Utils/AsyncManager.ets'
export const ReduxWorkerMiddle = store => next => action => {
let asyncManager = AsyncManager.getInstance()
asyncManager.postMessage(action)
let result = next(action)
console.info(`logger: new state ${JSON.stringify(store.getState())}`)
return result
}
@@ -0,0 +1,21 @@
/**
* Copyright (c) 2022 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 const logger = store => next => action => {
console.info(`logger: dispatch ${JSON.stringify(action)}, store: ${JSON.stringify(store.getState())}`)
let result = next(action)
console.info(`logger: new state ${JSON.stringify(store.getState())}`)
return result
}
@@ -0,0 +1,40 @@
/**
* Copyright (c) 2022 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 {ACTION_CHANGE_PREVIEW_SIZE, ACTION_CHANGE_SHUTTER_BUTTON} from '../actions/ModeChange.ets'
import {UIDATA_TAB_ITEM} from '../actions/UiData.ets'
let initState = {
number: 154,
res: "app.media.icon",
tabItem: ['', 'flash', 'zoom', 'focus', 'setup']
}
export default function ModeChangeReducer(state = initState, action: {
type: string,
data: any
}) {
switch (action.type) {
case ACTION_CHANGE_PREVIEW_SIZE:
return { ...state, number: action.data.size}
case ACTION_CHANGE_SHUTTER_BUTTON:
return { ...state, res: action.data.res}
case UIDATA_TAB_ITEM:
return { ...state, tabItem: action.data}
default:
return state;
}
return state;
}
@@ -0,0 +1,8 @@
{
"string": [
{
"name": "commonutil_library",
"value": "commonutil_library"
}
]
}
-2
View File
@@ -1,2 +0,0 @@
/build
/.preview
-11
View File
@@ -1,11 +0,0 @@
apply plugin: 'com.huawei.ohos.hap'
ohos {
compileSdkVersion 6
defaultConfig {
compatibleSdkVersion 6
}
supportSystem "standard"
}
dependencies {
}
-35
View File
@@ -1,35 +0,0 @@
/*
* Copyright (c) 2021 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 PreviewModel from '../default/model/PreviewModel.js';
import RemoteDeviceModel from './model/RemoteDeviceModel.js';
import KvStoreModel from './model/KvStoreModel.js';
import LogUtil from '../default/common/utils/LogUtil.js';
let mLogUtil = new LogUtil();
export default {
data: {
previewModel: new PreviewModel(),
remoteDeviceModel: new RemoteDeviceModel(),
kvStoreModel: new KvStoreModel()
},
onCreate() {
mLogUtil.cameraInfo('AceApplication onCreate');
},
onDestroy() {
mLogUtil.cameraInfo('AceApplication onDestroy');
}
};
@@ -1,53 +0,0 @@
/*
* Copyright (c) 2021 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 '../../css/CommonPageStyle.css';
.DialogDiv {
flex-direction: column;
align-items: center;
}
.DialogTitleText {
width: 86.8%;
font-weight: 600;
}
.InnerBtn {
width: 80%;
justify-content: space-around;
align-items: center;
}
.DialogCancelButton {
width: 100%;
}
.DialogDeviceList {
width: 86.8%;
}
.DeviceListItem {
width: 100%;
flex-direction: row;
align-items: center;
justify-content: space-between;
}
.DeviceItemTitle {
width: 80%;
height: 100%;
text-align: start;
}
@@ -1,42 +0,0 @@
<!--
/*
* Copyright (c) 2021 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.
*/
-->
<div>
<dialog if="{{ dialogWidth !== 0 }}" id="ContinueAbilityDialog" style="width : {{ dialogWidth }} px;"
class="DialogMain" oncancel="cancelDialog">
<div class="DialogDiv">
<text class="DialogTitleText" style="height : {{ dialogTitleTextHeight }} px;
font-size : {{ dialogTitleTextFontSize }} px;">{{ $t('strings.choose_device') }}</text>
<list class="DialogDeviceList" divider="true" style="max-height : {{ dialogDeviceListMaxHeight }} px;">
<list-item for="{{ deviceList }}" class="DeviceListItem"
style="height : {{ deviceListItemHeight }} px;">
<label class="DeviceItemTitle" target="{{ $item.id }}"
style="font-size : {{ deviceItemTitleFontSize }} px;">{{ $item.name }}</label>
<input class="DeviceItemRadio" type="radio" checked="{{ $item.id == presentDeviceId }}"
id="{{ $item.id }}"
name="{{ $item.listName }}" value="{{ $item.id }}"
onchange="onRadioChange({{ $item.id }})"></input>
</list-item>
</list>
<div class="InnerBtn" style="height : {{ innerBtnHeight }} px;">
<button class="DialogCancelButton" type="text" style="font-size : {{ dialogCancelButtonFontSize }} px;"
value="{{ $t('strings.restore_defaults_dialog_cancel') }}"
onclick="onDismissDialogClicked"></button>
</div>
</div>
</dialog>
</div>
@@ -1,141 +0,0 @@
/*
* Copyright (c) 2021 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 LogUtil from '../../../common/utils/LogUtil.js';
import DateTimeUtil from '../../utils/DateTimeUtil.js';
let mLogUtil = new LogUtil();
let mDateTimeUtil = new DateTimeUtil();
export default {
props: {
openDeviceListDialog: {
default: false,
}
},
data: {
presentDeviceId: 'localhost',
isDeviceListDialogOpen: false,
deviceList: [],
dialogWidth: 0,
dialogTitleTextHeight: 0,
dialogTitleTextFontSize: 0,
innerBtnHeight: 0,
dialogCancelButtonFontSize: 0,
dialogDeviceListMaxHeight: 0,
deviceListItemHeight: 0,
deviceItemTitleFontSize: 0
},
onInit() {
mLogUtil.cameraInfo('openDeviceListDialog onInit begin.');
this.$watch('openDeviceListDialog', (newV, oldV) => {
mLogUtil.cameraInfo(`openDeviceListDialog newV: ${newV} oldV: ${oldV}`);
if (newV && !this.isDeviceListDialogOpen) {
this.openDialog();
}
if (!newV && this.isDeviceListDialogOpen) {
this.dismissDialog();
}
});
this.$app.$def.data.previewModel.getDialogStyle((data) => {
mLogUtil.cameraInfo(`openDeviceListDialog onInit dialogStyle data= ${JSON.stringify(data)}`);
this.dialogWidth = data.dialogWidth;
this.dialogTitleTextHeight = data.dialogTitleTextHeight;
this.dialogTitleTextFontSize = data.dialogTitleTextFontSize;
this.innerBtnHeight = data.innerBtnHeight;
this.dialogCancelButtonFontSize = data.dialogCancelButtonFontSize;
this.dialogDeviceListMaxHeight = data.dialogDeviceListMaxHeight;
this.deviceListItemHeight = data.deviceListItemHeight;
this.deviceItemTitleFontSize = data.deviceItemTitleFontSize;
mLogUtil.cameraInfo('openDeviceListDialog onInit dialogStyle end');
});
mLogUtil.cameraInfo('openDeviceListDialog onInit end.');
},
onDestroy() {
mLogUtil.cameraInfo('openDeviceListDialog onDestroy begin.');
this.dismissDialog();
mLogUtil.cameraInfo('openDeviceListDialog onDestroy end.');
},
onRadioChange(value, e) {
mLogUtil.cameraInfo('radioChange begin.');
if (value === e.value) {
mLogUtil.cameraInfo('onRadioChange');
this.$emit('deviceListRadioChange', {
inputValue: value,
event: e,
deviceList: this.deviceList
});
}
mLogUtil.cameraInfo('radioChange end.');
},
openDialog() {
mLogUtil.cameraInfo('openDialog begin.');
let self = this;
let curRandom = Math.random();
let curTime = mDateTimeUtil.getTime();
let splitTime = curTime.split(':').join('');
let curDay = mDateTimeUtil.getDate();
let splitDay = curDay.split('-').join('');
let curListName = `${splitDay}` + `${splitTime}` + `${curRandom}`;
this.deviceList = [{
name: this.$t('strings.localhost_front'),
id: 'localhost',
listName: curListName
}];
this.$app.$def.data.remoteDeviceModel.registerDeviceListCallback(() => {
mLogUtil.cameraInfo('CameraDeviceList on remote device updated');
mLogUtil.cameraInfo(`count= ${this.$app.$def.data.remoteDeviceModel.deviceList.length}`);
var list = [];
list[0] = self.deviceList[0];
for (let [item, index] of new Map(
this.$app.$def.data.remoteDeviceModel.deviceList.map(
(item, i) => [item, i]))) {
mLogUtil.cameraInfo(`CameraDevice ${index} / ${item.deviceId}
deviceName= ${item.deviceName} deviceType= ${item.deviceType}`);
list[index + 1] = {
name: item.deviceName,
id: item.deviceId,
listName: curListName
};
}
self.deviceList = list;
});
this.presentDeviceId = this.$app.$def.data.remoteDeviceModel.getCurrentDeviceId();
mLogUtil.cameraInfo(`switchCamera presentDeviceId: ${this.presentDeviceId}`);
this.isDeviceListDialogOpen = true;
this.$element('ContinueAbilityDialog').show();
mLogUtil.cameraInfo('openDialog end.');
},
cancelDialog() {
mLogUtil.cameraInfo('cancelDialog begin.');
this.isDeviceListDialogOpen = false;
this.$emit('deviceListDialogCancel');
this.$app.$def.data.remoteDeviceModel.unregisterDeviceListCallback();
mLogUtil.cameraInfo('cancelDialog end.');
},
onDismissDialogClicked() {
mLogUtil.cameraInfo('onDismissDialogClicked begin.');
this.dismissDialog();
mLogUtil.cameraInfo('onDismissDialogClicked end.');
},
dismissDialog() {
mLogUtil.cameraInfo('dismissDialog begin.');
this.$emit('deviceListDialogCancel');
this.isDeviceListDialogOpen = false;
this.$element('ContinueAbilityDialog').close();
this.$app.$def.data.remoteDeviceModel.unregisterDeviceListCallback();
mLogUtil.cameraInfo('dismissDialog end.');
}
};
@@ -1,63 +0,0 @@
/*
* Copyright (c) 2021 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.
*/
.SwitchCameraWrap {
justify-content: center;
align-items: center;
position: relative;
}
.SmallSwitchCamera {
background-color: transparent;
}
.SwitchCameraCircle {
background-color: transparent;
}
.ShadowTwo {
/* box-shadow: 0px 0px 5px 0px rgba(0,0,0,0.25);*/
}
.BorderStyle {
border-style: solid;
border-color: #fff;
}
.Container {
width: 100%;
height: 100%;
flex-direction: column;
align-items: center;
background-color: #000;
}
.Shoot {
margin-left: 11.66%;
margin-right: 11.66%;
background-color: transparent;
}
.DisableStyle {
opacity: .4;
}
.EnableStyle {
opacity: 1;
}
.OpacityHide {
opacity: 0;
}
@@ -1,55 +0,0 @@
/*
* Copyright (c) 2021 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 LogUtil from '../utils/LogUtil.js';
let mLogUtil = new LogUtil();
export default class DateTimeUtil {
getTime() {
mLogUtil.cameraInfo('getTime begin.');
const DATETIME = new Date();
const HOURS = DATETIME.getHours();
const MINUTES = DATETIME.getMinutes();
const SECONDS = DATETIME.getSeconds();
mLogUtil.cameraInfo('getTime end.');
return this.concatTime(HOURS, MINUTES, SECONDS);
}
getDate() {
mLogUtil.cameraInfo('getDate begin.');
const DATETIME = new Date();
const YEAR = DATETIME.getFullYear();
const MONTH = DATETIME.getMonth() + 1;
const DAY = DATETIME.getDate();
mLogUtil.cameraInfo('getDate end.');
return this.concatDate(YEAR, MONTH, DAY);
}
fill(value) {
mLogUtil.cameraInfo('fill begin.');
return (value > 9 ? '' : '0') + value;
}
concatDate(year, month, date) {
mLogUtil.cameraInfo('concatDate begin.');
return `${year}-${month}-${date}`;
}
concatTime(hours, minutes, seconds) {
mLogUtil.cameraInfo('concatTime begin.');
return `${this.fill(hours)}:${this.fill(minutes)}:${this.fill(seconds)}`;
}
}
@@ -1,41 +0,0 @@
/*
* Copyright (c) 2021 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 Router from '@system.router';
let RouterUtil = (function () {
return {
push: function (uri, params) {
Router.push({
uri: uri,
params: params
});
},
replace: function (uri, params) {
Router.replace({
uri: uri,
params: params
});
},
back: function () {
Router.back();
},
clear: function () {
Router.clear();
}
};
})();
export default RouterUtil;
-16
View File
@@ -1,16 +0,0 @@
{
"strings": {
"photoMode": "PHOTO",
"videoMode": "VIDEO",
"app_name": "app_name",
"photo": "photo",
"video": "video",
"choose_device": "choose_device",
"localhost_front": "This device",
"remote_camera_in_use": "Remote camera in use",
"network_interruption": "Network interruption",
"remote_camera_started_fail": "Remote camera started fail",
"restore_defaults_dialog_confirm": "Restore defaults dialog confirm",
"restore_defaults_dialog_cancel": "Restore defaults dialog cancel"
}
}
-16
View File
@@ -1,16 +0,0 @@
{
"strings": {
"photoMode": "拍照",
"videoMode": "录像",
"app_name": "相机",
"photo": "拍照",
"video": "录像",
"choose_device": "选择设备",
"localhost_front": "本机",
"remote_camera_in_use": "正在使用其他摄像头",
"network_interruption": "网络中断",
"remote_camera_started_fail": "对端设备未响应",
"restore_defaults_dialog_confirm": "确认",
"restore_defaults_dialog_cancel": "取消"
}
}
@@ -1,171 +0,0 @@
/*
* Copyright (c) 2021 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 DistributedData from '@ohos.data.distributeddata';
import LogUtil from '../common/utils/LogUtil.js';
import DateTimeUtil from '../common/utils/DateTimeUtil.js';
let mLogUtil = new LogUtil();
let mDateTimeUtil = new DateTimeUtil();
const STORE_ID = 'camera_kv_store';
export default class KvStoreModel {
kvManager;
kvStore;
listenerList = [];
constructor() {
}
createKvStore(callback) {
if (typeof (this.kvStore) === 'undefined') {
var config = {
bundleName: 'com.ohos.camera',
userInfo: {
userId: '0',
userType: 0
}
};
let self = this;
mLogUtil.cameraInfo('Camera[KvStoreModel] createKVManager begin');
DistributedData.createKVManager(config).then((manager) => {
mLogUtil.cameraInfo(`Camera[KvStoreModel] createKVManager success, kvManager
${JSON.stringify(manager)}`);
self.kvManager = manager;
var options = {
createIfMissing: true,
encrypt: false,
backup: false,
autoSync: true,
kvStoreType: 1,
schema: '',
securityLevel: 3,
};
mLogUtil.cameraInfo('Camera[KvStoreModel] kvManager.getKVStore begin');
self.kvManager.getKVStore(STORE_ID, options).then((store) => {
mLogUtil.cameraInfo(`Camera[KvStoreModel] getKVStore success, kvStore=${store}`);
self.kvStore = store;
callback();
});
mLogUtil.cameraInfo('Camera[KvStoreModel] kvManager.getKVStore end');
});
mLogUtil.cameraInfo('Camera[KvStoreModel] createKVManager end');
} else {
callback();
}
}
broadcastMessage(msg) {
mLogUtil.cameraInfo('broadcastMessage begin.');
mLogUtil.cameraInfo(` Camera[KvStoreModel] broadcastMessage${msg}`);
let self = this;
var num = self.getBroadcastId();
this.createKvStore(() => {
self.put(msg, num);
});
mLogUtil.cameraInfo('broadcastMessage end.');
}
put(key, value) {
mLogUtil.cameraInfo(`Camera[KvStoreModel] kvStore.put key ${key},value ${value}`);
this.kvStore.put(key, value).then((data) => {
this.kvStore.get(key).then((data) => {
mLogUtil.cameraInfo(`Camera[KvStoreModel] kvStore.get key ${key},
data ${JSON.stringify(data)}`);
});
mLogUtil.cameraInfo(`Camera[KvStoreModel] kvStore.put key ${key}, finished,
data ${JSON.stringify(data)}`);
}).catch((err) => {
mLogUtil.cameraError(`Camera[KvStoreModel] kvStore.put key ${key},
failed ${JSON.stringify(err)}`);
});
}
setOnMessageReceivedListener(msg, callback) {
mLogUtil.cameraInfo(`Camera[KvStoreModel] setOnMessageReceivedListener ${msg}`);
let self = this;
this.createKvStore(() => {
mLogUtil.cameraInfo(`KvStoreModel createKvStore listenerList= ${JSON.stringify(self.listenerList)}`);
if (self.listenerList.length !== 0) {
self.listenerList[self.listenerList.length] = {
receivedMsg: msg,
receivedCallback: callback
};
return;
}
self.listenerList[0] = {
receivedMsg: msg,
receivedCallback: callback
};
mLogUtil.cameraInfo(`Camera[KvStoreModel] kvStore.on(dataChange) ${JSON.stringify(self.listenerList[0])}`);
self.kvStore.on('dataChange', 1, (data) => {
setTimeout(() => {
mLogUtil.cameraInfo(`KvStoreModel dataChange ${JSON.stringify(data)}`);
mLogUtil.cameraInfo(`KvStoreModel dataChange listenerList= ${JSON.stringify(self.listenerList)}`);
for (let item of data.insertEntries) {
for (let prop of self.listenerList) {
if (item.key === prop.receivedMsg) {
mLogUtil.cameraInfo(`Camera insertEntries receive ${prop.msg} = ${item.value}`);
prop.receivedCallback();
}
}
}
for (let item of data.updateEntries) {
for (let prop of self.listenerList) {
if (item.key === prop.receivedMsg) {
mLogUtil.cameraInfo(`Camera updateEntries receive ${prop.msg} = ${item.value}`);
prop.receivedCallback();
}
}
}
}, 0);
});
mLogUtil.cameraInfo('Camera[KvStoreModel] kvStore.on(dataChange) end');
});
mLogUtil.cameraInfo('setOnMessageReceivedListener end.');
}
setOffMessageReceivedListener() {
mLogUtil.cameraInfo('setOffMessageReceivedListener begin.');
this.listenerList = [];
mLogUtil.cameraInfo('setOffMessageReceivedListener end.');
}
messageData() {
mLogUtil.cameraInfo('messageData begin.');
var data = {
msgFromDistributedTakePhoto: 'msgFromDistributedTakePhoto',
msgFromDistributedBack: 'msgFromDistributedBack',
msgFromDistributedQuit: 'msgFromDistributedQuit',
msgFromResponderReady: 'msgFromResponderReady',
msgFromResponderBack: 'msgFromResponderBack',
msgFromResponderQuit: 'msgFromResponderQuit'
};
mLogUtil.cameraInfo(`messageData data: ${data}`);
return data;
}
getBroadcastId() {
mLogUtil.cameraInfo('getBroadcastId begin.');
let broadcastRandom = Math.random();
let broadcastTime = mDateTimeUtil.getTime();
let splitBroadcastTime = broadcastTime.split(':').join('');
let broadcastDay = mDateTimeUtil.getDate();
let splitBroadcastDay = broadcastDay.split('-').join('');
let concatBroadcastId = `${splitBroadcastDay}` + `${splitBroadcastTime}` + `${broadcastRandom}`;
mLogUtil.cameraInfo('getBroadcastId end.');
return concatBroadcastId;
}
}
@@ -1,166 +0,0 @@
/*
* Copyright (c) 2021 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 LogUtil from '../common/utils/LogUtil.js';
import MediaLibrary from '@ohos.multimedia.medialibrary';
import display from '@ohos.display';
let mLogUtil = new LogUtil();
let mMediaImage = MediaLibrary.getMediaLibraryHelper();
const ALBUMNAME = 'camera';
const SYSTEM_UI_HEIGHT = 134;
const DESIGN_WIDTH = 720.0;
const PHOTO_ASPECT_RATIO_3_TO_4 = 0;
const PHOTO_ASPECT_RATIO_9_TO_16 = 1;
const PHOTO_ASPECT_RATIO_1_TO_1 = 2;
const PHOTO_ASPECT_RATIO_15_TO_26 = 3;
const MOVIE_ASPECT_RATIO_3_TO_4 = 4;
const MOVIE_ASPECT_RATIO_9_TO_16 = 5;
const MOVIE_ASPECT_RATIO_15_TO_26 = 6;
const PREVIEW_ASPECT_RATIO_LIST = [0.75, 0.5625, 1, 0.576923, 0.75, 0.5625, 0.576923];
export default class PreviewModel {
photoQuality = '';
previewAspectRatio = PHOTO_ASPECT_RATIO_3_TO_4;
proportion = 0;
screenHeight = 0;
screenWidth = 0;
dialogWidth = 0;
viewAreaStyle = {};
dialogStyle = {};
constructor() {
}
getDialogStyle(callback) {
mLogUtil.cameraInfo('getDialogStyle begin.');
if (this.dialogWidth !== 0) {
this.dialogStyle.dialogWidth = this.dialogWidth;
} else {
this.dialogStyle.dialogWidth = DESIGN_WIDTH * 0.694;
}
mLogUtil.cameraInfo(`getDialogStyle this.dialogWidth= ${this.dialogWidth}`);
this.dialogStyle.dialogTitleTextHeight = this.dialogStyle.dialogWidth * 0.16;
this.dialogStyle.dialogTitleTextFontSize = this.dialogStyle.dialogWidth * 0.064;
this.dialogStyle.innerBtnHeight = this.dialogStyle.dialogWidth * 0.24;
this.dialogStyle.dialogCancelButtonFontSize = this.dialogStyle.dialogWidth * 0.064;
this.dialogStyle.dialogDeviceListMaxHeight = this.dialogStyle.dialogWidth * 0.3;
this.dialogStyle.deviceListItemHeight = this.dialogStyle.dialogWidth * 0.16;
this.dialogStyle.deviceItemTitleFontSize = this.dialogStyle.dialogWidth * 0.06;
callback(this.dialogStyle);
mLogUtil.cameraInfo('getDialogStyle end');
}
getPreviewStyle(callback) {
mLogUtil.cameraInfo('getPreviewStyle begin.');
let self = this;
if (this.screenHeight === 0) {
display.getDefaultDisplay().then((dis) => {
mLogUtil.cameraInfo('getPreviewStyle getDefaultDisplay begin.');
self.proportion = DESIGN_WIDTH / dis.width;
self.screenHeight = (dis.height - SYSTEM_UI_HEIGHT) * self.proportion;
self.screenWidth = DESIGN_WIDTH;
self.getPreviewStyle_();
callback(self.viewAreaStyle);
mLogUtil.cameraInfo(`getPreviewStyle screenHeight=0'${JSON.stringify(self.viewAreaStyle)}`);
});
} else {
this.getPreviewStyle_();
callback(this.viewAreaStyle);
mLogUtil.cameraInfo(`getPreviewStyle screenHeight!=0'${JSON.stringify(self.viewAreaStyle)}`);
}
mLogUtil.cameraInfo('getPreviewStyle end');
}
getPreviewStyle_() {
mLogUtil.cameraInfo('getPreviewStyle_ begin.');
if (this.screenWidth / this.screenHeight <= PREVIEW_ASPECT_RATIO_LIST[this.previewAspectRatio]) {
mLogUtil.cameraInfo('getPreviewStyle_ without margin');
this.viewAreaStyle.previewAreaWidth = this.screenWidth;
this.viewAreaStyle.previewAreaHeight
= this.viewAreaStyle.previewAreaWidth / PREVIEW_ASPECT_RATIO_LIST[this.previewAspectRatio];
this.viewAreaStyle.footerWrapMargin = 0;
} else {
mLogUtil.cameraInfo('getPreviewStyle_ left and right margin');
this.viewAreaStyle.previewAreaHeight = this.screenHeight;
this.viewAreaStyle.previewAreaWidth
= this.viewAreaStyle.previewAreaHeight * PREVIEW_ASPECT_RATIO_LIST[this.previewAspectRatio];
this.viewAreaStyle.footerWrapMargin = (this.screenWidth - this.viewAreaStyle.previewAreaWidth) / 2;
}
this.dialogWidth = this.viewAreaStyle.previewAreaWidth * 0.694;
this.viewAreaStyle.cameraViewImageWidth = this.viewAreaStyle.previewAreaWidth * 0.1333;
this.viewAreaStyle.cameraViewImageHeight = this.viewAreaStyle.previewAreaWidth * 0.1111;
this.viewAreaStyle.remoteTitleTextFontSize = this.viewAreaStyle.previewAreaWidth * 0.0333;
this.viewAreaStyle.modeSwitchHeight = this.viewAreaStyle.previewAreaWidth * 0.1417;
this.viewAreaStyle.listItemMargin = this.viewAreaStyle.previewAreaWidth * 0.4;
this.viewAreaStyle.modeText = this.viewAreaStyle.previewAreaWidth * 0.0333;
this.viewAreaStyle.footBarHeight = this.viewAreaStyle.previewAreaWidth * 0.2344;
this.viewAreaStyle.imageStyleWidth = this.viewAreaStyle.previewAreaWidth * 0.1;
this.viewAreaStyle.imageStyleHeight = this.viewAreaStyle.imageStyleWidth;
this.viewAreaStyle.imageStyleBorderRadius = this.viewAreaStyle.previewAreaWidth * 0.05;
this.viewAreaStyle.shootWidth = this.viewAreaStyle.previewAreaWidth * 0.1889;
this.viewAreaStyle.shootHeight = this.viewAreaStyle.shootWidth;
this.viewAreaStyle.shootBorderRadius = this.viewAreaStyle.previewAreaWidth * 0.0944;
this.viewAreaStyle.smallSwitchCameraWidth = this.viewAreaStyle.previewAreaWidth * 0.0667;
this.viewAreaStyle.smallSwitchCameraHeight = this.viewAreaStyle.smallSwitchCameraWidth;
this.viewAreaStyle.smallSwitchCameraBorderRadius = this.viewAreaStyle.smallSwitchCameraWidth / 2;
this.viewAreaStyle.switchCameraCircleWidth = this.viewAreaStyle.previewAreaWidth * 0.1;
this.viewAreaStyle.switchCameraCircleHeight = this.viewAreaStyle.switchCameraCircleWidth;
this.viewAreaStyle.switchCameraCircleBorderRadius = this.viewAreaStyle.previewAreaWidth * 0.05;
this.viewAreaStyle.borderStyleBorder = this.viewAreaStyle.previewAreaWidth * 0.0056;
mLogUtil.cameraInfo('getPreviewStyle_ end');
}
setCurrentPreviewAspectRatio(aspectRatio) {
mLogUtil.cameraInfo('setCurrentPreviewAspectRatio begin.');
this.previewAspectRatio = aspectRatio;
mLogUtil.cameraInfo(`setCurrentPreviewAspectRatio end.${this.previewAspectRatio}`);
}
getCurrentPreviewAspectRatio() {
mLogUtil.cameraInfo(`setCurrentPreviewAspectRatio begin.${this.previewAspectRatio}`);
return this.previewAspectRatio;
}
getPhotoUri() {
return new Promise((resolve, reject) => {
mLogUtil.cameraInfo('PreviewModel getPhotoUri begin.');
const IMAGEARGS = {
selections: ALBUMNAME,
selectionArgs: ['imagealbum'],
};
let photoUri;
mMediaImage.getImageAssets(IMAGEARGS, (error, value) => {
if (error) {
mLogUtil.cameraError(`MediaLibrary: getImageAssets returned an error ${error.message}`);
}
if (value === undefined) {
mLogUtil.cameraError(`MediaLibrary: There are no images in ${IMAGEARGS.selections} folder`);
} else {
mLogUtil.cameraInfo(`MediaLibrary: There are images in ${IMAGEARGS.selections} folder`);
photoUri = `file://${value[0].URI}`;
mLogUtil.cameraInfo(`MediaLibrary: initialize photoUri ${photoUri}`);
}
resolve(photoUri);
});
});
}
getPhotoQuality() {
return this.photoQuality;
}
}
@@ -1,307 +0,0 @@
/*
* Copyright (c) 2021 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 deviceManager from '@ohos.distributedHardware.deviceManager';
import LogUtil from '../common/utils/LogUtil.js';
var SUBSCRIBE_ID = 100;
let mLogUtil = new LogUtil();
let cameraDeviceId = 'localhost';
export default class RemoteDeviceModel {
deviceList = [];
deviceTrustedInfo = [];
callbackForList;
callbackForStateChange;
authCallback = null;
#deviceManager;
constructor() {
}
registerDeviceManagerOn() {
mLogUtil.cameraInfo('registerDeviceManagerOn begin.');
let self = this;
this.#deviceManager.on('deviceStateChange', (data) => {
mLogUtil.cameraInfo(`Camera[RemoteDeviceModel] deviceStateChange data= ${JSON.stringify(data)}`);
let j = 0;
let deviceItemExist = false;
switch (data.action) {
case 0:
self.deviceStateChangeOnLine(self, j, deviceItemExist, data);
break;
case 2:
self.deviceStateChangeReady(self, data);
break;
case 1:
self.deviceStateChangeOffLine(self, data);
break;
default:
break;
}
mLogUtil.cameraInfo('deviceStateChange end.');
});
this.#deviceManager.on('deviceFound', (data) => {
mLogUtil.cameraInfo(`Camera[RemoteDeviceModel] deviceFound data= ${JSON.stringify(data)}`);
mLogUtil.cameraInfo(`Camera[RemoteDeviceModel] deviceFound self.deviceList= ${self.deviceList}`);
for (var i = 0; i < self.deviceList.length; i++) {
if (self.deviceList[i].deviceId === data.device.deviceId) {
mLogUtil.cameraInfo('Camera[RemoteDeviceModel] device founded, ignored');
return;
}
}
mLogUtil.cameraInfo(`Camera[RemoteDeviceModel] deviceFound data.device= ${JSON.stringify(data.device)}`);
self.deviceList[self.deviceList.length] = data.device;
mLogUtil.cameraInfo(`deviceList information ${JSON.stringify(self.deviceList)} ${self.deviceList.length}`);
self.deviceTrustedInfo[self.deviceTrustedInfo.length] = false;
self.callbackForList();
mLogUtil.cameraInfo('deviceFound end.');
});
this.#deviceManager.on('discoverFail', (data) => {
mLogUtil.cameraInfo(`Camera[RemoteDeviceModel] discoverFail data= ${JSON.stringify(data)}`);
});
this.#deviceManager.on('serviceDie', () => {
mLogUtil.cameraInfo('serviceDie begin.');
self.callbackForStateChange('SERVICEDIE', 0);
mLogUtil.cameraError('Camera[RemoteDeviceModel] serviceDie');
});
this.startDeviceDiscovery();
mLogUtil.cameraInfo('registerDeviceManagerOn end.');
}
deviceStateChangeOnLine(self, j, deviceItemExist, data) {
mLogUtil.cameraInfo('deviceStateChangeOnLine begin.');
for (let i = 0; i < self.deviceList.length; i++) {
if (self.deviceList[i].deviceName === data.device.deviceName) {
mLogUtil.cameraInfo('online device exists in deviceList');
j = i;
deviceItemExist = true;
break;
}
}
if (!deviceItemExist) {
mLogUtil.cameraInfo('online device do not exist in deviceList');
self.deviceList[self.deviceList.length] = data.device;
self.deviceTrustedInfo[self.deviceTrustedInfo.length] = true;
self.callbackForList();
} else if (!self.deviceTrustedInfo[j]) {
mLogUtil.cameraInfo('online device exists in deviceList and not auth');
self.deviceTrustedInfo[j] = true;
self.deviceList[j] = data.device;
if (self.authCallback != null) {
mLogUtil.cameraInfo('authCallback is define');
self.authCallback();
self.authCallback = null;
} else {
mLogUtil.cameraInfo('authCallback is unDefine');
}
}
mLogUtil.cameraInfo(`Camera[RemoteDeviceModel] online, list= ${JSON.stringify(self.deviceList)}`);
}
deviceStateChangeReady(self, data) {
mLogUtil.cameraInfo('deviceStateChangeReady begin.');
if (self.deviceList.length > 0) {
for (var i = 0; i < self.deviceList.length; i++) {
if (self.deviceList[i].deviceId === data.device.deviceId) {
self.deviceList[i] = data.device;
break;
}
}
}
mLogUtil.cameraInfo(`Camera[RemoteDeviceModel] change, list= ${JSON.stringify(self.deviceList)}`);
self.callbackForList();
mLogUtil.cameraInfo('deviceStateChangeReady end');
}
deviceStateChangeOffLine(self, data) {
mLogUtil.cameraInfo('deviceStateChangeOffLine begin');
if (self.deviceList.length > 0) {
for (var i = 0; i < self.deviceList.length; i++) {
if (self.deviceList[i].deviceId === data.device.deviceId) {
mLogUtil.cameraInfo(`RemoteDeviceModel offline deviceId: ${data.device.deviceId}`);
self.deviceList.splice(i, 1);
self.deviceTrustedInfo.splice(i, 1);
self.callbackForStateChange('OFFLINE', data.device.deviceId);
self.callbackForList();
break;
}
}
}
mLogUtil.cameraInfo(`Camera[RemoteDeviceModel] offline, list= ${JSON.stringify(data.device)}`);
}
startDeviceDiscovery() {
mLogUtil.cameraInfo('startDeviceDiscovery begin.');
SUBSCRIBE_ID = Math.floor(65536 * Math.random());
var info = {
subscribeId: SUBSCRIBE_ID,
mode: 0xAA,
medium: 2,
freq: 2,
isSameAccount: false,
isWakeRemote: true,
capability: 0
};
mLogUtil.cameraInfo(`Camera[RemoteDeviceModel] startDeviceDiscovery ${SUBSCRIBE_ID}`);
this.#deviceManager.startDeviceDiscovery(info);
mLogUtil.cameraInfo('startDeviceDiscovery end');
}
authDevice(deviceId, callback) {
mLogUtil.cameraInfo(`Camera[RemoteDeviceModel] authDevice ${deviceId}`);
for (var i = 0; i < this.deviceList.length; i++) {
if (this.deviceList[i].deviceId === deviceId) {
if (this.deviceTrustedInfo[i]) {
return;
}
mLogUtil.cameraInfo(JSON.stringify(this.deviceList[i]));
let self = this;
let j = i;
setTimeout(() => {
let extraInfo = {
"targetPkgName": 'com.ohos.camera',
"appName": 'Camera',
"appDescription": 'Camera player application',
"business": '0'
};
let authParam = {
"authType": 1,
"appIcon": '',
"appThumbnail": '',
"extraInfo": extraInfo
};
mLogUtil.cameraInfo(`Camera authenticateDevice= ${JSON.stringify(self.deviceList[j])}`);
self.#deviceManager.authenticateDevice(self.deviceList[j], authParam, (err, data) => {
mLogUtil.cameraInfo('authResult begin.');
mLogUtil.cameraInfo(`Camera[RemoteDeviceModel] authResult data= ${JSON.stringify(data)}`);
if (err) {
mLogUtil.cameraError(`authenticateDevice err: ${JSON.stringify(err)}`);
self.authCallback = null;
} else {
mLogUtil.cameraInfo(`authenticateDevice succeed, data= ${JSON.stringify(data)}`);
self.authCallback = callback;
}
mLogUtil.cameraInfo('authResult end.');
});
}, 0);
}
}
}
registerDeviceManagerOff() {
mLogUtil.cameraInfo('registerDeviceManagerOff begin.');
this.#deviceManager.stopDeviceDiscovery(SUBSCRIBE_ID);
this.#deviceManager.off('deviceStateChange');
this.#deviceManager.off('deviceFound');
this.#deviceManager.off('discoverFail');
this.#deviceManager.off('serviceDie');
mLogUtil.cameraInfo('registerDeviceManagerOff end.');
}
createDeviceManager(callback) {
mLogUtil.cameraInfo('createDeviceManager begin.');
if (typeof (this.#deviceManager) === 'undefined') {
let self = this;
deviceManager.createDeviceManager('com.ohos.camera', (error, value) => {
if (error) {
mLogUtil.cameraError('createDeviceManager failed.');
return;
}
self.#deviceManager = value;
callback();
mLogUtil.cameraError('Camera[RemoteDeviceModel] createDeviceManager callback returned');
mLogUtil.cameraError(`error= ${error} value= ${JSON.stringify(value)}`);
});
} else {
callback();
}
mLogUtil.cameraInfo('createDeviceManager end.');
}
registerDeviceListCallback(callback) {
mLogUtil.cameraInfo('Camera[RemoteDeviceModel] registerDeviceListCallback');
let self = this;
this.createDeviceManager(() => {
self.callbackForList = callback;
if (self.#deviceManager === undefined) {
mLogUtil.cameraError('Camera[RemoteDeviceModel] deviceManager has not initialized');
self.callbackForList();
return;
}
var list = self.#deviceManager.getTrustedDeviceListSync();
mLogUtil.cameraInfo(`getTrustedDeviceListSync end, deviceList= ${JSON.stringify(list)}`);
if (typeof (list) !== 'undefined' && typeof (list.length) !== 'undefined') {
self.deviceList = list;
for (let i = 0; i < self.deviceList.length; i++) {
self.deviceTrustedInfo[i] = true;
}
mLogUtil.cameraInfo(`self.deviceTrustedInfo ${JSON.stringify(self.deviceTrustedInfo)}`);
}
self.callbackForList();
self.registerDeviceManagerOff();
self.registerDeviceManagerOn();
});
mLogUtil.cameraInfo('registerDeviceListCallback end.');
}
unregisterDeviceListCallback() {
mLogUtil.cameraInfo('unregisterDeviceListCallback begin.');
this.callbackForList = null;
this.registerDeviceManagerOff();
if (this.callbackForStateChange !== null) {
this.registerDeviceManagerOn();
}
this.deviceList = [];
mLogUtil.cameraInfo('unregisterDeviceListCallback end.');
}
registerDeviceStateChangeCallback(callback) {
mLogUtil.cameraInfo('registerDeviceStateChangeCallback begin.');
let self = this;
this.createDeviceManager(() => {
self.callbackForStateChange = callback;
if (self.#deviceManager === undefined) {
mLogUtil.cameraError('Camera[RemoteDeviceModel] deviceManager has not initialized');
return;
}
self.registerDeviceManagerOff();
self.registerDeviceManagerOn();
});
mLogUtil.cameraInfo('registerDeviceStateChangeCallback end.');
}
unregisterDeviceStateChangeCallback() {
mLogUtil.cameraInfo('unregisterDeviceStateChangeCallback begin.');
this.callbackForStateChange = null;
this.registerDeviceManagerOff();
if (this.callbackForList !== null) {
this.registerDeviceManagerOn();
}
mLogUtil.cameraInfo('unregisterDeviceStateChangeCallback end.');
}
setCurrentDeviceId(deviceId) {
mLogUtil.cameraInfo('setCurrentDeviceId begin.');
cameraDeviceId = deviceId;
mLogUtil.cameraInfo(`setCurrentDeviceId end.${cameraDeviceId}`);
}
getCurrentDeviceId() {
mLogUtil.cameraInfo(`getCurrentDeviceId begin.${cameraDeviceId}`);
return cameraDeviceId;
}
}
@@ -1,50 +0,0 @@
/*
* Copyright (c) 2021 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/css/CommonPageStyle.css';
.CameraView {
flex-direction: row;
justify-content: center;
align-items: center;
background-color: #262626;
}
.DistributedFooter {
position: fixed;
left: 0;
bottom: 0;
flex-direction: column;
}
.RemoteTitle {
justify-content: center;
align-items: center;
}
.RemoteTitleText {
color: #FFF;
/* box-shadow: 0px 0px 5px 0px rgba(0,0,0,0.25);*/
}
.RemoteBar {
justify-content: center;
align-items: center;
flex-direction: row;
}
.ImageStyle {
opacity: .4;
}
@@ -1,57 +0,0 @@
<!--
/*
* Copyright (c) 2021 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.
*/
-->
<element name="deviceListDialog" src="../../common/component/DeviceListDialog/DeviceListDialog.hml"></element>
<div class="Container">
<div class="CameraView" style="width : {{ previewAreaWidth }} px; height : {{ previewAreaHeight }} px;">
<image style="width : {{ cameraViewImageWidth }} px; height : {{ cameraViewImageHeight }} px;"
src="../../common/media/camera.svg"></image>
</div>
<div class="DistributedFooter" style="margin-left : {{ footerWrapMargin }} px;">
<div class="RemoteTitle" style="width : {{ previewAreaWidth }} px; height : {{ modeSwitchHeight }} px;">
<text class="RemoteTitleText" style="font-size : {{ remoteTitleTextFontSize }} px;">
{{ $t('strings.remote_camera_in_use') }}</text>
</div>
<div class="RemoteBar" style="width : {{ previewAreaWidth }} px; height : {{ footBarHeight }} px;">
<image class="ImageStyle ShadowTwo" src="../../common/media/ic_camera_thumbnail_default_white.svg"
style="width : {{ imageStyleWidth }} px; height : {{ imageStyleHeight }} px;
border-radius : {{ imageStyleBorderRadius }} px;"></image>
<button class="Shoot ShadowTwo {{ isTouchPhoto ? 'DisableStyle' : 'EnableStyle' }}"
style="width : {{ shootWidth }} px; height : {{ shootHeight }} px;
icon-width : {{ shootWidth }} px; icon-height : {{ shootHeight }} px;
border-radius : {{ shootBorderRadius }} px;"
ontouchstart="onTouchStart" ontouchend="onTouchEnd" type="circle"
icon="/common/media/take_photo_normal.svg"></button>
<stack class="SwitchCameraWrap">
<button class="SmallSwitchCamera ShadowTwo" type="circle" icon="/common/media/small_switch_camera.svg"
style="width : {{ smallSwitchCameraWidth }} px; height : {{ smallSwitchCameraHeight }} px;
icon-width : {{ smallSwitchCameraWidth }} px;
icon-height : {{ smallSwitchCameraHeight }} px;
border-radius : {{ smallSwitchCameraBorderRadius }} px;">
</button>
<div class="SwitchCameraCircle BorderStyle" onclick="switchCamera"
style="width : {{ switchCameraCircleWidth }} px; height : {{ switchCameraCircleHeight }} px;
border-radius : {{ switchCameraCircleBorderRadius }} px;
border-width : {{ borderStyleBorder }} px;"></div>
</stack>
<deviceListDialog if="{{ previewAreaWidth !== 0 }}" open-device-list-dialog="{{ isDeviceListDialogOpen }}"
@device-list-dialog-cancel="deviceListDialogCancel"
@device-list-radio-change="deviceListRadioChange"></deviceListDialog>
</div>
</div>
</div>
@@ -1,187 +0,0 @@
/*
* Copyright (c) 2021 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 LogUtil from '../../common/utils/LogUtil.js';
import DistributedPresenter from '../../presenter/distributedPresenter/DistributedPresenter.js';
import Prompt from '@system.prompt';
import RouterUtil from '../../common/utils/RouterUtil.js';
import PageData from '../../common/constants/PageData.js';
const PREVIEW_VIEW = PageData.PREVIEW_PAGE;
let mLogUtil = new LogUtil();
let mDistributedPresenter;
export default {
data: {
isTouchPhoto: false,
isPromptDialogShow: false,
isDeviceListDialogOpen: false,
previewAreaWidth: 0,
previewAreaHeight: 0,
cameraViewImageWidth: 0,
cameraViewImageHeight: 0,
footerWrapMargin: 0,
modeSwitchHeight: 0,
remoteTitleTextFontSize: 0,
footBarHeight: 0,
imageStyleWidth: 0,
imageStyleHeight: 0,
imageStyleBorderRadius: 0,
shootWidth: 0,
shootHeight: 0,
shootBorderRadius: 0,
smallSwitchCameraWidth: 0,
smallSwitchCameraHeight: 0,
smallSwitchCameraBorderRadius: 0,
switchCameraCircleWidth: 0,
switchCameraCircleHeight: 0,
switchCameraCircleBorderRadius: 0,
borderStyleBorder: 0
},
onInit() {
mLogUtil.cameraInfo('DistributedView onInit begin.');
mDistributedPresenter = new DistributedPresenter(
this.$app.$def.data.previewModel,
this.$app.$def.data.kvStoreModel,
this.$app.$def.data.remoteDeviceModel);
mDistributedPresenter.registerDeviceStateChangeCallback((action, deviceId) => {
mLogUtil.cameraInfo(`DistributedView on device state changed ${deviceId} , action ${action}`);
switch (action) {
case 'OFFLINE':
if (mDistributedPresenter.getCurrentDeviceId() === deviceId) {
this.promptShowDialog();
setTimeout(() => {
this.startPreviewView();
}, 3000);
}
break;
default:
break;
}
});
mDistributedPresenter.getPreviewStyle((data) => {
mLogUtil.cameraInfo(`PreviewView onInit begin getPreviewStyle= ${JSON.stringify(data)}`);
this.previewAreaHeight = data.previewAreaHeight;
this.previewAreaWidth = data.previewAreaWidth;
this.cameraViewImageWidth = data.cameraViewImageWidth;
this.cameraViewImageHeight = data.cameraViewImageHeight;
this.footerWrapMargin = data.footerWrapMargin;
this.modeSwitchHeight = data.modeSwitchHeight;
this.remoteTitleTextFontSize = data.remoteTitleTextFontSize;
this.footBarHeight = data.footBarHeight;
this.imageStyleWidth = data.imageStyleWidth;
this.imageStyleHeight = data.imageStyleHeight;
this.imageStyleBorderRadius = data.imageStyleBorderRadius;
this.shootWidth = data.shootWidth;
this.shootHeight = data.shootHeight;
this.shootBorderRadius = data.shootBorderRadius;
this.smallSwitchCameraWidth = data.smallSwitchCameraWidth;
this.smallSwitchCameraHeight = data.smallSwitchCameraHeight;
this.smallSwitchCameraBorderRadius = data.smallSwitchCameraBorderRadius;
this.switchCameraCircleWidth = data.switchCameraCircleWidth;
this.switchCameraCircleHeight = data.switchCameraCircleHeight;
this.switchCameraCircleBorderRadius = data.switchCameraCircleBorderRadius;
this.borderStyleBorder = data.borderStyleBorder;
mLogUtil.cameraInfo(`PreviewView onInit end getPreviewStyle= ${JSON.stringify(data)}`);
});
mLogUtil.cameraInfo('DistributedView onInit end.');
},
onDestroy() {
mLogUtil.cameraInfo('DistributedView onDestroy begin.');
mDistributedPresenter.stopRemoteCamera();
mLogUtil.cameraInfo('DistributedView onDestroy end.');
},
onBackPress() {
mLogUtil.cameraInfo('DistributedView onBackPress begin.');
if (this.isPromptDialogShow) {
mLogUtil.cameraInfo('DistributedView onBackPress PromptDialogExist');
return true;
} else if (this.isDeviceListDialogOpen) {
mLogUtil.cameraInfo('DistributedView onBackPress DialogComponentExist');
this.isDeviceListDialogOpen = false;
return true;
} else {
mLogUtil.cameraInfo('DistributedView Router begin.');
this.startPreviewView();
mLogUtil.cameraInfo('DistributedView Router end.');
return true;
}
mLogUtil.cameraInfo('DistributedView onBackPress end.');
},
deviceListDialogCancel() {
mLogUtil.cameraInfo('DistributedView deviceListDialogCancel begin.');
this.isDeviceListDialogOpen = false;
mLogUtil.cameraInfo('DistributedView deviceListDialogCancel end.');
},
switchCamera() {
mLogUtil.cameraInfo('DistributedView switchCamera begin.');
this.isDeviceListDialogOpen = true;
mLogUtil.cameraInfo('DistributedView switchCamera end.');
},
onTouchStart() {
mLogUtil.cameraInfo('onTouchStart begin.');
mDistributedPresenter.remoteTakePhoto();
this.isTouchPhoto = true;
mLogUtil.cameraInfo('onTouchStart end.');
},
onTouchEnd() {
mLogUtil.cameraInfo('onTouchEnd begin.');
this.isTouchPhoto = false;
mLogUtil.cameraInfo('onTouchEnd end.');
},
deviceListRadioChange(e) {
mLogUtil.cameraInfo('deviceListRadioChange begin.');
var inputValue = e.detail.inputValue;
var event = e.detail.event;
mLogUtil.cameraInfo(`DistributedView Camera inputValue ${JSON.stringify(inputValue)}`);
mLogUtil.cameraInfo(`DistributedView Camera event ${JSON.stringify(event)}`);
if (inputValue === event.value) {
mLogUtil.cameraInfo('DistributedView equal');
if (event.value === 'localhost') {
this.deviceListDialogCancel();
this.startPreviewView();
}
}
mLogUtil.cameraInfo('deviceListRadioChange end.');
},
promptShowDialog() {
mLogUtil.cameraInfo('promptShowDialog begin.');
let self = this;
this.isPromptDialogShow = true;
Prompt.showDialog({
message: self.$t('strings.network_interruption'),
buttons:
[{
text: self.$t('strings.restore_defaults_dialog_confirm'),
color: '#666666',
}],
success: function (data) {
self.isPromptDialogShow = false;
mLogUtil.cameraInfo(`dialog success callbackclick button : ${data.index}`);
},
cancel: function () {
self.isPromptDialogShow = false;
mLogUtil.cameraInfo('dialog cancel callback');
},
});
mLogUtil.cameraInfo('promptShowDialog end.');
},
startPreviewView() {
mLogUtil.cameraInfo('DistributedView startPreviewView begin.');
RouterUtil.replace(PREVIEW_VIEW);
mDistributedPresenter.setCurrentDeviceId('localhost');
mLogUtil.cameraInfo('DistributedView startPreviewView end.');
}
};
@@ -1,104 +0,0 @@
/*
* Copyright (c) 2021 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/css/CommonPageStyle.css';
.FlashingStyle {
background-color: #000;
}
.PreviewArea {
display: flex;
flex-direction: row;
}
.CameraPic {
filter: blur(50px);
}
.ModeSwitch {
position: fixed;
left: 0;
align-items: center;
flex-direction: column;
background-color: transparent;
}
.SpotWrap {
position: absolute;
left: 0;
top: 72.55%;
width: 100%;
height: 9.8%;
justify-content: center;
align-items: center;
}
.Spot {
background-color: #006cde;
width: 1.38%;
height: 100%;
border-radius: 6px;
}
.List {
flex-direction: row;
width: 100%;
height: 100%;
}
.ListItem {
align-items: center;
justify-content: center;
width: 20%;
}
.ListItemWidth {
width: 100%;
}
.FootBar {
position: fixed;
bottom: 0;
left: 0;
justify-content: center;
align-items: center;
background-color: transparent;
}
.CloseRecorderThumbnail {
background-color: #FFF;
}
.AnimationStyle {
animation-name: ScaleDraw;
animation-timing-function: ease-in;
animation-iteration-count: 1;
animation-duration: 250ms;
}
.ModeText {
color: #FFF;
}
@keyframes ScaleDraw {
from {
transform: scale(1.5);
}
to {
transform: scale(1);
}
}
@@ -1,109 +0,0 @@
<!--
/*
* Copyright (c) 2021 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.
*/
-->
<element name="deviceListDialog" src="../../common/component/DeviceListDialog/DeviceListDialog.hml"></element>
<stack class="Container">
<div if="{{ previewAreaWidth !== 0 }}" class="PreviewArea"
style="width : {{ previewAreaWidth }} px; height : {{ previewAreaHeight }} px;">
<camera if="{{ isCreateCamera }}" id="CameraId" style="width : {{ previewAreaWidth }} px;
height : {{ previewAreaHeight }} px;"></camera>
<image if="{{ isShowHazyPicture }}" style="width : {{ previewAreaWidth }} px;
height : {{ previewAreaHeight }} px;" class="CameraPic" src="{{ hazyPictureUri }}"></image>
</div>
<div show="{{ isShowFlashingState }}" class="FlashingStyle" style="width : {{ previewAreaWidth }} px;
height : {{ previewAreaHeight }} px"></div>
<div class="ModeSwitch" style="width : {{ previewAreaWidth }} px; height : {{ modeSwitchHeight }} px;
bottom : {{ footBarHeight }} px; margin-left : {{ footerWrapMargin }} px;">
<list if="{{ whichPage === 'ResponderPreview' }}" class="List" id="List"
nitialindex="0" itemcenter="true" scrolleffect="no">
<list-item class="ListItem ListItemWidth">
<text style="font-weight : {{ photoFontWeight }} px; font-size : {{ modeText }} px;"
class="ModeText ShadowTwo">{{ $t('strings.photoMode') }}</text>
</list-item>
</list>
<list if="{{ whichPage !== 'ResponderPreview' && isVideoShoot }}" class="List" id="List"
ontouchend="listTouchEnd" onscroll="scroll" nitialindex="0" itemcenter="true" scrolleffect="no">
<list-item class="ListItem" onclick="jumpToPhoto" style="margin-left : {{ listItemMargin }} px;">
<text style="font-weight : {{ photoFontWeight }} px; font-size : {{ modeText }} px;"
class="ModeText ShadowTwo">{{ $t('strings.photoMode') }}</text>
</list-item>
<list-item class="ListItem" onclick="jumpToVideo" style="margin-right : {{ listItemMargin }} px;">
<text style="font-weight : {{ videoFontWeight }} px; font-size : {{ modeText }} px;"
class="ModeText ShadowTwo">{{ $t('strings.videoMode') }}</text>
</list-item>
</list>
<div if="{{ isVideoShoot }}" class="SpotWrap">
<div class="Spot ShadowTwo"></div>
</div>
</div>
<div class="FootBar"
style="width : {{ previewAreaWidth }} px; height : {{ footBarHeight }} px;
margin-left : {{ footerWrapMargin }} px;">
<stack class="ImageStyle" style="width : {{ imageStyleWidth }} px; height : {{ imageStyleHeight }} px;
border-radius : {{ imageStyleBorderRadius }} px;">
<div show="{{ isVideoStop && isVideoShootButton }}" class="ImageStyle
{{ isVideoStop ? 'CloseRecorderThumbnail' : '' }} {{ animationClassName }}"
style="width : {{ imageStyleWidth }} px; height : {{ imageStyleHeight }} px;
border-radius : {{ imageStyleBorderRadius }} px;"
onclick="jumpToAlbum">
</div>
<div if="{{ isVideoShoot && ! isVideoStop }}"
class="{{ photoUri === '/common/media/ic_camera_thumbnail_default_white.svg' ? '' : 'BorderStyle' }}"
style="border-width : {{ borderStyleBorder }} px; border-radius : {{ imageStyleBorderRadius }} px;">
<image class="ImageStyle ShadowTwo {{ animationClassName }}" src="{{ photoUri }}"
style="width : {{ imageStyleWidth }} px; height : {{ imageStyleHeight }} px;
border-radius : {{ imageStyleBorderRadius }} px;" onclick="jumpToAlbum"></image>
</div>
</stack>
<button class="Shoot ShadowTwo {{ isTouchPhoto ? 'DisableStyle' : 'EnableStyle' }}"
style="width : {{ shootWidth }} px; height : {{ shootHeight }} px; icon-width : {{ shootWidth }} px;
icon-height : {{ shootHeight }} px; border-radius : {{ shootBorderRadius }} px;"
ontouchstart="onTouchStartPhoto" ontouchend="onTouchEndPhoto" type="circle"
if="{{ isPhotoShootButton }}" icon="/common/media/take_photo_normal.svg"></button>
<button class="Shoot ShadowTwo" if="{{ isVideoShootButton }}"
style="width : {{ shootWidth }} px; height : {{ shootHeight }} px; icon-width : {{ shootWidth }} px;
icon-height : {{ shootHeight }} px; border-radius : {{ shootBorderRadius }} px;"
ontouchend="onTouchEndVideoStart" type="circle" icon="/common/media/take_video_normal.svg"></button>
<button class="Shoot ShadowTwo" if="{{ isVideoStopButton }}" ontouchend="onTouchEndVideoStop" type="circle"
style="width : {{ shootWidth }} px; height : {{ shootHeight }} px; icon-width : {{ shootWidth }} px;
icon-height : {{ shootHeight }} px; border-radius : {{ shootBorderRadius }} px;"
icon="/common/media/take_video_stop.svg"></button>
<div if="{{ mode === 'video' }}" class="SwitchCameraCircle"
style="width : {{ switchCameraCircleWidth }} px; height : {{ switchCameraCircleHeight }} px;
border-radius : {{ switchCameraCircleBorderRadius }} px;"></div>
<stack if="{{ mode === 'photo' }}"
class="SwitchCameraWrap {{ whichPage === 'ResponderPreview' ? 'DisableStyle' : '' }}">
<button class="SmallSwitchCamera ShadowTwo" type="circle" icon="/common/media/small_switch_camera.svg"
style="width : {{ smallSwitchCameraWidth }} px; height : {{ smallSwitchCameraHeight }} px;
icon-width : {{ smallSwitchCameraWidth }} px; icon-height : {{ smallSwitchCameraHeight }} px;
border-radius : {{ smallSwitchCameraBorderRadius }} px;">
</button>
<div if="{{ whichPage === 'ResponderPreview' }}" class="SwitchCameraCircle BorderStyle"
style="width : {{ switchCameraCircleWidth }} px; height : {{ switchCameraCircleHeight }} px;
border-radius : {{ switchCameraCircleBorderRadius }} px;
border-width : {{ borderStyleBorder }} px;"></div>
<div else class="SwitchCameraCircle BorderStyle" onclick="switchCamera"
style="width : {{ switchCameraCircleWidth }} px; height : {{ switchCameraCircleHeight }} px;
border-radius : {{ switchCameraCircleBorderRadius }} px;
border-width : {{ borderStyleBorder }} px;"></div>
</stack>
<deviceListDialog if="{{ previewAreaWidth !== 0 }}" open-device-list-dialog="{{ isDeviceListDialogOpen }}"
@device-list-dialog-cancel="deviceListDialogCancel"
@device-list-radio-change="deviceListRadioChange"></deviceListDialog>
</div>
</stack>
@@ -1,458 +0,0 @@
/*
* Copyright (c) 2021 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 LogUtil from '../../common/utils/LogUtil.js';
import PreviewPresenter from '../../presenter/previewPresenter/PreviewPresenter.js';
import featureAbility from '@ohos.ability.featureAbility';
import Prompt from '@system.prompt';
import RouterUtil from '../../common/utils/RouterUtil.js';
import PageData from '../../common/constants/PageData.js';
const DISTRIBUTED_VIEW = PageData.DISTRIBUTED_PAGE;
let mLogUtil = new LogUtil();
let mPreviewPresenter;
export default {
data: {
isTouchPhoto: false,
photoUri: '/common/media/ic_camera_thumbnail_default_white.svg',
newestPicUri: '/common/media/ic_camera_thumbnail_default_white.svg',
photoFontWeight: 600,
videoFontWeight: 400,
animationClassName: '',
isShowFlashingState: false,
isCreateCamera: true,
previewHeight: 960,
whichPage: 'DistributedPreview',
cameraStatus: 'DistributedPreview',
modeIndex: 0,
mode: 'photo',
scrollValue: 0,
isPhotoShootButton: true,
dialogMessage: '',
isPromptDialogShow: false,
isDeviceListDialogOpen: false,
isVideoShoot: true,
isVideoStopButton: false,
isVideoShootButton: false,
hazyPictureUri: '',
isShowHazyPicture: false,
isInSwitchingPreviewSize: false,
isVideoStop: false,
previewAreaWidth: 0,
previewAreaHeight: 0,
footerWrapMargin: 0,
modeSwitchHeight: 0,
listItemMargin: 0,
modeText: 0,
footBarHeight: 0,
imageStyleWidth: 0,
imageStyleHeight: 0,
imageStyleBorderRadius: 0,
shootWidth: 0,
shootHeight: 0,
shootBorderRadius: 0,
smallSwitchCameraWidth: 0,
smallSwitchCameraHeight: 0,
smallSwitchCameraBorderRadius: 0,
switchCameraCircleWidth: 0,
switchCameraCircleHeight: 0,
switchCameraCircleBorderRadius: 0,
borderStyleBorder: 0
},
onInit() {
mLogUtil.cameraInfo('PreviewView onInit begin.');
mPreviewPresenter = new PreviewPresenter(
this.$app.$def.data.previewModel,
this.$app.$def.data.kvStoreModel,
this.$app.$def.data.remoteDeviceModel);
featureAbility.getWant().then((want) => {
mLogUtil.cameraInfo(`onInit Camera featureAbility.getWant = ${JSON.stringify(want.parameters)}`);
switch (want.parameters.request) {
case 'startPhotoBack':
this.whichPage = 'ResponderPreview';
this.cameraStatus = 'ResponderPreview';
mLogUtil.cameraInfo('Camera featureAbility.getWant success');
break;
default:
this.cameraStatus = 'DistributedPreview';
break;
}
mLogUtil.cameraInfo('onInit getWant success');
this.responderPreviewStartedSuccess();
}).catch((error) => {
mLogUtil.cameraError(`Camera featureAbility.getWant fail ${error}`);
});
mPreviewPresenter.getPreviewStyle((data) => {
mLogUtil.cameraInfo(`PreviewView onInit begin getPreviewStyle= ${JSON.stringify(data)}`);
this.previewAreaHeight = data.previewAreaHeight;
this.previewAreaWidth = data.previewAreaWidth;
this.footerWrapMargin = data.footerWrapMargin;
this.modeSwitchHeight = data.modeSwitchHeight;
this.listItemMargin = data.listItemMargin;
this.modeText = data.modeText;
this.footBarHeight = data.footBarHeight;
this.imageStyleWidth = data.imageStyleWidth;
this.imageStyleHeight = data.imageStyleHeight;
this.imageStyleBorderRadius = data.imageStyleBorderRadius;
this.shootWidth = data.shootWidth;
this.shootHeight = data.shootHeight;
this.shootBorderRadius = data.shootBorderRadius;
this.smallSwitchCameraWidth = data.smallSwitchCameraWidth;
this.smallSwitchCameraHeight = data.smallSwitchCameraHeight;
this.smallSwitchCameraBorderRadius = data.smallSwitchCameraBorderRadius;
this.switchCameraCircleWidth = data.switchCameraCircleWidth;
this.switchCameraCircleHeight = data.switchCameraCircleHeight;
this.switchCameraCircleBorderRadius = data.switchCameraCircleBorderRadius;
this.borderStyleBorder = data.borderStyleBorder;
mLogUtil.cameraInfo(`PreviewView onInit end getPreviewStyle= ${JSON.stringify(data)}`);
});
mLogUtil.cameraInfo('PreviewView onInit end.');
},
onReady() {
},
onShow() {
mLogUtil.cameraInfo('PreviewView onShow begin.');
this.animationClassName = '';
let self = this;
this.photoUri = '/common/media/ic_camera_thumbnail_default_white.svg';
mPreviewPresenter.getPhotoUri().then((data) => {
if (data !== '') {
self.photoUri = data.replace('"', '').replace('"', '');
self.newestPicUri = self.photoUri;
}
mLogUtil.cameraInfo(`PreviewView onShow photoUri: ${this.photoUri}`);
});
mLogUtil.cameraInfo('PreviewView onShow end.');
},
onDestroy() {
mLogUtil.cameraInfo('PreviewView onDestroy begin.');
if (this.cameraStatus === 'ResponderPreview') {
mPreviewPresenter.remoteReturnBack();
}
mLogUtil.cameraInfo('PreviewView onDestroy end.');
},
onBackPress() {
mLogUtil.cameraInfo('PreviewView onBackPress begin.');
if (this.isPromptDialogShow) {
mLogUtil.cameraInfo('PreviewView isPromptDialogShow exist');
return true;
} else if (this.isDeviceListDialogOpen) {
mLogUtil.cameraInfo('PreviewView closeDialogComponent');
this.isDeviceListDialogOpen = false;
return true;
} else if (this.mode === 'video' && !this.isVideoShoot) {
this.onTouchEndVideoStop();
mLogUtil.cameraInfo('PreviewView onBackPress stopVideoShoot');
return true;
} else {
mLogUtil.cameraInfo('PreviewView onBackPress withoutDialog');
return false;
}
mLogUtil.cameraInfo('PreviewView onBackPress end.');
},
onNewRequest() {
mLogUtil.cameraInfo('PreviewView onNewRequest begin.');
featureAbility.getWant().then((want) => {
mLogUtil.cameraInfo(`onNewRequest Camera featureAbility.getWant = ${JSON.stringify(want.parameters)}`);
switch (want.parameters.request) {
case 'startPhotoBack':
this.whichPage = 'ResponderPreview';
this.cameraStatus = 'ResponderPreview';
mLogUtil.cameraInfo('Camera featureAbility.getWant success');
break;
default:
this.cameraStatus = 'DistributedPreview';
break;
}
mLogUtil.cameraInfo('onNewRequest getWant success');
this.responderPreviewStartedSuccess();
}).catch((error) => {
mLogUtil.cameraError(`Camera featureAbility.getWant fail ${error}`);
});
mLogUtil.cameraInfo('PreviewView onNewRequest end.');
},
responderPreviewStartedSuccess() {
let self = this;
mLogUtil.cameraInfo('PreviewView responderPreviewStartedSuccess begin.');
if (this.cameraStatus === 'ResponderPreview') {
mPreviewPresenter.previewStartedSuccess(this.$element('CameraId'), () => {
mLogUtil.cameraInfo('responderPreviewStartedSuccess onTouchStartPhoto.');
self.onTouchStartPhoto();
setTimeout(() => {
mLogUtil.cameraInfo('responderPreviewStartedSuccess onTouchEndPhoto.');
self.onTouchEndPhoto();
}, 200);
});
mPreviewPresenter.registerDeviceStateChangeCallback((action, deviceId) => {
mLogUtil.cameraInfo('PreviewView registerDeviceStateChangeCallback begin.');
switch (action) {
case 'OFFLINE':
this.promptShowDialog(self.$t('strings.network_interruption'));
setTimeout(() => {
featureAbility.terminateSelf((error) => {
mLogUtil.cameraError(`PreviewView terminateSelf finished, error= ${error}`);
});
}, 3000);
break;
default:
break;
}
});
}
mLogUtil.cameraInfo('PreviewView responderPreviewStartedSuccess end.');
},
videoStopDefault() {
mLogUtil.cameraInfo('videoStopDefault begin.');
this.isPhotoShootButton = false;
this.isVideoShootButton = true;
this.isVideoStopButton = false;
this.isVideoShoot = true;
this.isVideoStop = true;
mLogUtil.cameraInfo('videoStopDefault end.');
},
onTouchEndVideoStop() {
mLogUtil.cameraInfo('onTouchEndVideoStop begin.');
if (this.isInSwitchingPreviewSize) {
mLogUtil.cameraInfo('onTouchEndVideoStop finished, in switching preview size');
return;
}
mPreviewPresenter.closeRecorder(this.$element('CameraId')).then((object) => {
if (object.result === 'success') {
this.animationClassName = '';
this.animationClassName = 'AnimationStyle';
this.animationClassName = '';
this.videoStopDefault();
}
});
mLogUtil.cameraInfo('onTouchEndVideoStop end.');
},
onTouchEndVideoStart() {
mLogUtil.cameraInfo('onTouchEndVideoStart begin.');
if (this.isInSwitchingPreviewSize) {
mLogUtil.cameraInfo('onTouchEndVideoStart finished, in switching preview size');
return;
}
mPreviewPresenter.startRecorder(this.$element('CameraId'));
this.isPhotoShootButton = false;
this.isVideoShootButton = false;
this.isVideoStopButton = true;
this.isVideoShoot = false;
mLogUtil.cameraInfo('onTouchEndVideoStart end.');
},
jumpToPhoto() {
mLogUtil.cameraInfo('jumpToPhoto begin.');
let self = this;
if (self.mode === 'video') {
self.mode = 'photo';
self.isPhotoShootButton = true;
self.isVideoShootButton = false;
self.isVideoStopButton = false;
self.photoFontWeight = 600;
self.videoFontWeight = 400;
self.modeIndex = 0;
self.isVideoStop = false;
self.$element('List').scrollTo({
index: self.modeIndex
});
}
mLogUtil.cameraInfo('jumpToPhoto end.');
},
jumpToVideo() {
mLogUtil.cameraInfo('jumpToVideo begin.');
let self = this;
if (self.mode === 'photo') {
self.mode = 'video';
self.isPhotoShootButton = false;
self.isVideoShootButton = true;
self.isVideoStopButton = false;
self.photoFontWeight = 400;
self.videoFontWeight = 600;
self.modeIndex = 1;
self.isVideoStop = false;
self.$element('List').scrollTo({
index: self.modeIndex
});
}
mLogUtil.cameraInfo('jumpToVideo end.');
},
scroll({scrollX: scrollXValue, scrollState: stateValue}) {
mLogUtil.cameraInfo('scroll begin.');
let self = this;
self.scrollValue += scrollXValue;
mLogUtil.cameraInfo(`scroll data: scrollValue ${self.scrollValue} stateValue ${stateValue}`);
if (self.scrollValue < -50 && stateValue === 1 && self.mode === 'video') {
self.jumpToPhoto();
}
if (self.scrollValue > 50 && stateValue === 1 && self.mode === 'photo') {
self.jumpToVideo();
}
if (stateValue === 0) {
self.scrollValue = 0;
self.$element('List').scrollTo({
index: self.modeIndex
});
}
mLogUtil.cameraInfo('scroll end.');
},
switchCamera() {
mLogUtil.cameraInfo('PreviewView switchCamera begin.');
if (this.isInSwitchingPreviewSize) {
mLogUtil.cameraInfo('switchCamera finished, in switching preview size');
return;
}
this.isDeviceListDialogOpen = true;
mLogUtil.cameraInfo('PreviewView switchCamera end.');
},
setPreviewSize(height, thumbnailUri) {
mLogUtil.cameraInfo(`PreviewView setPreviewSize ${height}`);
this.stashedPreviewHeight = height;
if (this.isInSwitchingPreviewSize) {
mLogUtil.cameraInfo('PreviewView setPreviewSize finished, in switching preview size');
return;
}
this.isInSwitchingPreviewSize = true;
mPreviewPresenter.takePhoto(this.$element('CameraId')).then((object) => {
let self = this;
if (object.result === 'complete') {
self.hazyPictureUri = object.photoUri;
self.isShowHazyPicture = true;
self.isCreateCamera = false;
setTimeout(() => {
self.previewHeight = self.stashedPreviewHeight;
self.isCreateCamera = true;
self.isShowHazyPicture = false;
if (thumbnailUri) {
self.photoUri = thumbnailUri;
}
mPreviewPresenter.deleteAlbumAsset();
self.isInSwitchingPreviewSize = false;
mLogUtil.cameraInfo(`PreviewView openCamera previewHeight= ${self.previewHeight}`);
}, 1500);
} else {
self.isInSwitchingPreviewSize = false;
mLogUtil.cameraError('PreviewView setPreviewSize failed, generate preview frame failed');
}
});
},
jumpToAlbum() {
mLogUtil.cameraInfo('jumpToAlbum begin.');
if (this.isInSwitchingPreviewSize) {
mLogUtil.cameraInfo('jumpToAlbum finished, in switching preview size');
return;
}
mPreviewPresenter.jumpToAlbum();
mLogUtil.cameraInfo('jumpToAlbum end.');
},
onTouchStartPhoto() {
mLogUtil.cameraInfo('onTouchStartPhoto begin.');
if (this.isInSwitchingPreviewSize) {
mLogUtil.cameraInfo('onTouchStartPhoto finished, in switching preview size');
return;
}
this.isShowFlashingState = true;
setTimeout(() => {
this.isShowFlashingState = false;
}, 100);
mPreviewPresenter.takePhoto(this.$element('CameraId'), true).then((object) => {
if (object.result === 'success') {
this.photoUri = object.photoUri;
this.newestPicUri = this.photoUri;
this.animationClassName = '';
this.animationClassName = 'AnimationStyle';
this.animationClassName = '';
}
});
this.isTouchPhoto = true;
mLogUtil.cameraInfo('onTouchStartPhoto end.');
},
onTouchEndPhoto() {
mLogUtil.cameraInfo('onTouchEndPhoto begin.');
if (this.isInSwitchingPreviewSize) {
mLogUtil.cameraInfo('onTouchEndPhoto finished, in switching preview size');
return;
}
this.isTouchPhoto = false;
mLogUtil.cameraInfo('onTouchEndPhoto end.');
},
deviceListDialogCancel() {
mLogUtil.cameraInfo('PreviewView deviceListDialogCancel begin.');
this.isDeviceListDialogOpen = false;
mLogUtil.cameraInfo('PreviewView deviceListDialogCancel end.');
},
deviceListRadioChange(e) {
mLogUtil.cameraInfo('deviceListRadioChange begin.');
var inputValue = e.detail.inputValue;
var event = e.detail.event;
var deviceList = e.detail.deviceList;
mLogUtil.cameraInfo(`Camera[IndexPage] JSON.stringify inputValue ${JSON.stringify(inputValue)}`);
mLogUtil.cameraInfo(`Camera[IndexPage] JSON.stringify event ${JSON.stringify(event)}`);
mLogUtil.cameraInfo(`Camera[IndexPage] deviceList ${JSON.stringify(deviceList)}`);
let self = this;
mPreviewPresenter.startRemoteCamera(inputValue, event, deviceList, (data) => {
switch (data) {
case 'backToLocalhost':
break;
case 'remoteCameraStartedFail':
mLogUtil.cameraInfo('remoteCameraStartedFail begin.');
self.isDeviceListDialogOpen = false;
setTimeout(() => {
self.promptShowDialog(self.$t('strings.remote_camera_started_fail'));
}, 500);
mLogUtil.cameraInfo('remoteCameraStartedFail end.');
break;
case 'remoteCameraStartedSuccess':
mLogUtil.cameraInfo('remoteCameraStartedSuccess begin.');
self.startDistributedView();
mLogUtil.cameraInfo('remoteCameraStartedSuccess end.');
break;
default:
break;
}
});
mLogUtil.cameraInfo('deviceListRadioChange end.');
},
listTouchEnd() {
mLogUtil.cameraInfo('listTouchEnd begin.');
this.scrollValue = 0;
mLogUtil.cameraInfo('listTouchEnd end.');
},
promptShowDialog(message) {
mLogUtil.cameraInfo('promptShowDialog begin.');
this.isPromptDialogShow = true;
let self = this;
Prompt.showDialog({
message: message,
buttons:
[{
text: self.$t('strings.restore_defaults_dialog_confirm'),
color: '#666666',
}],
success: function (data) {
self.isPromptDialogShow = false;
mLogUtil.cameraInfo(`dialog success callback ${JSON.stringify(data)}`);
},
cancel: function () {
self.isPromptDialogShow = false;
mLogUtil.cameraInfo('dialog cancel callback');
},
});
mLogUtil.cameraInfo('promptShowDialog end.');
},
startDistributedView() {
RouterUtil.replace(DISTRIBUTED_VIEW);
}
};
@@ -1,74 +0,0 @@
/*
* Copyright (c) 2021 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 LogUtil from '../../common/utils/LogUtil.js';
import RouterUtil from '../../common/utils/RouterUtil.js';
import PageData from '../../common/constants/PageData.js';
const PREVIEW_VIEW = PageData.PREVIEW_PAGE;
let mLogUtil = new LogUtil();
let mPreviewModel
let mKvStoreModel;
let mRemoteDeviceModel;
export default class DistributedPresenter {
constructor(previewModel, kvStoreModel, remoteDeviceModel) {
mLogUtil.cameraInfo('DistributedPresenter constructor begin.');
mPreviewModel = previewModel;
mKvStoreModel = kvStoreModel;
mRemoteDeviceModel = remoteDeviceModel;
mKvStoreModel.setOnMessageReceivedListener(mKvStoreModel.messageData().msgFromResponderBack, () => {
mKvStoreModel.setOffMessageReceivedListener();
this.setCurrentDeviceId('localhost');
RouterUtil.replace(PREVIEW_VIEW);
});
mLogUtil.cameraInfo('DistributedPresenter constructor end.');
}
stopRemoteCamera() {
mLogUtil.cameraInfo('stopRemoteCamera begin.');
mKvStoreModel.broadcastMessage(mKvStoreModel.messageData().msgFromDistributedBack);
mKvStoreModel.setOffMessageReceivedListener();
mLogUtil.cameraInfo('stopRemoteCamera end.');
}
remoteTakePhoto() {
mLogUtil.cameraInfo('remoteTakePhoto begin.');
mKvStoreModel.broadcastMessage(mKvStoreModel.messageData().msgFromDistributedTakePhoto);
mLogUtil.cameraInfo('remoteTakePhoto end.');
}
registerDeviceStateChangeCallback(callback) {
mLogUtil.cameraInfo('registerDeviceStateChangeCallback begin.');
mRemoteDeviceModel.registerDeviceStateChangeCallback(callback);
mLogUtil.cameraInfo('registerDeviceStateChangeCallback end.');
}
setCurrentDeviceId(deviceId) {
mLogUtil.cameraInfo('DistributedPresenter setCurrentDeviceId begin.');
mRemoteDeviceModel.setCurrentDeviceId(deviceId);
}
getCurrentDeviceId() {
mLogUtil.cameraInfo('getCurrentDeviceId begin.');
return mRemoteDeviceModel.getCurrentDeviceId();
}
getPreviewStyle(callback) {
mLogUtil.cameraInfo('DistributedPresenter getPreviewStyle begin.');
mPreviewModel.getPreviewStyle(callback);
mLogUtil.cameraInfo('DistributedPresenter getPreviewStyle end');
}
}
@@ -1,318 +0,0 @@
/*
* Copyright (c) 2021 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 LogUtil from '../../common/utils/LogUtil.js';
import featureAbility from '@ohos.ability.featureAbility';
import media from '@ohos.multimedia.media';
import mediaLibrary from '@ohos.multimedia.medialibrary';
let mMedia = mediaLibrary.getMediaLibraryHelper();
let mLogUtil = new LogUtil();
let mPreviewModel;
let mKvStoreModel;
let mRemoteDeviceModel;
let mAudioPlayer;
let mTimeOUtFlag;
export default class PreviewPresenter {
constructor(previewModel, kvStoreModel, remoteDeviceModel) {
mPreviewModel = previewModel;
mKvStoreModel = kvStoreModel;
mRemoteDeviceModel = remoteDeviceModel;
mAudioPlayer = undefined;
}
takePhoto(element, state) {
mLogUtil.cameraInfo('takePhoto begin.');
if (state) {
this.playSound('file://system/etc/capture.ogg');
}
let photoUri = '';
return new Promise((resolve, reject) => {
element.takePhoto({
quality: mPreviewModel.getPhotoQuality(),
success: (res) => {
mLogUtil.cameraInfo(`takePhoto success: ${JSON.stringify(res)}`);
photoUri = res.uri;
if (state) {
resolve({
result: 'success',
photoUri: photoUri
});
}
},
fail: (res) => {
reject(new Error({
result: 'fail'
}));
mLogUtil.cameraError(`takePhoto fail: ${res.errormsg} ${res.errorcode}`);
},
complete: (res) => {
if (!state) {
resolve({
result: 'complete',
photoUri: photoUri
});
}
mLogUtil.cameraInfo(`takePhoto complete: ${res}`);
},
});
});
mLogUtil.cameraInfo('takePhoto end.');
}
async getPhotoUri() {
mLogUtil.cameraInfo('getPhotoUri begin.');
let photoUri = await mPreviewModel.getPhotoUri().then((data) => {
mLogUtil.cameraInfo(`getPhotoUri: ${JSON.stringify(data)}`);
return data;
});
mLogUtil.cameraInfo(`getPhotoUri: photoUri ${JSON.stringify(photoUri)}`);
return JSON.stringify(photoUri);
}
jumpToAlbum() {
mLogUtil.cameraInfo('jumpToAlbum begin.');
let actionData = {
uri: 'photodetail'
};
let paramBundleName = 'com.ohos.photos';
let paramAbilityName = 'com.ohos.photos.MainAbility';
let result = featureAbility.startAbility({
want: {
parameters: actionData,
bundleName: paramBundleName,
abilityName: paramAbilityName
},
}).then((data) => {
mLogUtil.cameraInfo(`startAbility : success : ${JSON.stringify(data)}`);
}).catch((error) => {
mLogUtil.cameraError(`startAbility : fail : ${JSON.stringify(error)}`);
});
mLogUtil.cameraInfo(`jumpToAlbum end: ${result}`);
}
previewStartedSuccess(element, callback) {
mLogUtil.cameraInfo('previewStartedSuccess begin.');
mKvStoreModel.broadcastMessage(mKvStoreModel.messageData().msgFromResponderReady);
mKvStoreModel.setOnMessageReceivedListener(mKvStoreModel.messageData().msgFromDistributedBack, () => {
mLogUtil.cameraInfo('OnMessageReceived previewBack');
featureAbility.terminateSelf((error) => {
mLogUtil.cameraError(`previewStartedSuccess terminateSelf finished, error= ${error}`);
});
});
mKvStoreModel.setOnMessageReceivedListener(mKvStoreModel.messageData().msgFromDistributedTakePhoto, () => {
mLogUtil.cameraInfo('OnMessageReceived takePhoto');
callback();
});
mLogUtil.cameraInfo('previewStartedSuccess end.');
}
registerDeviceStateChangeCallback(callback) {
mLogUtil.cameraInfo('registerDeviceStateChangeCallback begin.');
mRemoteDeviceModel.registerDeviceStateChangeCallback(callback);
mLogUtil.cameraInfo('registerDeviceStateChangeCallback end.');
}
remoteReturnBack() {
mLogUtil.cameraInfo('remoteReturnBack begin.');
mKvStoreModel.broadcastMessage(mKvStoreModel.messageData().msgFromResponderBack);
mLogUtil.cameraInfo('remoteReturnBack end.');
}
startAbilityContinuation(device, callback) {
mLogUtil.cameraInfo(`startAbilityContinuation deviceId= ${device.deviceId} deviceName= ${device.deviceName}`);
mTimeOUtFlag = false;
let startedFailTimer = setTimeout(() => {
mLogUtil.cameraInfo('remoteCameraStartedFail');
callback('remoteCameraStartedFail');
mTimeOUtFlag = true;
mRemoteDeviceModel.setCurrentDeviceId('localhost');
}, 7000);
mKvStoreModel.setOnMessageReceivedListener(mKvStoreModel.messageData().msgFromResponderReady, () => {
mLogUtil.cameraInfo('OnMessageReceived, remoteAbilityStarted');
clearTimeout(startedFailTimer);
if (!mTimeOUtFlag) {
callback('remoteCameraStartedSuccess');
}
});
featureAbility.startAbility({
want: {
bundleName: 'com.ohos.camera',
abilityName: 'com.ohos.camera.MainAbility',
deviceId: device.deviceId,
parameters: {
request: 'startPhotoBack'
}
}
}).then((data) => {
mLogUtil.cameraInfo(`featureAbility.startAbility finished, ${JSON.stringify(data)}`);
});
}
startRemoteCamera(inputValue, event, deviceList, callback) {
mLogUtil.cameraInfo(`startRemoteCamera ${inputValue}, ${event.value}`);
mRemoteDeviceModel.setCurrentDeviceId(event.value);
if (inputValue !== event.value) {
return;
}
if (event.value === 'localhost') {
mLogUtil.cameraInfo('startRemoteCamera radioChange to localhost.');
callback('backToLocalhost');
return;
}
if (deviceList.filter(item => item.id === event.value).length === 0) {
return;
}
let self = this;
let deviceItemExist = false;
let deviceName = '';
let j = 0;
mLogUtil.cameraInfo(`deviceList.length: ${mRemoteDeviceModel.deviceList.length}`);
for (var i = 0; i < mRemoteDeviceModel.deviceList.length; i++) {
if (mRemoteDeviceModel.deviceList[i].deviceId === event.value) {
j = i;
deviceItemExist = true;
break;
}
}
if (!deviceItemExist) {
mLogUtil.cameraError('can not find radioChange device from deviceList');
return;
}
if (mRemoteDeviceModel.deviceTrustedInfo[j]) {
mLogUtil.cameraInfo('radioChange device has been authorized');
self.startAbilityContinuation(mRemoteDeviceModel.deviceList[j], callback);
} else {
deviceName = mRemoteDeviceModel.deviceList[j].deviceName;
mRemoteDeviceModel.authDevice(event.value, () => {
mLogUtil.cameraInfo('radioChange device authorization success');
for (var i = 0; i < mRemoteDeviceModel.deviceList.length; i++) {
if (mRemoteDeviceModel.deviceList[i].deviceName === deviceName) {
if (mRemoteDeviceModel.deviceTrustedInfo[i]) {
mLogUtil.cameraInfo('authorization success and startAbilityContinuation');
self.startAbilityContinuation(mRemoteDeviceModel.deviceList[i], callback);
break;
}
}
}
});
}
mLogUtil.cameraInfo('startRemoteCamera end.');
}
returnDeviceList() {
mLogUtil.cameraInfo('returnDeviceList begin.');
return mRemoteDeviceModel.deviceList;
}
getDeviceList(callback) {
mLogUtil.cameraInfo('getDeviceList begin.');
mRemoteDeviceModel.registerDeviceListCallback(callback);
mLogUtil.cameraInfo('getDeviceList end.');
}
unregisterDeviceListCallback() {
mLogUtil.cameraInfo('unregisterDeviceListCallback begin.');
mRemoteDeviceModel.unregisterDeviceListCallback();
mLogUtil.cameraInfo('unregisterDeviceListCallback end.');
}
getCurrentDeviceId() {
mLogUtil.cameraInfo('getCurrentDeviceId begin.');
return mRemoteDeviceModel.getCurrentDeviceId();
mLogUtil.cameraInfo('getCurrentDeviceId end.');
}
playSound(soundUri) {
mLogUtil.cameraInfo('playSound begin.');
if (typeof (mAudioPlayer) !== 'undefined' && mAudioPlayer.src === soundUri && mAudioPlayer.state !== 'idle') {
mAudioPlayer.play();
} else {
mLogUtil.cameraInfo('playSound createAudioPlayer');
if (typeof (mAudioPlayer) !== 'undefined') {
mAudioPlayer.release();
mAudioPlayer = undefined;
}
mAudioPlayer = media.createAudioPlayer();
mAudioPlayer.on('dataLoad', () => {
mLogUtil.cameraInfo('playSound dataLoad callback');
mAudioPlayer.play();
});
mAudioPlayer.src = soundUri;
}
mLogUtil.cameraInfo('playSound end.');
}
startRecorder(element) {
mLogUtil.cameraInfo('startRecorder begin.');
this.playSound('file://system/etc/record_start.ogg');
element.startRecorder();
mLogUtil.cameraInfo('startRecorder end.');
}
closeRecorder(element) {
mLogUtil.cameraInfo('closeRecorder begin.');
this.playSound('file://system/etc/record_stop.ogg');
mLogUtil.cameraInfo('closeRecorder after playSound');
return new Promise((resolve, reject) => {
mLogUtil.cameraInfo('closeRecorder Promise begin.');
element.closeRecorder({
success: (res) => {
mLogUtil.cameraInfo(`closeRecorder success: ${JSON.stringify(res)}`);
resolve({
result: 'success',
photoUri: res.uri
});
mLogUtil.cameraInfo('closeRecorder Promise success end.');
},
fail: (res) => {
mLogUtil.cameraError('closeRecorder Promise fail begin.');
reject(new Error({
result: 'fail'
}));
mLogUtil.cameraError(`closeRecorder fail: ${res.errormsg} ${res.errorcode}`);
},
complete: (res) => {
mLogUtil.cameraInfo(`closeRecorder complete: ${res}`);
},
});
mLogUtil.cameraInfo('closeRecorder Promise end.');
});
}
deleteAlbumAsset() {
mLogUtil.cameraInfo('deleteAlbumAsset begin.');
let args = {
selections: 'camera',
selectionArgs: ['imagealbum'],
};
mMedia.getImageAssets(args, (error, images) => {
mLogUtil.cameraInfo(`deleteAlbumAsset images: ${images[0].URI}`);
images[0].commitDelete((error, commitFlag) => {
if (commitFlag) {
mLogUtil.cameraInfo('deleteAlbumAsset success');
}
});
});
mLogUtil.cameraInfo('deleteAlbumAsset end.');
}
getPreviewStyle(callback) {
mLogUtil.cameraInfo('previewPresenter getPreviewStyle begin.');
mPreviewModel.getPreviewStyle(callback);
mLogUtil.cameraInfo('previewPresenter getPreviewStyle end');
}
}
+19
View File
@@ -0,0 +1,19 @@
apply plugin: 'com.huawei.ohos.library'
ohos {
compileSdkVersion 8
defaultConfig {
compatibleSdkVersion 8
}
buildTypes {
release {
proguardOpt {
proguardEnabled false
rulesFiles 'proguard-rules.pro'
}
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar', '*.har'])
}
@@ -0,0 +1,23 @@
{
"app": {
"bundleName": "com.ohos.camera",
"vendor": "ohos",
"version": {
"code": 1000000,
"name": "1.0.0"
}
},
"deviceConfig": {
},
"module": {
"package": "com.ohos.camera.featurecommon",
"deviceType": [
"phone"
],
"distro": {
"deliveryWithInstall": true,
"moduleName": "featurecommon",
"moduleType": "har"
}
}
}
@@ -0,0 +1,33 @@
/*
* Copyright (c) 2022 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 {PhotoMode} from '../../../../../../../photo/src/main/ets/com/ohos/photo/PhotoMode'
import {VideoMode} from '../../../../../../../video/src/main/ets/com/ohos/video/VideoMode'
export class Mode {
private photoMode: PhotoMode = new PhotoMode()
private videoMode: VideoMode = new VideoMode()
public getParam(mode: string): string[] {
switch (mode) {
case 'PHOTO':
return this.photoMode.getTabBarParam()
break;
case 'VIDEO':
return this.videoMode.getTabBarParam()
default:
}
}
}
@@ -0,0 +1,66 @@
/*
* Copyright (c) 2022 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 router from '@system.router'
@Component
export struct ShowFlashBlack {
@State opacityValue: number = 1
@Link XcomponentWidth: string;
@Link XcomponentHeight: string;
@Link isShowFlashBlack: boolean;
build() {
Flex({ direction: FlexDirection.Row }) {
Row() {
Shape() {
Rect()
.width(Number(this.XcomponentWidth.split('px')[0]))
.height(Number(this.XcomponentHeight.split('px')[0]))
}
.fill(Color.Black)
.opacity(this.opacityValue)
.onAppear(() => {
animateTo({
duration: 50,
delay: 0,
onFinish: () => {
console.info("isShowFlashBlack111=" + this.isShowFlashBlack)
console.info("XcomponentWidth = " + Number(
this.XcomponentWidth.split('px')[0]))
console.info("XcomponentHeight = " + Number(
this.XcomponentHeight.split('px')[0]))
}
}, () => {
console.log("onAppear first")
})
animateTo({
duration: 300,
curve: Curve.Sharp,
delay: 50,
onFinish: () => {
this.isShowFlashBlack = false;
this.opacityValue = 1;
}
}, () => {
this.opacityValue = 0;
})
})
}
}.height(Number(this.XcomponentHeight.split('px')[0]))
.width(Number(this.XcomponentWidth.split('px')[0]))
}
}
@@ -0,0 +1,111 @@
/*
* Copyright (c) 2022 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 {CameraSwitchController} from './CameraSwitchController.ets'
import {CameraService} from '../../../../../../../../../common/src/main/ets/default/Camera/CameraService'
import MultiCameraDialog from '../customDialog/MultiCameraDialog.ets'
@Component
export struct CameraSwitchButton {
@State icon: Resource = $r("app.media.small_switch_camera")
width: number
height: number
margin: number
type: ButtonType
stateEffect: boolean
cameraSwitchController = new CameraSwitchController()
private cameraService = CameraService.getInstance()
@Link surfaceId: number
@Link cameraPosition: string
@Link btnOpacity_first: number
@Link btnOpacity_sec: number
@Link btnSwitch: boolean
@Link btnSwitchSec: boolean
@Link xComponentChangeFlag: boolean
@Link previewImage: string
@Link cameraId: string
@Link isSwitchBackground: boolean
@State switchAnimationTimer: number = 0
multiDialogController: CustomDialogController = new CustomDialogController({
builder: MultiCameraDialog({
action: this.onAccept,
cameraId:$cameraId,
cameraPosition:$cameraPosition,
xComponentChangeFlag: $xComponentChangeFlag
}),
autoCancel: true,
alignment: DialogAlignment.Center,
cancel: this.existView
})
aboutToAppear() {
this.cameraSwitchController.getParam()
this.icon = this.cameraSwitchController.icon
this.width = this.cameraSwitchController.width
this.height = this.cameraSwitchController.height
this.margin = this.cameraSwitchController.margin
this.type = this.cameraSwitchController.type
this.stateEffect = this.cameraSwitchController.stateEffect
}
private openMultiDialog() {
console.info('CameraSwitchButton.openMultiDialog called')
this.multiDialogController.open()
}
public existView() {
}
private onAccept() {
}
build() {
Column() {
Stack() {
Image($r('app.media.small_switch_camera'))
.width('67.5%')
.aspectRatio(1)
.clip(new Circle({ width: '100%', height: '100%' }))
Column() {
}
.border({ width: 2, color: 0xffffff, radius: 20, style: BorderStyle.Solid })
.width('100%')
.height('100%')
}
.width('100%')
.height('100%')
.onClick(() => {
if (this.previewImage == 'MULTI') {
this.openMultiDialog()
} else {
this.xComponentChangeFlag = !this.xComponentChangeFlag
if (this.cameraPosition !== 'BACK') {
if (this.cameraPosition === 'ORIGIN') {
this.cameraPosition = 'FRONT'
} else {
this.cameraPosition = 'BACK'
}
} else {
this.cameraPosition = 'FRONT'
}
}
})
}
.width(40)
.aspectRatio(1)
}
}
@@ -0,0 +1,32 @@
/*
* Copyright (c) 2022 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 class CameraSwitchController {
icon: Resource
width: number
height: number
margin: number
type: ButtonType
stateEffect: boolean
getParam(): void {
this.icon = $r("app.media.small_switch_camera")
this.width = 40
this.height = 40
this.margin = 48
this.type = ButtonType.Circle
this.stateEffect = true
}
}
@@ -0,0 +1,60 @@
/**
* Copyright (c) 2022 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 {CameraService} from '../../../../../../../../../common/src/main/ets/default/Camera/CameraService'
@Component
export default struct EntryComponentForMulti {
@Prop item: string
@Link cameraPosition: string
@Link xComponentChangeFlag: boolean
private onChange: Function
private cameraService = CameraService.getInstance()
private curCameraName
private aboutToAppear() {
this.curCameraName = this.cameraService.getCameraName()
}
build() {
Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.SpaceBetween }) {
Text(this.item)
.fontColor('#000000')
.fontSize(16)
.fontWeight(FontWeight.Medium)
.margin({ top: '12vp', left: '12vp', bottom: '12vp', right: '24vp' })
Radio({ group: 'settingChildren', value: this.item.toString() })
.width(24)
.height(24)
.checked(this.item.toString() === this.curCameraName)
.enabled(true)
.onChange(() => {
console.info('EntryComponentForMulti onChange: ' + this.item)
this.cameraService.setCameraName(this.item)
if (this.item == '本地(前置)') {
this.cameraPosition = 'FRONT'
} else if (this.item == '本地(后置)') {
this.cameraPosition = 'BACK'
} else {
this.cameraPosition = this.item
}
this.xComponentChangeFlag = !this.xComponentChangeFlag
this.onChange()
})
}
.height(48)
.width('100%')
}
}
@@ -0,0 +1,131 @@
/*
* Copyright (c) 2022 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 {CameraService} from '../../../../../../../../../common/src/main/ets/default/Camera/CameraService'
import EntryComponentForMulti from './EntryComponentForMulti'
@CustomDialog
export default struct MultiCameraDialog {
private cameraService = CameraService.getInstance()
@Link cameraId: string
@Link cameraPosition: string
@Link xComponentChangeFlag: boolean
controller: CustomDialogController
cancel: () => void
confirm: () => void
private localList = ['本地(前置)', '本地(后置)']
private moreList = []
@State isShowMore: boolean = false
async aboutToAppear() {
console.info('MultiCameraDialog aboutToAppear.')
this.moreList = this.cameraService.getDeviceInfo()
this.cameraService.getCameraLists().then(() => {
let cameraList = this.cameraService.cameraListInfo
this.isShowMore = cameraList.length > 5 ? true : false
})
}
private onChange(): void {
this.controller.close()
this.cancel()
}
build() {
Column() {
Row() {
Text('选择摄像头')
.fontSize('20fp')
.fontColor('#E6000000')
.fontWeight(FontWeight.Medium)
.opacity(0.9)
.padding({ left: 20 })
}
.width('100%')
.height(40)
Row() {
Text('已连接设备').fontSize('12fp').fontColor(Color.Gray).padding({ left: 20 })
}
.width('100%')
.height(20)
List() {
ForEach(this.localList, (item) => {
ListItem() {
EntryComponentForMulti({
item: item,
onChange: () => this.onChange(),
cameraPosition: $cameraPosition,
xComponentChangeFlag: $xComponentChangeFlag
})
}
.margin({ left: '12vp', right: '12vp' })
.width('100%')
.height(48);
})
}
.listDirection(Axis.Vertical)
.divider({ strokeWidth: 0.5, color: '#33000000', startMargin: 0, endMargin: 12 })
.margin({ left: '24vp', right: '24vp' })
Row() {
Text('更多设备')
.fontSize('14fp')
.fontColor('#99FFFFFF')
.opacity(0.6)
.fontWeight(FontWeight.Medium)
.padding({ left: 20 })
}
.width('100%')
.height(20)
if (this.isShowMore) {
List() {
ForEach(this.moreList, (item) => {
ListItem() {
EntryComponentForMulti({
item: item,
onChange: () => this.onChange(),
cameraPosition: $cameraPosition,
xComponentChangeFlag: $xComponentChangeFlag
});
}
.margin({ left: '12vp', right: '12vp' })
.width('100%')
.height(48);
})
}
.listDirection(Axis.Vertical)
.divider({ strokeWidth: 0.5, color: '#33000000', startMargin: 0, endMargin: 12 })
.margin({ left: '24vp', right: '24vp' })
}
Button({ type: ButtonType.Normal, stateEffect: true }) {
Text($r('app.string.cancel'))
.fontSize('16fp')
.fontColor('#1095E8')
.fontWeight(FontWeight.Medium)
.height(40)
}
.margin({ top: '8vp', bottom: '16vp' })
.height(56)
.backgroundColor(0xffffff)
.onClick(() => {
this.controller.close()
})
}
}
}
@@ -0,0 +1,74 @@
/*
* Copyright (c) 2022 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 SettingListModel from '../../../../../../../../../common/src/main/ets/default/model/SettingListImpl/SettingListModel.ets';
import settings from '@ohos.settings';
import {SettingsUtil} from '../../../../../../../../../common/src/main/ets/default/Utils/SettingsUtil.ets';
@Component
export default struct EntryComponent {
@Prop itemValue: string;
@Prop checkedValue: string;
@Prop settingAlias: string;
@State getValue: string = ''
private onChange: Function
private settingsUtil = SettingsUtil.getInstance()
async aboutToAppear(): Promise<void> {
console.info(`EntryComponent aboutToAppear calle1d = ${this.settingAlias}`)
try {
this.getValue = await this.settingsUtil.getSettingValue(this.settingAlias)
console.log(`EntryComponent.getValue=${this.getValue}`)
} catch {
console.log(`catch this.settingAlias=${this.settingAlias}`)
if (this.settingAlias === 'Video resolution' || this.settingAlias === 'videoResolution') {
this.getValue = '[16:9] 720p'
} else {
this.getValue = '4:3'
}
console.log(`catch this.getValue=${this.getValue}`)
}
}
private logger(): boolean {
console.info('EntryComponent build')
return true
}
build() {
if (this.logger()) {
Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.SpaceBetween }) {
Text(this.itemValue)
.fontSize(16)
.fontWeight(FontWeight.Regular)
.margin({ top: '12vp', bottom: '12vp' })
Radio({ group: 'settingChildren', value: this.itemValue.toString() })
.width(24)
.height(24)
.checked(this.itemValue.toString() === this.getValue.toString())
.enabled(true)
.onChange(() => {
console.info(`EntryComponent onChange settingAlias${this.settingAlias}`)
console.info(`EntryComponent onChange itemValue${this.itemValue}`)
this.settingsUtil.setSettingValue(this.settingAlias, this.itemValue).then(() => {
this.onChange()
})
})
}
.height(48)
.width('100%')
}
}
}
@@ -0,0 +1,47 @@
/*
* Copyright (c) 2022 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 {ModeAssembler} from './ModeAssembler'
import {Mode} from '../Mode.ets'
export class FeatureManager {
private mode = new Mode()
private modeAssembler = new ModeAssembler()
private preMode: string = 'PHOTO'
public currentMode: string = this.preMode
public tabItem: string[]
constructor() {
console.info('Application onCreate FeatureManager::getInstance.')
this.modeAssembler.assembler(this.preMode, null)
}
public static getInstance(): FeatureManager {
console.info('FeatureManager::getInstance.')
return new FeatureManager()
}
public changeMode(currentMode: string): void {
console.info('changeMode start')
this.modeAssembler.assembler(this.preMode, currentMode)
this.tabItem = this.mode.getParam(currentMode)
this.currentMode = currentMode
this.preMode = this.currentMode
}
public getParam(): void {
this.tabItem = this.mode.getParam(this.currentMode)
}
}
@@ -0,0 +1,49 @@
/*
* Copyright (c) 2022 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 class ModeAssembler {
private needAdd: string[]
private needDelete: string[]
public assembler(preMode: string, currentMode: string): void {
let tabBarItem: string[]
if (currentMode == null) {
} else if (preMode != currentMode) {
if (currentMode == 'VIDEO') {
this.needAdd = ['timer']
this.needDelete = ['flash', 'focus']
} else if (currentMode == 'PHOTO') {
this.needDelete = ['timer']
this.needAdd = ['flash', 'focus']
}
this.attachFunction(this.needAdd)
this.disattachFunction(this.needDelete)
}
}
private intersect(preItem: string[], currentItem: string[]): void {
}
private attachFunction(item: string[]): void {
}
private disattachFunction(item: string[]): void {
}
}
@@ -0,0 +1,175 @@
/*
* Copyright (c) 2022 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 {ShutterController} from './ShutterController.ets'
import {CameraService} from '../../../../../../../../../common/src/main/ets/default/Camera/CameraService'
import GetPixelMap from '../../../../../../../../../common/src/main/ets/default/Camera/GetPixelMap'
import router from "@system.router"
@Component
export struct ShutterButton {
@State icon: Resource = $r("app.media.ic_circled_filled")
@Link @Watch("modeUpdate") previewImage: string
width: number
height: number
type: ButtonType
stateEffect: boolean
shutterController = new ShutterController()
private cameraService = CameraService.getInstance()
getPixelMap = new GetPixelMap()
@Link videoState: string
@Link isThirdPartyCall: boolean
@Link isStartVideo: boolean
@Link isBigVideoTimerVisible: boolean
@Link isSmallVideoTimerVisible: boolean
@Link isResumeVideo: boolean
@Link iscContinueVideo: boolean
@Link isShowFlashBlack: boolean
@State tempScale: number = 1
@Link xComponentChangeFlag: boolean
aboutToAppear() {
this.shutterController.getParam()
this.icon = this.shutterController.icon
this.width = this.shutterController.width
this.height = this.shutterController.height
this.type = this.shutterController.type
this.stateEffect = this.shutterController.stateEffect
}
modeUpdate() {
if (this.previewImage === 'VIDEO') {
this.icon = $r("app.media.take_video_normal")
} else {
this.icon = $r("app.media.ic_circled_filled")
}
this.videoState = 'beforeTakeVideo'
}
build() {
if (this.videoState === 'beforeTakeVideo') {
Stack({alignContent: Alignment.Center}) {
if (this.previewImage === 'VIDEO'){
Image(this.icon)
.width(76)
.aspectRatio(1)
.onTouch((event: TouchEvent) => {
if (event.type === TouchType.Up) {
this.isBigVideoTimerVisible = true
this.videoState = 'startTakeVideo'
this.xComponentChangeFlag = !this.xComponentChangeFlag
this.isStartVideo = true
}
})
} else {
Image($r("app.media.ic_circled")).fillColor(Color.White)
.width(76)
.aspectRatio(1)
Image(this.icon)
.width(54)
.aspectRatio(1)
.fillColor(Color.White)
.scale({ x: this.tempScale, y: this.tempScale, z: this.tempScale })
.onTouch((event: TouchEvent) => {
if (event.type === TouchType.Down) {
animateTo({
duration: 125,
curve: Curve.Sharp,
delay: 0
}, () => {
this.tempScale = 0.85
console.info("Down Call Back")
})
} else if (event.type === TouchType.Up) {
animateTo({
duration: 125,
curve: Curve.Sharp,
delay: 0,
onFinish: () => {
console.info(`this.onFinish= ${this.tempScale}`)
this.tempScale = 1
console.info("Up onFinish")
}
}, () => {
this.tempScale = 1
console.info("Up Call Back")
})
this.isShowFlashBlack = true
this.cameraService.takePicture(() => {
if (this.isThirdPartyCall) {
router.push({ uri: "pages/ThirdPreviewView" })
}
})
}
console.info(`event.type=${event.type}`)
})
}
}
.width(76)
.aspectRatio(1)
.margin({ left: 48, right: 48 })
} else {
Column() {
Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
if (this.videoState === 'startTakeVideo') {
Image($r('app.media.ic_video_recording'))
.width(20)
.aspectRatio(1)
.fillColor(Color.White)
.margin({ right: 16 })
.onClick(() => {
this.isResumeVideo = true
this.iscContinueVideo = false
this.cameraService.pauseVideo()
this.videoState = 'pauseTakeVideo'
})
} else if (this.videoState === 'pauseTakeVideo') {
Image($r('app.media.ic_video_pause'))
.width(20)
.aspectRatio(1)
.fillColor('#ff0000')
.margin({ right: 16 })
.onClick(() => {
this.isResumeVideo = false
this.iscContinueVideo = true
this.cameraService.resumeVideo()
this.videoState = 'startTakeVideo'
})
}
Image($r('app.media.ic_video_end'))
.width(20)
.aspectRatio(1)
.fillColor(Color.White)
.margin({ left: 16 })
.onClick(() => {
this.isResumeVideo = false
this.iscContinueVideo = false
this.isBigVideoTimerVisible = false
this.isSmallVideoTimerVisible = false
this.cameraService.stopVideo()
this.cameraService.releaseVideo()
this.videoState = 'beforeTakeVideo'
})
}.width('100%')
.height('100%')
}
.width(120)
.height(56)
.borderRadius(28)
.border({ width: 2, color: 0xffffff, style: BorderStyle.Solid })
.margin({left: 26, right: 26})
}
}
}
@@ -0,0 +1,174 @@
/*
* Copyright (c) 2022 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 {ShutterController} from './ShutterController.ets'
import {CameraService} from '../../../../../../../../../common/src/main/ets/default/Camera/CameraService'
import GetPixelMap from '../../../../../../../../../common/src/main/ets/default/Camera/GetPixelMap'
import router from "@system.router"
@Component
export struct ShutterButtonLand {
@State icon: Resource = $r("app.media.ic_circled_filled")
@Link @Watch("modeUpdate") previewImage: string
width: number
height: number
type: ButtonType
stateEffect: boolean
shutterController = new ShutterController()
private cameraService = CameraService.getInstance()
getPixelMap = new GetPixelMap()
@Link videoState: string
@Link isThirdPartyCall: boolean
@Link isStartVideo: boolean
@Link isBigVideoTimerVisible: boolean
@Link isSmallVideoTimerVisible: boolean
@Link isResumeVideo: boolean
@Link iscContinueVideo: boolean
@Link isShowFlashBlack: boolean
@State tempScale: number = 1
@Link xComponentChangeFlag: boolean
aboutToAppear() {
this.shutterController.getParam()
this.icon = this.shutterController.icon
this.width = this.shutterController.width
this.height = this.shutterController.height
this.type = this.shutterController.type
this.stateEffect = this.shutterController.stateEffect
}
modeUpdate() {
if (this.previewImage === 'VIDEO') {
this.icon = $r("app.media.take_video_normal")
} else {
this.icon = $r("app.media.ic_circled_filled")
}
this.videoState = 'beforeTakeVideo'
}
build() {
if (this.videoState === 'beforeTakeVideo') {
Stack({alignContent: Alignment.Center}) {
if (this.previewImage === 'VIDEO'){
Image(this.icon)
.width(76)
.aspectRatio(1)
.onTouch((event: TouchEvent) => {
if (event.type === TouchType.Up) {
this.isBigVideoTimerVisible = true
this.videoState = 'startTakeVideo'
this.xComponentChangeFlag = !this.xComponentChangeFlag
this.isStartVideo = true
}
})
} else {
Image($r("app.media.ic_circled")).fillColor(Color.White)
.width(76)
.aspectRatio(1)
Image(this.icon)
.width(54)
.aspectRatio(1)
.fillColor(Color.White)
.scale({ x: this.tempScale, y: this.tempScale, z: this.tempScale })
.onTouch((event: TouchEvent) => {
if (event.type === TouchType.Down) {
animateTo({
duration: 125,
curve: Curve.Sharp,
delay: 0
}, () => {
this.tempScale = 0.85
console.info("Down Call Back")
})
} else if (event.type === TouchType.Up) {
animateTo({
duration: 125,
curve: Curve.Sharp,
delay: 0,
onFinish: () => {
console.info(`this.onFinish= ${this.tempScale}`)
this.tempScale = 1
console.info("Up onFinish")
}
}, () => {
this.tempScale = 1
console.info("Up Call Back")
})
this.isShowFlashBlack = true
this.cameraService.takePicture(() => {
if (this.isThirdPartyCall) {
router.push({ uri: "pages/ThirdPreviewView" })
}
})
}
console.info(`event.type=${event.type}`)
})
}
}
.width(76)
.aspectRatio(1)
.margin({ top: 48, bottom: 48 })
} else {
Column() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
if (this.videoState === 'startTakeVideo') {
Image($r('app.media.ic_video_recording'))
.width(20)
.aspectRatio(1)
.fillColor(Color.White)
.margin({ bottom: 16 })
.onClick(() => {
this.isResumeVideo = true
this.iscContinueVideo = false
this.cameraService.pauseVideo()
this.videoState = 'pauseTakeVideo'
})
} else if (this.videoState === 'pauseTakeVideo') {
Image($r('app.media.ic_video_pause'))
.width(20)
.aspectRatio(1)
.fillColor('#ff0000')
.margin({ bottom: 16 })
.onClick(() => {
this.isResumeVideo = false
this.iscContinueVideo = true
this.cameraService.resumeVideo()
this.videoState = 'startTakeVideo'
})
}
Image($r('app.media.ic_video_end'))
.width(20)
.aspectRatio(1)
.fillColor(Color.White)
.margin({ top: 16 })
.onClick(() => {
this.isResumeVideo = false
this.iscContinueVideo = false
this.isBigVideoTimerVisible = false
this.isSmallVideoTimerVisible = false
this.cameraService.stopVideo()
this.cameraService.releaseVideo()
this.videoState = 'beforeTakeVideo'
})
}
}
.width(56)
.height(120)
.borderRadius(28)
.border({ width: 2, color: 0xffffff, style: BorderStyle.Solid })
.margin({ top: 48, bottom: 48 })
}
}
}
@@ -0,0 +1,31 @@
/*
* Copyright (c) 2022 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 class ShutterController {
icon: Resource
width: number
height: number
type: ButtonType
stateEffect: boolean
getParam(): void {
this.icon = $r("app.media.ic_circled_filled")
this.width = 76
this.height = 76
this.type = ButtonType.Circle
this.stateEffect = true
}
}
@@ -0,0 +1,26 @@
/*
* Copyright (c) 2022 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 class ThumbnailController {
width: number
height: number
margin: number
getParam(): void {
this.width = 40
this.height = 40
this.margin = 48
}
}
@@ -0,0 +1,91 @@
/*
* Copyright (c) 2022 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 {ThumbnailController} from './ThumbnailController.ets'
import {CameraService} from '../../../../../../../../../common/src/main/ets/default/Camera/CameraService'
import GetPixelMap from '../../../../../../../../../common/src/main/ets/default/Camera/GetPixelMap'
@Component
export struct ThumbnailView {
@State thumbnail: string = ''
@State useThumbnail: boolean = false
@State tempBorder: Object = { width: 2, color: 0xffffff, style: BorderStyle.Solid }
private defaultIcon: Resource = $r("app.media.ic_camera_thumbnail_default_white")
private cameraService = CameraService.getInstance()
getPixelMap = new GetPixelMap()
thumbnailController = new ThumbnailController()
@State scaleValue: number = 1
@State tempScaleX: number= 1;
@State tempScaleY: number= 1;
@State tempOpacity: number= 1;
@State @Watch("thumbnailUpdate") isThumbnail: boolean = false
aboutToAppear() {
this.cameraService.getThumbnail((thumbnail) => {
if (thumbnail != '' && thumbnail != undefined) {
this.useThumbnail = true
this.thumbnail = thumbnail
this.isThumbnail = !this.isThumbnail
console.info("ThumbnailView update thumbnail: " + this.thumbnail)
} else {
this.useThumbnail = false
this.tempBorder = {};
console.info("ThumbnailView update thumbnail fail: " + this.thumbnail)
}
})
this.thumbnailController.getParam()
}
public thumbnailUpdate() {
this.scaleValue = 1.5
this.tempOpacity = 0.0
animateTo({ duration: 100, curve: Curve.Sharp }, () => {
this.tempOpacity = 1
})
animateTo({ duration: 300, curve: Curve.Sharp }, () => {
this.scaleValue = 1
})
}
build() {
Column() {
Stack() {
Image(this.useThumbnail ? this.thumbnail : this.defaultIcon)
.width('100%')
.aspectRatio(1)
.borderRadius(20)
.objectFit(ImageFit.Fill)
}
.onClick(async () => {
console.log('startAbility start')
await globalThis.cameraAbilityContext.startAbility({
parameters: {uri: 'photodetail'},
bundleName: "com.ohos.photos",
abilityName: "com.ohos.photos.MainAbility",
})
})
.width('100%')
.height('100%')
}
.borderRadius(20)
.border(this.tempBorder)
.opacity(this.tempOpacity)
.width(40)
.aspectRatio(1)
.scale({ x: this.scaleValue, y: this.scaleValue })
}
}
@@ -0,0 +1,20 @@
{
"color": [
{
"name":"notificationitem_background",
"value":"#ffffff"
},
{
"name":"title_text_color",
"value":"#222D37"
},
{
"name":"content_text_color",
"value":"#FF435563"
},
{
"name":"name_text_color",
"value":"#435563"
}
]
}
@@ -0,0 +1,112 @@
{
"float": [
{
"name": "notification_title_fontsize",
"value": "20"
},
{
"name": "notification_expanded_text_maxheight",
"value": "295"
},
{
"name": "notification_content_fontsize",
"value": "20"
},
{
"name": "notification_content_lineheight",
"value": "20"
},
{
"name": "notification_content_maxlines",
"value": "1"
},
{
"name": "content_margin_top",
"value": "10"
},
{
"name": "body_margin_top",
"value": "10"
},
{
"name": "item_opicaty",
"value": "0.9"
},
{
"name": "item_borderradius",
"value": "20"
},
{
"name": "item_margintop",
"value": "10"
},
{
"name": "item_marginleft",
"value": "10"
},
{
"name": "item_marginright",
"value": "10"
},
{
"name": "item_paddingleft",
"value": "20"
},
{
"name": "item_paddingright",
"value": "20"
},
{
"name": "item_paddingbottom",
"value": "20"
},
{
"name": "item_setting_image_width",
"value": "30"
},
{
"name": "item_setting_image_height",
"value": "30"
},
{
"name": "item_delete_image_width",
"value": "30"
},
{
"name": "item_delete_image_height",
"value": "30"
},
{
"name": "titleitem_row_space",
"value": "10"
},
{
"name": "titleitem_height",
"value": "50"
},
{
"name": "title_image_width",
"value": "30"
},
{
"name": "title_image_height",
"value": "30"
},
{
"name": "title_name_fontsize",
"value": "20"
},
{
"name": "title_time_fontsize",
"value": "20"
},
{
"name": "displayicon_width",
"value": "20"
},
{
"name": "displayicon_height",
"value": "20"
}
]
}
@@ -0,0 +1,8 @@
{
"string": [
{
"name": "noticeitem",
"value": "noticeitem"
}
]
}

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 63.1 (92452) - https://sketch.com -->
<title>ic/camera/public/flash_always_on</title>
<desc>Created with Sketch.</desc>
<defs>
<path d="M14.25,20.375 C14.6642136,20.375 15,20.7107864 15,21.125 C15,21.5392136 14.6642136,21.875 14.25,21.875 L9.75,21.875 C9.33578644,21.875 9,21.5392136 9,21.125 C9,20.7107864 9.33578644,20.375 9.75,20.375 L14.25,20.375 Z M15,17.625 C15.4142136,17.625 15.75,17.9607864 15.75,18.375 C15.75,18.7892136 15.4142136,19.125 15,19.125 L9,19.125 C8.58578644,19.125 8.25,18.7892136 8.25,18.375 C8.25,17.9607864 8.58578644,17.625 9,17.625 L15,17.625 Z M12,2.125 C16.1421356,2.125 19.5,5.48286438 19.5,9.625 C19.5,12.4597689 17.9128745,15.0128043 15.4398127,16.2912439 C15.3333496,16.3462796 15.2152477,16.3750004 15.0954007,16.3750004 L8.90459924,16.3750004 C8.78475226,16.3750004 8.66665037,16.3462796 8.56018734,16.2912439 C6.08712548,15.0128043 4.5,12.4597689 4.5,9.625 C4.5,5.48286438 7.85786438,2.125 12,2.125 Z M12,3.625 C8.6862915,3.625 6,6.3112915 6,9.625 C6,11.8330802 7.20287153,13.8267082 9.09265403,14.8750004 L14.9073452,14.8750004 C16.7971282,13.8267087 18,11.8330805 18,9.625 C18,6.3112915 15.3137085,3.625 12,3.625 Z" id="path-1"></path>
</defs>
<g id="ic/camera/public/flash_always_on" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<mask id="mask-2" fill="white">
<use xlink:href="#path-1"></use>
</mask>
<use id="flash_always_on" fill="#FFFFFF" xlink:href="#path-1"></use>
<g id="ic/bg/white" mask="url(#mask-2)" fill="#FFFFFF" fill-rule="nonzero">
<!-- <rect id="Rectangle-13-Copy" x="0" y="0" width="24" height="24"></rect>-->
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 63.1 (92452) - https://sketch.com -->
<title>ic/camera/public/flash_always_on</title>
<desc>Created with Sketch.</desc>
<defs>
<path d="M14.25,20.375 C14.6642136,20.375 15,20.7107864 15,21.125 C15,21.5392136 14.6642136,21.875 14.25,21.875 L9.75,21.875 C9.33578644,21.875 9,21.5392136 9,21.125 C9,20.7107864 9.33578644,20.375 9.75,20.375 L14.25,20.375 Z M15,17.625 C15.4142136,17.625 15.75,17.9607864 15.75,18.375 C15.75,18.7892136 15.4142136,19.125 15,19.125 L9,19.125 C8.58578644,19.125 8.25,18.7892136 8.25,18.375 C8.25,17.9607864 8.58578644,17.625 9,17.625 L15,17.625 Z M12,2.125 C16.1421356,2.125 19.5,5.48286438 19.5,9.625 C19.5,12.4597689 17.9128745,15.0128043 15.4398127,16.2912439 C15.3333496,16.3462796 15.2152477,16.3750004 15.0954007,16.3750004 L8.90459924,16.3750004 C8.78475226,16.3750004 8.66665037,16.3462796 8.56018734,16.2912439 C6.08712548,15.0128043 4.5,12.4597689 4.5,9.625 C4.5,5.48286438 7.85786438,2.125 12,2.125 Z M12,3.625 C8.6862915,3.625 6,6.3112915 6,9.625 C6,11.8330802 7.20287153,13.8267082 9.09265403,14.8750004 L14.9073452,14.8750004 C16.7971282,13.8267087 18,11.8330805 18,9.625 C18,6.3112915 15.3137085,3.625 12,3.625 Z" id="path-1"></path>
</defs>
<g id="ic/camera/public/flash_always_on" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<mask id="mask-2" fill="white">
<use xlink:href="#path-1"></use>
</mask>
<use id="flash_always_on" fill="#006cde" xlink:href="#path-1"></use>
<g id="ic/bg/white" mask="url(#mask-2)" fill="#FFFFFF" fill-rule="nonzero">
<!-- <rect id="Rectangle-13-Copy" x="0" y="0" width="24" height="24"></rect>-->
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 63.1 (92452) - https://sketch.com -->
<title>ic/camera/public/flash_auto</title>
<desc>Created with Sketch.</desc>
<defs>
<path d="M7.10398929,3.091547 C7.46772137,3.28971827 7.60193492,3.74523093 7.40376365,4.108963 L4.78546603,10.7501422 L10.4951685,10.7501422 C11.3210126,10.7501422 11.7505358,11.6664585 11.4105074,12.3462983 L8.446,19.335 L9.63678779,19.8408135 C9.76388299,19.8947622 9.82317994,20.0415273 9.76923122,20.1686225 C9.74560314,20.2242868 9.70259978,20.2695002 9.64818847,20.2958859 L6.81711664,21.6687612 C6.69288228,21.7290064 6.5433321,21.6771328 6.48308697,21.5528985 C6.47817287,21.5427649 6.47394916,21.5323108 6.47044468,21.5216077 L5.49138079,18.5314258 C5.44841706,18.4002093 5.51996008,18.2590083 5.65117659,18.2160446 C5.70864589,18.1972276 5.77098779,18.1998788 5.82665207,18.2235068 L7.064,18.748 L9.76976789,12.2501422 L3.99516847,12.2501422 C3.12016664,12.2501422 2.79891626,11.3155956 3.12434807,10.664732 L6.08657328,3.39132136 C6.28474455,3.02758928 6.74025722,2.89337573 7.10398929,3.091547 Z M17.4817165,11.0083008 L20.9578857,21.1240903 L19.222464,21.1240903 L18.4837544,18.9060741 L14.9792731,18.9060741 L14.3788178,21.1240903 L12.8065094,21.1240903 L15.9303912,11.0083008 L17.4817165,11.0083008 Z M16.7858212,13.0526316 L15.4288103,17.4736842 L18.1571089,17.4736842 L16.7858212,13.0526316 Z" id="path-1"></path>
</defs>
<g id="ic/camera/public/flash_auto" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<mask id="mask-2" fill="white">
<use xlink:href="#path-1"></use>
</mask>
<use id="flash_auto" fill="#FFFFFF" xlink:href="#path-1"></use>
<g id="ic/bg/white" mask="url(#mask-2)" fill="#FFFFFF" fill-rule="nonzero">
<!-- <rect id="Rectangle-13-Copy" x="0" y="0" width="24" height="24"></rect>-->
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 63.1 (92452) - https://sketch.com -->
<title>ic/camera/public/flash_auto</title>
<desc>Created with Sketch.</desc>
<defs>
<path d="M7.10398929,3.091547 C7.46772137,3.28971827 7.60193492,3.74523093 7.40376365,4.108963 L4.78546603,10.7501422 L10.4951685,10.7501422 C11.3210126,10.7501422 11.7505358,11.6664585 11.4105074,12.3462983 L8.446,19.335 L9.63678779,19.8408135 C9.76388299,19.8947622 9.82317994,20.0415273 9.76923122,20.1686225 C9.74560314,20.2242868 9.70259978,20.2695002 9.64818847,20.2958859 L6.81711664,21.6687612 C6.69288228,21.7290064 6.5433321,21.6771328 6.48308697,21.5528985 C6.47817287,21.5427649 6.47394916,21.5323108 6.47044468,21.5216077 L5.49138079,18.5314258 C5.44841706,18.4002093 5.51996008,18.2590083 5.65117659,18.2160446 C5.70864589,18.1972276 5.77098779,18.1998788 5.82665207,18.2235068 L7.064,18.748 L9.76976789,12.2501422 L3.99516847,12.2501422 C3.12016664,12.2501422 2.79891626,11.3155956 3.12434807,10.664732 L6.08657328,3.39132136 C6.28474455,3.02758928 6.74025722,2.89337573 7.10398929,3.091547 Z M17.4817165,11.0083008 L20.9578857,21.1240903 L19.222464,21.1240903 L18.4837544,18.9060741 L14.9792731,18.9060741 L14.3788178,21.1240903 L12.8065094,21.1240903 L15.9303912,11.0083008 L17.4817165,11.0083008 Z M16.7858212,13.0526316 L15.4288103,17.4736842 L18.1571089,17.4736842 L16.7858212,13.0526316 Z" id="path-1"></path>
</defs>
<g id="ic/camera/public/flash_auto" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<mask id="mask-2" fill="white">
<use xlink:href="#path-1"></use>
</mask>
<use id="flash_auto" fill="#006cde" xlink:href="#path-1"></use>
<g id="ic/bg/white" mask="url(#mask-2)" fill="#FFFFFF" fill-rule="nonzero">
<!-- <rect id="Rectangle-13-Copy" x="0" y="0" width="24" height="24"></rect>-->
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 63.1 (92452) - https://sketch.com -->
<title>ic/camera/public/flash_off</title>
<desc>Created with Sketch.</desc>
<defs>
<path d="M13.2087918,19.3310489 L14.4100571,19.8409557 C14.5371523,19.8949044 14.5964492,20.0416695 14.5425005,20.1687647 C14.5188724,20.224429 14.4758691,20.2696424 14.4214577,20.2960281 L11.5903859,21.6689034 C11.4661515,21.7291486 11.3166014,21.677275 11.2563562,21.5530407 C11.2514421,21.5429071 11.2472184,21.532453 11.243714,21.5217499 L10.2646501,18.5315679 C10.2216863,18.4003514 10.2932294,18.2591505 10.4244459,18.2161867 C10.4819152,18.1973698 10.5442571,18.2000209 10.5999213,18.223649 L11.8276348,18.7447825 L13.2656556,15.3031887 L10.2126091,12.2501422 L8.76672812,12.2501422 C7.89172629,12.2501422 7.57047591,11.3155956 7.89590773,10.664732 L8.10754569,10.1450788 L3.21966991,5.2188888 C2.9267767,4.92599558 2.9267767,4.45112184 3.21966991,4.15822863 C3.51256313,3.86533541 3.98743687,3.86533541 4.28033009,4.15822863 L20.2159701,20.120016 C20.5088633,20.4129093 20.5088633,20.887783 20.2159701,21.1806762 C19.9230768,21.4735694 19.4482031,21.4735694 19.1553099,21.1806762 L14.428412,16.465945 L13.2087918,19.3310489 L13.2087918,19.3310489 Z M14.5413275,12.2501422 L13.7418885,12.2501422 L12.2418885,10.7501422 L15.2667281,10.7501422 C16.0925722,10.7501422 16.5220955,11.6664585 16.1820671,12.3462983 L15.4805599,13.9897104 L14.3037483,12.8128987 L14.5413275,12.2501422 Z M10.8581329,3.39132136 C11.0563042,3.02758928 11.5118169,2.89337573 11.8755489,3.091547 C12.239281,3.28971827 12.3734946,3.74523093 12.1753233,4.108963 L10.3192135,8.81951384 L9.13253225,7.6328326 L10.8581329,3.39132136 Z" id="path-1"></path>
</defs>
<g id="ic/camera/public/flash_off" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<mask id="mask-2" fill="white">
<use xlink:href="#path-1"></use>
</mask>
<use id="flash_off" fill="#FFFFFF" xlink:href="#path-1"></use>
<g id="ic/bg/white" mask="url(#mask-2)" fill="#FFFFFF" fill-rule="nonzero">
<!-- <rect id="Rectangle-13-Copy" x="0" y="0" width="24" height="24"></rect>-->
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 63.1 (92452) - https://sketch.com -->
<title>ic/camera/public/flash_off</title>
<desc>Created with Sketch.</desc>
<defs>
<path d="M13.2087918,19.3310489 L14.4100571,19.8409557 C14.5371523,19.8949044 14.5964492,20.0416695 14.5425005,20.1687647 C14.5188724,20.224429 14.4758691,20.2696424 14.4214577,20.2960281 L11.5903859,21.6689034 C11.4661515,21.7291486 11.3166014,21.677275 11.2563562,21.5530407 C11.2514421,21.5429071 11.2472184,21.532453 11.243714,21.5217499 L10.2646501,18.5315679 C10.2216863,18.4003514 10.2932294,18.2591505 10.4244459,18.2161867 C10.4819152,18.1973698 10.5442571,18.2000209 10.5999213,18.223649 L11.8276348,18.7447825 L13.2656556,15.3031887 L10.2126091,12.2501422 L8.76672812,12.2501422 C7.89172629,12.2501422 7.57047591,11.3155956 7.89590773,10.664732 L8.10754569,10.1450788 L3.21966991,5.2188888 C2.9267767,4.92599558 2.9267767,4.45112184 3.21966991,4.15822863 C3.51256313,3.86533541 3.98743687,3.86533541 4.28033009,4.15822863 L20.2159701,20.120016 C20.5088633,20.4129093 20.5088633,20.887783 20.2159701,21.1806762 C19.9230768,21.4735694 19.4482031,21.4735694 19.1553099,21.1806762 L14.428412,16.465945 L13.2087918,19.3310489 L13.2087918,19.3310489 Z M14.5413275,12.2501422 L13.7418885,12.2501422 L12.2418885,10.7501422 L15.2667281,10.7501422 C16.0925722,10.7501422 16.5220955,11.6664585 16.1820671,12.3462983 L15.4805599,13.9897104 L14.3037483,12.8128987 L14.5413275,12.2501422 Z M10.8581329,3.39132136 C11.0563042,3.02758928 11.5118169,2.89337573 11.8755489,3.091547 C12.239281,3.28971827 12.3734946,3.74523093 12.1753233,4.108963 L10.3192135,8.81951384 L9.13253225,7.6328326 L10.8581329,3.39132136 Z" id="path-1"></path>
</defs>
<g id="ic/camera/public/flash_off" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<mask id="mask-2" fill="white">
<use xlink:href="#path-1"></use>
</mask>
<use id="flash_off" fill="#006cde" xlink:href="#path-1"></use>
<g id="ic/bg/white" mask="url(#mask-2)" fill="#FFFFFF" fill-rule="nonzero">
<!-- <rect id="Rectangle-13-Copy" x="0" y="0" width="24" height="24"></rect>-->
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 63.1 (92452) - https://sketch.com -->
<title>ic/camera/public/flash_on</title>
<desc>Created with Sketch.</desc>
<defs>
<path d="M12.1039893,3.091547 C12.4677214,3.28971827 12.6019349,3.74523093 12.4037637,4.108963 L9.78546603,10.7501422 L15.4951685,10.7501422 C16.3210126,10.7501422 16.7505358,11.6664585 16.4105074,12.3462983 L13.446,19.335 L14.6367878,19.8408135 C14.763883,19.8947622 14.8231799,20.0415273 14.7692312,20.1686225 C14.7456031,20.2242868 14.7025998,20.2695002 14.6481885,20.2958859 L11.8171166,21.6687612 C11.6928823,21.7290064 11.5433321,21.6771328 11.483087,21.5528985 C11.4781729,21.5427649 11.4739492,21.5323108 11.4704447,21.5216077 L10.4913808,18.5314258 C10.4484171,18.4002093 10.5199601,18.2590083 10.6511766,18.2160446 C10.7086459,18.1972276 10.7709878,18.1998788 10.8266521,18.2235068 L12.064,18.748 L14.7697679,12.2501422 L8.99516847,12.2501422 C8.12016664,12.2501422 7.79891626,11.3155956 8.12434807,10.664732 L11.0865733,3.39132136 C11.2847446,3.02758928 11.7402572,2.89337573 12.1039893,3.091547 Z" id="path-1"></path>
</defs>
<g id="ic/camera/public/flash_on" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<mask id="mask-2" fill="white">
<use xlink:href="#path-1"></use>
</mask>
<use id="flash_on" fill="#FFFFFF" xlink:href="#path-1"></use>
<g id="ic/bg/white" mask="url(#mask-2)" fill="#FFFFFF" fill-rule="nonzero">
<!-- <rect id="Rectangle-13-Copy" x="0" y="0" width="24" height="24"></rect>-->
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 63.1 (92452) - https://sketch.com -->
<title>ic/camera/public/flash_on</title>
<desc>Created with Sketch.</desc>
<defs>
<path d="M12.1039893,3.091547 C12.4677214,3.28971827 12.6019349,3.74523093 12.4037637,4.108963 L9.78546603,10.7501422 L15.4951685,10.7501422 C16.3210126,10.7501422 16.7505358,11.6664585 16.4105074,12.3462983 L13.446,19.335 L14.6367878,19.8408135 C14.763883,19.8947622 14.8231799,20.0415273 14.7692312,20.1686225 C14.7456031,20.2242868 14.7025998,20.2695002 14.6481885,20.2958859 L11.8171166,21.6687612 C11.6928823,21.7290064 11.5433321,21.6771328 11.483087,21.5528985 C11.4781729,21.5427649 11.4739492,21.5323108 11.4704447,21.5216077 L10.4913808,18.5314258 C10.4484171,18.4002093 10.5199601,18.2590083 10.6511766,18.2160446 C10.7086459,18.1972276 10.7709878,18.1998788 10.8266521,18.2235068 L12.064,18.748 L14.7697679,12.2501422 L8.99516847,12.2501422 C8.12016664,12.2501422 7.79891626,11.3155956 8.12434807,10.664732 L11.0865733,3.39132136 C11.2847446,3.02758928 11.7402572,2.89337573 12.1039893,3.091547 Z" id="path-1"></path>
</defs>
<g id="ic/camera/public/flash_on" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<mask id="mask-2" fill="white">
<use xlink:href="#path-1"></use>
</mask>
<use id="flash_on" fill="#006cde" xlink:href="#path-1"></use>
<g id="ic/bg/white" mask="url(#mask-2)" fill="#FFFFFF" fill-rule="nonzero">
<!-- <rect id="Rectangle-13-Copy" x="0" y="0" width="24" height="24"></rect>-->
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg viewBox="0 0 76 76" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>ic_circled</title>
<g id="ic_circled" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<path d="M38,76 C17.0131795,76 0,58.9868205 0,38 C0,17.0131795 17.0131795,0 38,0 C58.9868205,0 76,17.0131795 76,38 C76,58.9868205 58.9868205,76 38,76 Z M38,75 C58.4345357,75 75,58.4345357 75,38 C75,17.5654643 58.4345357,1 38,1 C17.5654643,1 1,17.5654643 1,38 C1,58.4345357 17.5654643,75 38,75 Z" id="Oval" fill="#000000" fill-rule="nonzero"></path>
</g>
</svg>

After

Width:  |  Height:  |  Size: 646 B

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg viewBox="0 0 54 54" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>ic_circled_filled</title>
<g id="ic_circled_filled" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<circle id="Path" fill="#000000" cx="27" cy="27" r="27"></circle>
</g>
</svg>

After

Width:  |  Height:  |  Size: 377 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 204 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 204 B

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="42.2px" height="42.2px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<svg viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 52.5 (67469) - http://www.bohemiancoding.com/sketch -->
<title>ic_system_back </title>
<desc>Created with Sketch.</desc>

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 1020 B

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<svg viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 52.5 (67469) - http://www.bohemiancoding.com/sketch -->
<title>ic_mode_edit_cancel</title>
<desc>Created with Sketch.</desc>

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<svg viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 52.5 (67469) - http://www.bohemiancoding.com/sketch -->
<title>ic_mode_edit_confirm</title>
<desc>Created with Sketch.</desc>

Before

Width:  |  Height:  |  Size: 963 B

After

Width:  |  Height:  |  Size: 936 B

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg viewBox="0 0 20 20" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>ic_video_end</title>
<g id="ic_video_end" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="编组" fill="#000000">
<rect id="Rectangle-11" x="2" y="2" width="16" height="16" rx="2"></rect>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 431 B

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg viewBox="0 0 20 20" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>ic_video_pause</title>
<g id="ic_video_pause" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<circle id="Oval-4-Copy-2" fill="#000000" cx="10" cy="10" r="9"></circle>
</g>
</svg>

After

Width:  |  Height:  |  Size: 379 B

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg viewBox="0 0 20 20" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>ic_video_recording</title>
<g id="ic_video_recording" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Combined-Shape" fill="#000000" transform="translate(3.000000, 2.000000)">
<path d="M4.54166667,0.5 C4.79479718,0.5 5,0.705202823 5,0.958333333 L5,15.0416667 C5,15.2947972 4.79479718,15.5 4.54166667,15.5 L0.458333333,15.5 C0.205202823,15.5 2.53044152e-16,15.2947972 0,15.0416667 L0,0.958333333 C2.45116043e-17,0.705202823 0.205202823,0.5 0.458333333,0.5 L4.54166667,0.5 Z M13.5416667,0.5 C13.7947972,0.5 14,0.705202823 14,0.958333333 L14,15.0416667 C14,15.2947972 13.7947972,15.5 13.5416667,15.5 L9.45833333,15.5 C9.20520282,15.5 9,15.2947972 9,15.0416667 L9,0.958333333 C9,0.705202823 9.20520282,0.5 9.45833333,0.5 L13.5416667,0.5 Z"></path>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 987 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 63.1 (92452) - https://sketch.com -->
<title>ic/camera/setting/resolution/photo</title>
<desc>Created with Sketch.</desc>
<defs>
<path d="M7,16.25 L7,18.5 L6,18.5 L6,16.25 L7,16.25 Z M18,16.25 L18,18.5 L17,18.5 L17,16.25 L18,16.25 Z M7,12.75 L7,14.75 L6,14.75 L6,12.75 L7,12.75 Z M18,12.75 L18,14.75 L17,14.75 L17,12.75 L18,12.75 Z M7,9.25 L7,11.25 L6,11.25 L6,9.25 L7,9.25 Z M18,9.25 L18,11.25 L17,11.25 L17,9.25 L18,9.25 Z M7,5.5 L7,7.75 L6,7.75 L6,5.5 L7,5.5 Z M18,5.5 L18,7.75 L17,7.75 L17,5.5 L18,5.5 Z M3.5,5.5 L3.5,18.5 L20.5,18.5 L20.5,5.5 L3.5,5.5 Z M3.5,4 L20.5,4 C21.3284271,4 22,4.67157288 22,5.5 L22,18.5 C22,19.3284271 21.3284271,20 20.5,20 L3.5,20 C2.67157288,20 2,19.3284271 2,18.5 L2,5.5 C2,4.67157288 2.67157288,4 3.5,4 Z" id="path-1"></path>
</defs>
<g id="ic/camera/setting/resolution/photo" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<mask id="mask-2" fill="white">
<use xlink:href="#path-1"></use>
</mask>
<use id="photo" fill="#FFFFFF" xlink:href="#path-1"></use>
<g id="ic/bg/white" mask="url(#mask-2)" fill="#FFFFFF" fill-rule="nonzero">
<!-- <rect id="Rectangle-13-Copy" x="0" y="0" width="24" height="24"></rect>-->
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 63.1 (92452) - https://sketch.com -->
<title>ic/camera/setting/sd/card</title>
<desc>Created with Sketch.</desc>
<g id="ic/camera/setting/sd/card" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<path d="M15.1078844,2.75 L18.2941176,5.77372412 L18.2941176,7.80169606 L20,9.48242686 L20,12.3459344 L18.7205882,12.3431837 L18.7205882,12.6092603 L20,13.8894101 L20,19.75 C20,20.5784271 19.3284271,21.25 18.5,21.25 L5.5,21.25 C4.67157288,21.25 4,20.5784271 4,19.75 L4,4.25 C4,3.42157288 4.67157288,2.75 5.5,2.75 L15.1078844,2.75 Z M14.5094305,4.25 L5.5,4.25 L5.5,19.75 L18.5,19.75 L18.5,14.5104771 L17.2205882,13.2303273 L17.2205882,10.8399553 L18.5,10.842706 L18.5,10.1102829 L16.7941176,8.4295521 L16.7941176,6.41816007 L14.5094305,4.25 Z M8.33264159,5.99968273 C8.42526659,5.99968273 8.50045409,6.08647028 8.50045409,6.19386986 L8.50045409,6.19386986 L8.50045409,9.27699728 C8.50045409,9.38439686 8.42526659,9.4711844 8.33264159,9.4711844 L8.33264159,9.4711844 L7.16826659,9.4711844 C7.07545409,9.4711844 7.00045409,9.38439686 7.00045409,9.27699728 L7.00045409,9.27699728 L7.00045409,6.19386986 C7.00045409,6.08647028 7.07545409,5.99968273 7.16826659,5.99968273 L7.16826659,5.99968273 Z M11.2616866,6.00004986 C11.3543116,6.00004986 11.4294991,6.08683741 11.4294991,6.19423699 L11.4294991,6.19423699 L11.4294991,9.27736441 C11.4294991,9.38476399 11.3543116,9.47155153 11.2616866,9.47155153 L11.2616866,9.47155153 L10.0973116,9.47155153 C10.0044991,9.47155153 9.92949912,9.38476399 9.92949912,9.27736441 L9.92949912,9.27736441 L9.92949912,6.19423699 C9.92949912,6.08683741 10.0044991,6.00004986 10.0973116,6.00004986 L10.0973116,6.00004986 Z M14.1907316,6.00004986 C14.2833566,6.00004986 14.3585441,6.08683741 14.3585441,6.19423699 L14.3585441,6.19423699 L14.3585441,9.27736441 C14.3585441,9.38476399 14.2833566,9.47155153 14.1907316,9.47155153 L14.1907316,9.47155153 L13.0263566,9.47155153 C12.9335441,9.47155153 12.8585441,9.38476399 12.8585441,9.27736441 L12.8585441,9.27736441 L12.8585441,6.19423699 C12.8585441,6.08683741 12.9335441,6.00004986 13.0263566,6.00004986 L13.0263566,6.00004986 Z" id="Combined-Shape" fill="#FFFFFF" fill-rule="nonzero"></path>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 63.1 (92452) - https://sketch.com -->
<title>ic/camera/setting/sound_mute</title>
<desc>Created with Sketch.</desc>
<defs>
<path d="M5.53033009,3.21966991 L21.0796997,18.7690395 C21.3725929,19.0619327 21.3725929,19.5368064 21.0796997,19.8296997 C20.7868064,20.1225929 20.3119327,20.1225929 20.0190395,19.8296997 L14.75,14.5606602 L14.75,20 C14.75,20.2664264 14.4679002,20.4643516 14.25,20.5 C13.8886788,20.5591119 13.5398154,20.3355077 13.4347231,20.2532615 L8,16 L5,16 C4.02258037,15.9539088 3.25,15.1877165 3.25,14.25 L3.25,9.75 C3.25,8.78418149 3.94725378,8.04440201 4.85499432,8.00099769 L8,8 L8.10518879,7.91584897 L4.46966991,4.28033009 C4.1767767,3.98743687 4.1767767,3.51256313 4.46966991,3.21966991 C4.76256313,2.9267767 5.23743687,2.9267767 5.53033009,3.21966991 Z M9.21966991,9.03033009 L9,9.25 L8.5,9.5 L5,9.5 C4.87891063,9.48386855 4.81869991,9.52911712 4.75,9.5 C4.75526803,9.59231345 4.73668448,9.63351746 4.75,9.75 L4.75,14.25 C4.73668448,14.3479637 4.84620357,14.4374497 5,14.5 L8.5,14.5 L9,14.75 L13.25,18 L13.25,13.0606602 L9.21966991,9.03033009 Z M19.9039421,7.91751901 C20.5515297,9.16896417 20.8943117,10.5606797 20.8943117,12 C20.8943117,13.4339274 20.5540973,14.8206417 19.9111383,16.0685444 L19.8646856,16.1430514 L18.7487772,15.0265322 C19.1719585,14.0846453 19.3943117,13.0589169 19.3943117,12 C19.3943117,10.8020046 19.1097107,9.64650715 18.5717409,8.60689563 C18.3813748,8.23901844 18.525276,7.78647285 18.8931532,7.59610675 C19.2610304,7.40574065 19.713576,7.54964182 19.9039421,7.91751901 Z M14.25,3.5 C14.469373,3.52558058 14.75,3.73324901 14.75,4 L14.75,11.029068 L13.25,9.52906799 L13.25,6 L11.1915436,7.47186279 L10.1915436,6.47186279 L13.4559153,3.74884091 C13.5539435,3.66589394 13.8771295,3.45652043 14.25,3.5 Z" id="path-1"></path>
</defs>
<g id="ic/camera/setting/sound_mute" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<mask id="mask-2" fill="white">
<use xlink:href="#path-1"></use>
</mask>
<use id="sound_mute" fill="#FFFFFF" fill-rule="nonzero" xlink:href="#path-1"></use>
<g id="ic/bg/white" mask="url(#mask-2)" fill="#FFFFFF" fill-rule="nonzero">
<!-- <rect id="Rectangle-13-Copy" x="0" y="0" width="24" height="24"></rect>-->
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

Before

Width:  |  Height:  |  Size: 939 B

After

Width:  |  Height:  |  Size: 939 B

Before

Width:  |  Height:  |  Size: 1018 B

After

Width:  |  Height:  |  Size: 1018 B

Some files were not shown because too many files have changed in this diff Show More