Signed-off-by: z00513345 <zhuchengfeng1@huawei.com>
This commit is contained in:
z00513345 2022-07-26 20:14:17 +08:00
parent 95e93ff541
commit b98327f0ea
287 changed files with 7327 additions and 4256 deletions

27
.gitignore vendored
View File

@ -1,25 +1,14 @@
*.iml
.gradle
/node_modules
/local.properties
.idea/*
.idea/gradle.xml
/.idea
/.deveco
**/build
*.iml
.DS_Store
build/outputs/hap/*
build/outputs/app/release/com.ohos.photos-release-unsigned.app
build/outputs/app/release/pack.info
/build
/captures
.externalNativeBuild
/entry/.preview
.cxx
module_photos.xml
photos.properties
photos.xml
photos_Mon_Jan_25_09-05-43_GMT+08-00_2021.properties
photos_Mon_Jan_25_09-05-43_GMT+08-00_2021.xml
module_photos_Mon_Jan_25_09-05-43_GMT+08-00_2021.xml
/package-lock.json
/entry/build/
/.gradle/
/.preview/
/.local.properties
/.gradle.properties

View File

@ -0,0 +1,5 @@
{
"totalTime": 2467438200,
"moduleNum": 0,
"taskTime": {}
}

View File

@ -1,17 +1,3 @@
/*
* 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.
*/
{
"app": {
"bundleName": "com.ohos.photos",

View File

@ -2,7 +2,7 @@
"string": [
{
"name": "app_name",
"value": "photos"
"value": "Gallery"
}
]
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.6 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

36
README.en.md Normal file
View File

@ -0,0 +1,36 @@
# NewPhotos
#### Description
{**When you're done, you can delete the content in this README and update the file with details for others getting started with your repository**}
#### Software Architecture
Software architecture description
#### Installation
1. xxxx
2. xxxx
3. xxxx
#### Instructions
1. xxxx
2. xxxx
3. xxxx
#### Contribution
1. Fork the repository
2. Create Feat_xxx branch
3. Commit your code
4. Create Pull Request
#### Gitee Feature
1. You can use Readme\_XXX.md to support different languages, such as Readme\_en.md, Readme\_zh.md
2. Gitee blog [blog.gitee.com](https://blog.gitee.com)
3. Explore open source project [https://gitee.com/explore](https://gitee.com/explore)
4. The most valuable open source project [GVP](https://gitee.com/gvp)
5. The manual of Gitee [https://gitee.com/help](https://gitee.com/help)
6. The most popular members [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)

View File

@ -1,40 +1,39 @@
# Photos<a name="EN-US_TOPIC_0000001177189635"></a>
# NewPhotos
- [Introduction](#section443318452403)
- [Architecture](#section17686421134110)
#### 介绍
{**以下是 Gitee 平台说明,您可以替换此简介**
Gitee 是 OSCHINA 推出的基于 Git 的代码托管平台(同时支持 SVN。专为开发者提供稳定、高效、安全的云端软件开发协作平台
无论是个人、团队、或是企业,都能够用 Gitee 实现代码托管、项目管理、协作开发。企业项目请看 [https://gitee.com/enterprises](https://gitee.com/enterprises)}
- [Directory Structure](#section7867113874118)
- [Repositories Involved](#section229716044218)
#### 软件架构
软件架构说明
## Introduction<a name="section443318452403"></a>
The Photos app is a pre-installed system app in the OpenHarmony system. It provides users with basic image browsing and album management functions, including viewing, moving, copying, deleting, and renaming images and videos.
#### 安装教程
### Architecture<a name="section17686421134110"></a>
1. xxxx
2. xxxx
3. xxxx
![](figures/l2.png)
#### 使用说明
## Directory Structure<a name="section7867113874118"></a>
1. xxxx
2. xxxx
3. xxxx
```
/applications/standard/photos/
├── figures # Architecture figures
├── entry
│ └── src
│ └── main
│ ├── config.json # Global configuration file
│ ├── resources # Resource configuration files
│ └── js # JavaScript code
│ └── common # Public resources
│ └── i18n # Internationalization
│ └── pages # Page code
├── signature # Certificate files
├── LICENSE # License files
```
#### 参与贡献
## Repositories Involved<a name="section229716044218"></a>
1. Fork 本仓库
2. 新建 Feat_xxx 分支
3. 提交代码
4. 新建 Pull Request
System apps
**applications\_standard\_photos**
#### 特技
1. 使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md
2. Gitee 官方博客 [blog.gitee.com](https://blog.gitee.com)
3. 你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解 Gitee 上的优秀开源项目
4. [GVP](https://gitee.com/gvp) 全称是 Gitee 最有价值开源项目,是综合评定出的优秀开源项目
5. Gitee 官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help)
6. Gitee 封面人物是一档用来展示 Gitee 会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)

View File

@ -1,377 +0,0 @@
# 图库源码开发说明
## 1. 简介
图库是系统内置的可视资源访问应用,提供图片和视频的管理、浏览、显示、编辑操作等功能,并支持默认相册和用户相册管理。
图库项目采用 TS 语言开发。
![](./figures/1层逻辑.png)
图库整体以 OpenHarmony 既有的 MVVM 的 App 架构设计为基础,向下扩展出一套 MVPView, Presenter, Model分层架构既有的 MVVM 框架整体理解为新扩展的 MVP 框架的 View 层),用于处理图库的业务逻辑与数据管理。
各层的作用分别如下:
- 视图层View负责更新 UI 显示以及触摸与点击事件的监听。
- 展现层Presenter负责处理视图层View发送的业务逻辑处理请求并连通 Model 层获取数据。
- 模型层Model负责处理展现层Presenter 中关于数据处理的请求以及返回数据请求结果。
应用各层中重要类及其功能如下表所示
| 模块 | 层级 | 类名 | 作用 |
| ------ | ------ | ------------------------ | ------------------------------------ |
| photos | 视图层 | phone.view.Index | phone图库入口画面的视图层逻辑控制类 |
| photos | 视图层 | pad.view.Index | pad图库入口画面的视图层逻辑控制类 |
| photos | 视图层 | TimelinePage | 图库图片视图层逻辑控制类 |
| photos | 视图层 | AlbumSetPage | 图库相册视图层逻辑控制类 |
| photos | 视图层 | PhotoBrowser | 图库大图浏览视图层逻辑控制类 |
| photos | 视图层 | PhotoGridPage | 图库宫格视图层逻辑控制类 |
| photos | 视图层 | ThirdSelectAlbumSetPage | 图库三方选择相册视图层逻辑控制类 |
| photos | 视图层 | ThirdSelectPhotoGridPage | 图库三方选择宫格视图层逻辑控制类 |
| photos | 视图层 | ThirdSelectPhotoBrowser | 图库三方选择大图浏览视图层逻辑控制类 |
| photos | 展现层 | PhotoDataSource | 图库列大图浏览展现层数据逻辑类 |
| photos | 展现层 | TimelineDataSource | 图库日试图展现层数据逻辑类 |
| photos | 展现层 | AlbumSetDataSource | 图库相册展现层数据逻辑类 |
| photos | 展现层 | MediaDataSource | 图库宫格展现层数据逻辑类 |
| photos | 展现层 | TimelineSelectManager | 图库日试图展现层选择逻辑类 |
| photos | 展现层 | ThirdSelectManager | 图库三方选择展现层选择逻辑类 |
| photos | 展现层 | AlbumSetSelectManager | 图库相册展现层选择逻辑类 |
| photos | 展现层 | SelectManager | 图库展现层选择逻辑类 |
| photos | 展现层 | BroadCast | 图库展现层消息分发类 |
| photos | 模型层 | AlbumInfo | 图库模型层相册信息类 |
| photos | 模型层 | MediaItem | 图库模型层媒体信息类 |
| photos | 模型层 | Thumbnail | 图库模型层媒体缩略信息类 |
## 2. 目录
```
/applications
├── src
│ └── main
│ ├── ets # ets代码目录
│ ├── MainAbility
│ ├── common # 共同代码目录
│ ├── access # 媒体库接口目录
│ ├── model # model目录
│ ├── browser # 浏览model目录
│ ├── album # 相册model目录
│ ├── dataObserver # 数据注册model目录
│ ├── interface # 接口model目录
│ ├── operation # 操作项model目录
│ └── photo # 照片model目录
│ └── common #共同业务逻辑和实体模型目录
│ ├── utils # 共同工具目录
│ └── view # 共同视图组件
│ ├── actionbar 共同标题栏、底层栏和工具栏组件目录
│ ├── dialog 共同对话框目录。
│ └── mediaOperation 共同相册选择页目录
│ ├── feature # 功能模块目录
│ ├── brower # 图库浏览功能目录
│ ├── utils # 图库浏览工具目录
│ └── view # 图库浏览视图目录
│ ├── album # 相册视图目录
│ ├── photo # 照片视图目录
│ └── photoGrid # 照片宫格目录
│ ├── thirdSelect # 第三方选择功能目录
│ ├── utils # 第三方选择工具目录
│ └── view # 第三方视图目录
│ └── timeline # 日视图宫格功能目录
│ ├── model # 日视图model目录
│ ├── utils # 日试图工具目录
│ └── view # 日试图视图目录
│ ├── product # 产品模块目录
│ ├── pad # pad模块目录
│ └── view # pad模块视图目录
│ └── phone # phone模块目录
│ └── view # phone模块视图目录
│ ├── resources # 资源目录
│ └── config.json # 项目配置信息
```
###
## 3. 基础开发说明
### 资源引用
#### 定义资源文件
- 在 `src/main/resources/`目录下,根据不同的资源类型,定义资源文件。
```json
{
"name": "default_background_color",
"value": "#F1F3F5"
},
```
#### 引用资源
- 在有对应page的ets文件中可直接通过`$r()`引用。
```` JavaScript
@Provide backgroundColor: Resource = $r('app.color.default_background_color');
````
## 4. 典型接口的使用
1. 相机启动图库大图浏览
```
this.context.startAbility({
bundleName:"com.ohos.photos",
abilityName: "com.ohos.photos.MainAbility",
parameters: {
uri: "photodetail"
}
}).then((data) => {
console.debug('startAbility complete');
}).catch((error) => {
console.debug(`startAbility failed, error: ${JSON.stringify(error)}`);
})
```
2. 三方应用启动图库三方单选
```
let startParmameter = {
bundleName:"com.ohos.photos",
abilityName: "com.ohos.photos.MainAbility",
parameters: {
uri: "singleselect"
}
};
this.context.startAbilityForResult(startParmameter).then((result) => {
console.info(`startAbilityForResult Promise.resolve is called, result.resultCode = ${JSON.stringify(result)}`)
let want = result['want'];
console.info(`test select single ${JSON.stringify(want)}`);
if (want != null && want != undefined) {
let param = want['parameters'];
console.info(`test select single ${JSON.stringify(param)}`);
if (param != null && param != undefined) {
let uri = param['select-item-list'];
console.info(`test select single ${uri}`);
}
}
}, (error) => {
console.info(`startAbilityForResult Promise.Reject is called, error.code = ${error.code}`)
})
```
3. 三方应用启动图库三方多选
```
let startParmameter = {
bundleName:"com.ohos.photos",
abilityName: "com.ohos.photos.MainAbility",
parameters: {
uri: "multipleselect"
}
};
this.context.startAbilityForResult(startParmameter).then((v) => {
let want = v['want'];
console.info(`test select multiple ${want}`);
if (want != null && want != undefined) {
let param = want['parameters'];
console.info(`test select multiple ${param}`);
if (param != null && param != undefined) {
let uri = param['select-item-list'];
console.info(`test select multiple ${uri[0]} ${uri[1]}`);
}
}
}, (error) => {
console.debug(`startAbility failed, error: ${JSON.stringify(error)}`);
})
```
## 5. 签名打包
### 签名
#### 签名文件的获取
1. 拷贝 OpenHarmony 标准版的 prebuilts\signcenter 目录到操作目录。
2. 拷贝图库工程的 signature\photos.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)
## 6. 安装、运行、调试
### 应用安装
配置 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
```
变更根目录读写权限
```
hdc shell "mount -o remount,rw /"
```
将签名好的 hap 包放入设备的 `/system/app` 目录下并修改hap包的权限。删除和发送文件命令如下
```
hdc file send 本地路径 /system/app/hap包名称
```
例:将当前本地目录的 `Photos.hap` 文件放入到 `system/app/Photos.hap` 文件中。
```
hdc file send Photos.hap /system/app/Photos.hap
```
> 注意,如果设备不存在 `/system/app` 目录,则需要手动创建该目录并修改权限。
> ```
> hdc shell
> cd system
> mkdir app
> chmod 777 app
> ```
> `/system/app` 目录放置系统应用例如PhotosSystemUISettings 等。
>
> 但hap包需要在该目录下手动设置权限
> ```
> chmod 666 hap包名
> ```
> 此目录应用不用手动安装,系统自动拉起。
### 应用运行
图库属于系统应用,在将签名的 hap 包放入 `/system/app` 目录后,重启系统,应用会自动拉起。
```
hdc_std shell "reboot"
```
> 注意,如果设备之前安装过系统应用,则需要执行如下几条命令清除设备中存储的应用信息才能够在设备重启的时候将我们装入设备的新 hap 包正常拉起。
> ```
> hdc_std shell "rm /data/* -rf"
> hdc_std shell "sync"
> hdc_std shell "/system/bin/udevadm trigger"
> ```
### 应用调试
#### log打印
- 在程序中添加 log
```JS
private log: Logger = new Logger('MoudleXXX')
entry() {
let input = 'hello'
this.log.info(`entry: ${input}`)
}
```
上述log打印为
```
Photos_MoudleXXX:entry: hello
```
可以在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 过滤信息
```
例:过滤包含信息 Album的 hilog
```
hilog | grep Album
```
## 7. 贡献代码
### Fork 代码仓库
1. 在码云上打开 photos代码仓库[仓库地址](https://gitee.com/OHOS_STD/applications_photos))。
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. 在本地新建 Photos 目录,在 Photos 目录中执行如下命令
```
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)

1
entry/.gitignore vendored
View File

@ -1,2 +1,3 @@
/node_modules
/build
/package-lock.json

View File

@ -1,17 +1,3 @@
/*
* 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.
*/
{
"apiType": 'stageMode',
"buildOption": {

View File

@ -1,16 +1,2 @@
/*
* 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.
*/
// Script for compiling build behavior. It is built in the build plug-in and cannot be modified currently.
module.exports = require('@ohos/hvigor-ohos-plugin').hapTasks

View File

@ -1,15 +1,10 @@
{
"name": "photos",
"name": "entry",
"version": "1.0.0",
"ohos": {
"org": "huawei",
"buildTool": "hvigor",
"directoryLevel": "project"
"directoryLevel": "module"
},
"dependencies": {
"@ohos/hvigor": "^1.0.6",
"@ohos/hvigor-base": "^1.0.6",
"@ohos/hvigor-ohos-plugin": "^1.0.6",
"@ohos/sdkmanager-common": "^1.1.1"
}
"dependencies": {}
}

View File

@ -2,5 +2,6 @@ import AbilityStage from "@ohos.application.AbilityStage"
export default class PhotosAbilityStage extends AbilityStage {
onCreate() {
globalThis.photosGlobalContext = this.context;
}
}

View File

@ -0,0 +1,78 @@
/*
* 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 FormExtension from '@ohos.application.FormExtension';
import {Logger} from './common/Logger'
import {FormControllerManager} from './controller/FormControllerManager'
import {FormController} from './controller/FormController'
import {Constants} from './common/Constants'
export default class FormAbility extends FormExtension {
private logger: Logger = new Logger('FormAbility');
onCreate(want) {
this.logger.info(`form onCreate. want ${JSON.stringify(want)}`);
let param = want.parameters;
let formId = param['ohos.extra.param.key.form_identity'];
this.logger.info(`form onCreate formId: ${formId}`);
let formControllerManager: FormControllerManager = FormControllerManager.getInstance(this.context);
formControllerManager.initData(formId, Constants.PHOTOS_FORM_OPERATION_MODE_NONE).then(() => {
let formController: FormController = formControllerManager.getController(formId);
this.logger.info(`form onCreate. formController ${formController}`);
formController = (formController == null) ? formControllerManager.createFormController(formId,
Constants.PHOTOS_FORM_OPERATION_MODE_NONE) : formController;
if (formController == null) {
this.logger.error(`Get null controller. formId: ${formId}`);
return null;
}
return formController.bindFormData(formId);
}).catch((err) => {
this.logger.error(`init err ${err}`);
})
return null;
}
onCastToNormal(formId) {
this.logger.info(`onCastToNormal, formId: ${formId}`);
}
onUpdate(formId) {
this.logger.info(`onUpdate, formId: ${formId} context ${JSON.stringify(this.context)}`);
let formControllerManager: FormControllerManager = FormControllerManager.getInstance(this.context);
formControllerManager.updateController(formId);
}
onVisibilityChange(newStatus) {
this.logger.info(`onVisibilityChange, newStatus: ${JSON.stringify(newStatus)}`);
let formControllerManager: FormControllerManager = FormControllerManager.getInstance(this.context);
for (let key in newStatus) {
this.logger.info(`onVisibilityChange, key:${key} value ${newStatus[key]}`);
let formId = key;
formControllerManager.initData(formId, Constants.PHOTOS_FORM_OPERATION_MODE_NONE);
}
}
onEvent(formId, message) {
this.logger.info(`onEvent, formId: ${formId}, message: ${message}`);
let formControllerManager: FormControllerManager = FormControllerManager.getInstance(this.context);
formControllerManager.onEvent(formId, message);
}
onDestroy(formId) {
this.logger.info(`onDestroy, formId: ${formId}`);
let formControllerManager: FormControllerManager = FormControllerManager.getInstance(this.context);
formControllerManager.destroyController(formId);
}
};

View File

@ -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.
*/
export class Constants {
// string value
static readonly FROM_CONTROLLER_MANAGER = 'form_controller_manager';
static readonly PHOTOS_FORM_STORAGE_PREFIX = 'photos_form_';
static readonly PHOTOS_FORM_CAMERA_NAME = 'Camera';
static readonly PHOTOS_FORM_ALBUM_NAME_ALL = 'default_all';
static readonly PHOTOS_FORM_OPERATION_MODE_NONE = 0;
static readonly PHOTOS_FORM_OPERATION_MODE_DESTROY = 1;
static readonly PHOTOS_FORM_OPERATION_MODE_UPDATE = 2;
static readonly PHOTOS_FORM_OPERATION_MODE_EVENT = 3;
static readonly PHOTOS_FORM_OPERATION_MODE_CALLBACK = 4;
static readonly FORM_ID = 'formId_';
static readonly DISPLAY_NAME = 'displayName_';
static readonly ALBUM_NAME = 'albumName_';
static readonly CURRENT_URL = 'currentUri_';
static readonly INTERVAL_TIME = 'intervalTime_';
static readonly CURRENT_INDEX = 'currentIndex_';
static readonly FLEX_GROW = 2;
static readonly DIALOG_BOTTOM_OFFSET: number = 12;
static readonly DEFAULT_TIME = 30;
static readonly NUMBER_2 = 2;
static readonly NUMBER_3 = 3;
static readonly NUMBER_4: number = 4;
static readonly NUMBER_8: number = 8;
static readonly NUMBER_12: number = 12;
static readonly NUMBER_24: number = 24;
static readonly FROM_PLAYBACK_INTERVAL = 'form_playback_interval';
static readonly PHOTOS_FORM_DEFAULT_PERIOD = 30;
static readonly SELECT_ALBUM: string = 'selectAlbum';
static readonly SELECT_PHOTO: string = 'selectPhoto';
}

View File

@ -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 {Logger as RootLogger} from '../../common/utils/Logger'
const MODULE_ALBUM = 'Form_';
export class Logger extends RootLogger {
constructor(module: string) {
super(MODULE_ALBUM + module);
}
}

View File

@ -0,0 +1,177 @@
/*
* 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 {MediaDataManager} from '../data/MediaDataManager'
import {Logger} from '../common/Logger'
import formBindingData from '@ohos.application.formBindingData';
import {Constants} from '../common/Constants'
import {DataStoreUtil} from '../../common/utils/DataStoreUtil'
import formProvider from '@ohos.application.formProvider';
import {MediaLibraryAccess} from '../../common/access/MediaLibraryAccess'
import {Constants as commonConstants} from '../../common/model/common/Constants'
export class FormController {
private context: any;
private formId: string;
private operationMode: number = Constants.PHOTOS_FORM_OPERATION_MODE_NONE;
private logger: Logger = new Logger('FormController');
private callback: Function = null;
private static readonly MSG_ROUTER_PHOTOS = 'routerPhotos'
mediaDataManager: MediaDataManager;
constructor(context: any, formId: string, operationMode: number, callback?: Function) {
this.context = context;
this.formId = formId;
this.operationMode = operationMode;
this.callback = callback;
this.mediaDataManager = new MediaDataManager(context, formId, operationMode, this);
}
bindFormData(formId: string): any {
this.logger.info(`bindFormData start formId: ${formId}`)
let fd = this.mediaDataManager.getCurrentFd();
let image: string = "image" + this.mediaDataManager.getMediaData().arkUri;
let dataObj1: any;
if (image == "image0") {
dataObj1 = {
"fd": fd==-1? false: true,
"image1": "memory://image" + this.mediaDataManager.getMediaData().arkUri,
"albumName": this.mediaDataManager.getCurrentAlbumName(),
"currentIndex": this.mediaDataManager.getCurrentIndex(),
"isShow": this.mediaDataManager.getIsShowAlbumName(),
"formImages": {"image0": fd}
};
} else {
dataObj1 = {
"fd": fd==-1? false: true,
"image1": "memory://image" + this.mediaDataManager.getMediaData().arkUri,
"albumName": this.mediaDataManager.getCurrentAlbumName(),
"currentIndex": this.mediaDataManager.getCurrentIndex(),
"isShow": this.mediaDataManager.getIsShowAlbumName(),
"formImages": {"image1": fd}
};
}
this.logger.debug(`bindFormData, createFormBindingData dataObj2.data: ${JSON.stringify(dataObj1)}`);
let obj = formBindingData.createFormBindingData(JSON.stringify(dataObj1));
this.logger.debug(`bindFormData, createFormBindingData obj2.data: ${JSON.stringify(obj.data)}`);
return obj;
}
updateFormData(formId: string, vars: string[]): void {
this.logger.debug(`updateFormData formId: ${JSON.stringify(formId)}`);
let obj3 = this.bindFormData(formId);
this.logger.debug(`updateFormData obj: ${JSON.stringify(obj3)}`);
formProvider.updateForm(formId, obj3)
.then((data) => {
this.logger.info(`updateFormData, data: ${JSON.stringify(data)}`);
if (this.mediaDataManager.getIsShowAlbumName()) {
formProvider.setFormNextRefreshTime(formId, this.mediaDataManager.getIntervalTime()).then(() => {
this.logger.error(`setFormNextRefreshTime successfully!`);
if (this.callback != null) {
this.callback.call(this.callback);
}
this.onDestroy();
}).catch((err) => {
this.logger.error(`init err ${err}`);
})
} else {
if (this.callback != null) {
this.callback.call(this.callback);
}
this.onDestroy();
}
}).catch((error) => {
this.logger.error(`updateForm failed. Cause: ${JSON.stringify(error)}`);
this.mediaDataManager.closeFd();
});
}
onDestroy() {
this.logger.info('onDestroy start!');
this.mediaDataManager.closeFd();
DataStoreUtil.getInstance(this.context).removeCache();
MediaLibraryAccess.getInstance().onDestroy();
this.callback = null;
this.logger.info('onDestroy done end!');
}
onUpdateFormData(formId: string): void {
this.logger.debug(`onUpdateFormData formId: ${formId}`);
this.mediaDataManager.setNextIndex();
}
routerPhotoBrowser() {
this.logger.debug('routerPhotoBrowser start!');
let param = {
'bundleName': 'com.ohos.photos',
'abilityName': 'com.ohos.photos.MainAbility',
'parameters': {
'uri': (this.mediaDataManager.getMediaData().currentUri != '')? commonConstants.ACTION_URI_FORM_ABILITY : commonConstants.ACTION_URI_FORM_ABILITY_NONE,
'albumId': `${this.mediaDataManager.getMediaData().albumId}`,
'currentIndex': this.mediaDataManager.getMediaData().currentIndex
}
};
this.logger.debug(`routerPhotoBrowser parm ${JSON.stringify(param)}`);
this.context.startAbility(param).then(() => {
this.logger.info(`raul startAbility complete`);
AppStorage.Delete(Constants.FROM_CONTROLLER_MANAGER);
});
this.onDestroy();
this.logger.debug('routerPhotoBrowser end!');
}
onTriggerFormEvent(formId: string, message): void {
this.logger.debug(`onTriggerFormEvent ${formId} ${message}`);
let msgObj = JSON.parse(message);
let param = msgObj["params"];
let msg = param["message"];
this.logger.debug(`onTriggerFormEvent ${param} ${msg}`);
if (msg == FormController.MSG_ROUTER_PHOTOS) {
this.routerPhotoBrowser();
}
}
onEvent(formId: string):void {
this.logger.debug('onEvent start!');
if (this.callback != null) {
if (this.mediaDataManager.getUpdateTag()) {
this.mediaDataManager.setUpdateTag(false)
this.logger.debug(`updateFormData formId: ${JSON.stringify(formId)}`);
let obj3 = this.bindFormData(formId);
this.logger.debug(`updateFormData obj: ${JSON.stringify(obj3)}`);
formProvider.updateForm(formId, obj3)
.then((data) => {
this.logger.info(`updateFormData, data: ${JSON.stringify(data)}`);
this.onTriggerFormEvent(formId, this.callback.call(this.callback));
}).catch((error) => {
this.onTriggerFormEvent(formId, this.callback.call(this.callback));
});
} else {
this.onTriggerFormEvent(formId, this.callback.call(this.callback));
}
}
this.logger.debug('onEvent end!');
}
onCallback():void {
this.logger.debug('onCallback start!');
if (this.callback != null) {
this.callback.call(this.callback);
}
this.logger.debug('onCallback end!');
}
onDeleteForm(formId: string): void {
this.mediaDataManager.storageDelete();
}
}

View File

@ -0,0 +1,117 @@
/*
* 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 {Constants} from '../common/Constants'
import {FormController} from './FormController'
import {Logger} from '../common/Logger'
import {DataStoreUtil} from '../../common/utils/DataStoreUtil'
import abilityAccessCtrl from '@ohos.abilityAccessCtrl'
import bundle from '@ohos.bundle'
export class FormControllerManager {
private context: any;
private formControllerMap = new Map();
private logger: Logger = new Logger('FormControllerManager');
private constructor(context) {
this.logger.info('new FormControllerManager');
this.context = context;
DataStoreUtil.getInstance(globalThis.photosGlobalContext);
}
public static getInstance(context: any): FormControllerManager {
if (AppStorage.Get(Constants.FROM_CONTROLLER_MANAGER) == null) {
AppStorage.SetOrCreate(Constants.FROM_CONTROLLER_MANAGER, new FormControllerManager(context));
}
return AppStorage.Get(Constants.FROM_CONTROLLER_MANAGER);
}
public createFormController(formId: string, operationMode: number, callback?: Function): FormController {
this.logger.debug('createFormController start!');
if (formId == '0') {
this.logger.info('formId is 0 or formName is null!');
return null;
}
let controller = new FormController(this.context, formId, operationMode, callback);
if (controller == null || controller == undefined) {
this.logger.error('It is failed to create FormController!');
return null;
}
this.formControllerMap.set(formId, controller);
this.logger.debug('createFormController end!');
return controller;
}
async initData(formId: string, operationMode: number, callback?: Function): Promise<void> {
this.logger.debug(`initData start! operationMode: ${operationMode}`);
await DataStoreUtil.getInstance(globalThis.photosGlobalContext).init().then(async () => {
let formIdKey: string = 'formId_' + formId;
let hasFormId = await DataStoreUtil.getInstance(globalThis.photosGlobalContext).hasData(formIdKey);
this.logger.debug(`The value of hasFormId is ${hasFormId}`);
if (hasFormId) {
this.createFormController(formId, operationMode, callback);
}
}).catch((err) => {
this.logger.error(`init err ${err}`);
})
this.logger.debug('initData end!');
}
public destroyController(formId: string): void {
this.initData(formId, Constants.PHOTOS_FORM_OPERATION_MODE_DESTROY);
}
public updateController(formId: string, callback?: Function): void {
this.initData(formId, Constants.PHOTOS_FORM_OPERATION_MODE_UPDATE, callback);
}
public onEvent(formId: string, message: string): void {
this.initData(formId, Constants.PHOTOS_FORM_OPERATION_MODE_EVENT, function (): any {
return message;
})
}
public onCallback(formId: string, callback: Function): void {
this.initData(formId, Constants.PHOTOS_FORM_OPERATION_MODE_CALLBACK, callback);
}
public getController(formId: string): FormController {
this.logger.debug('getController start!');
let controller: FormController = this.formControllerMap.get(formId);
if (controller == null || controller == undefined) {
this.logger.info(`has no controller with formid ${formId}`);
return null;
}
this.logger.debug('getController end!');
return controller;
}
public deleteFormController(formId: string): void {
this.logger.debug('deleteFormController start!')
if (this.formControllerMap.has(formId)) {
let ret = this.formControllerMap.delete(formId);
if (ret) {
this.logger.info('It is successful to delete FormController');
} else {
this.logger.error('It is failed to delete FormController');
}
} else {
this.logger.info(`deleteFormController, It has no controller with formid ${formId}`);
}
this.logger.debug('deleteFormController end!');
}
}

View File

@ -0,0 +1,40 @@
/*
* 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.
*/
export class MediaData {
formId: string = '0';
albumName: string = '';
albumId: string = '';
displayName: string = '';
currentUri: string = '';
currentIndex:number = 0;
intervalTime: number = 0;
//数据持久化保存布尔型目前存在问题,使用数字类型保存。
isShowAlbumName: number = 0;
arkUri: number = 0;
constructor(formId: string, displayName: string, albumName: string,
albumId: string, currentUri: string,currentIndex: number,
intervalTime: number, isShowAlbumName: number, arkUri: number) {
this.formId = formId;
this.albumId = albumId;
this.displayName = displayName;
this.albumName = albumName;
this.currentUri = currentUri;
this.currentIndex = currentIndex;
this.intervalTime = intervalTime;
this.isShowAlbumName = isShowAlbumName;
this.arkUri = arkUri;
}
}

View File

@ -0,0 +1,448 @@
/*
* 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 {MediaData} from './MediaData'
import {Constants} from '../common/Constants'
import {Logger} from '../common/Logger'
import {AlbumDefine} from '../../common/model/browser/AlbumDefine'
import {DataStoreUtil} from '../../common/utils/DataStoreUtil'
import {MediaLibraryAccess} from '../../common/access/MediaLibraryAccess'
import resourceManager from '@ohos.resourceManager';
export class MediaDataManager {
private mediaData: MediaData = null;
private formController: any = null;
private items: any[];
private logger: Logger = new Logger('MediaDataManager');
private hasNewChange: boolean = false;
private fd: number = -1;
private key: string = '';
private operationMode: number = Constants.PHOTOS_FORM_OPERATION_MODE_NONE;
private context:any;
private isNextFag: boolean = true;
private isUpdate: boolean = false;
constructor(context: any, formId: string, operationMode: number, formController: any) {
this.formController = formController;
this.operationMode = operationMode;
this.context = context;
this.initData(formId);
}
async getResourceString(resource: Resource) {
try {
this.logger.info(`getResourceString: ${JSON.stringify(resource)}`);
let mgr: resourceManager.ResourceManager = await resourceManager.getResourceManager(this.context);
if (mgr != null || mgr != undefined) {
return await mgr.getString(resource.id);
} else {
this.logger.error(`getResourceManager instance is none`);
return null;
}
} catch (error) {
this.logger.error(`getResourceString error: ${error}`);
return null;
}
}
async initData(formId: string) {
this.logger.info(`initData formId ${formId}`);
MediaLibraryAccess.getInstance().onCreate(this.context);
MediaLibraryAccess.getInstance().getPublicDirectory().then(async () => {
await this.storageRead(formId);
if (this.mediaData == null || this.mediaData == undefined) {
this.logger.info('initData new MediaData!');
this.mediaData = new MediaData(formId,
await this.getResourceString($r('app.string.album_camera')),
Constants.PHOTOS_FORM_CAMERA_NAME, AlbumDefine.ALBUM_ID_CAMERA, '', 0,
Constants.PHOTOS_FORM_DEFAULT_PERIOD, 1, 0);
}
this.logger.info(`initData formId ${this.mediaData.formId}
albumName ${this.mediaData.albumName} currentIndex ${this.mediaData.currentIndex}`);
let displayName = await this.getAlbumDisplayName(this.mediaData.albumId);
if (displayName != null) {
this.mediaData.displayName = displayName;
this.logger.info('initData displayName' + this.mediaData.displayName)
}
await this.loadData();
});
}
private async getAlbumDisplayName(formId) {
this.logger.debug('getAlbumDisplayName name ' + formId)
switch (formId) {
case AlbumDefine.ALBUM_ID_ALL:
return await this.getResourceString($r('app.string.album_all'));
case AlbumDefine.ALBUM_ID_CAMERA:
return await this.getResourceString($r('app.string.album_camera'));
case AlbumDefine.ALBUM_ID_FAVOR:
return await this.getResourceString($r('app.string.album_favor'));
case AlbumDefine.ALBUM_ID_REMOTE:
return await this.getResourceString($r('app.string.album_remote_device'));
case AlbumDefine.ALBUM_ID_SNAPSHOT:
return await this.getResourceString($r('app.string.album_screen_shot'));
default:
break;
}
return null;
}
async saveData() {
this.logger.debug('saveData');
this.filterOutVideoMediaData();
this.updateMediaData();
if (((this.operationMode != Constants.PHOTOS_FORM_OPERATION_MODE_EVENT)
&& (this.operationMode != Constants.PHOTOS_FORM_OPERATION_MODE_DESTROY)
&& (this.operationMode != Constants.PHOTOS_FORM_OPERATION_MODE_UPDATE)) || this.isUpdate) {
try {
this.fd = await this.openCurrentFd();
} catch (error) {
this.logger.error(`open Fd failed: ${error}`);
}
}
this.logger.debug(`saveData fd: ${this.fd}`);
await this.storageSet();
this.operationFormController();
}
operationFormController() {
this.logger.debug(`operFormControllerOper operationMode ${this.operationMode}`);
switch (this.operationMode){
case Constants.PHOTOS_FORM_OPERATION_MODE_DESTROY:
this.operationMode = Constants.PHOTOS_FORM_OPERATION_MODE_NONE;
this.formController.onDeleteForm(this.mediaData.formId);
break;
case Constants.PHOTOS_FORM_OPERATION_MODE_UPDATE:
this.operationMode = Constants.PHOTOS_FORM_OPERATION_MODE_NONE;
this.formController.onUpdateFormData(this.mediaData.formId);
break;
case Constants.PHOTOS_FORM_OPERATION_MODE_EVENT:
this.operationMode = Constants.PHOTOS_FORM_OPERATION_MODE_NONE;
this.formController.onEvent(this.mediaData.formId);
break;
case Constants.PHOTOS_FORM_OPERATION_MODE_CALLBACK:
this.operationMode = Constants.PHOTOS_FORM_OPERATION_MODE_NONE;
this.formController.onCallback(this.mediaData.formId);
break;
default:
this.formController.updateFormData(this.mediaData.formId, []);
break;
}
this.logger.debug('operationFormController end!');
}
async storageRead(formId: string) {
this.logger.debug('storageRead start!');
let formIdKey: string = 'formId_' + formId
let hasFormId = await DataStoreUtil.getInstance(globalThis.photosGlobalContext).hasData(formIdKey);
this.logger.debug(`The value of hasFormId is ${hasFormId}`)
if (hasFormId) {
let displayNameKey = 'displayName_' + formId;
let displayName = await DataStoreUtil.getInstance(globalThis.photosGlobalContext).getData(displayNameKey, '') as string;
this.logger.debug(`The value of albumName is ${displayName}`);
let albumNameKey = 'albumName_' + formId;
let albumName = await DataStoreUtil.getInstance(globalThis.photosGlobalContext).getData(albumNameKey, '') as string;
this.logger.debug(`The value of albumName is ${albumName}`);
let albumIdKey = 'albumId_' + formId;
let albumId = await DataStoreUtil.getInstance(globalThis.photosGlobalContext).getData(albumIdKey, '') as string;
this.logger.debug(`The value of albumId is ${albumId}`);
let currentUriKey = 'currentUri_' + formId;
let currentUri = await DataStoreUtil.getInstance(globalThis.photosGlobalContext).getData(currentUriKey, '') as string;
this.logger.debug(`The value of currentUri is ${currentUri}`);
let currentIndexKey = 'currentIndex_' + formId;
let currentIndex = await DataStoreUtil.getInstance(globalThis.photosGlobalContext).getData(currentIndexKey, 0) as number;
this.logger.debug(`The value of currentIndex is ${currentIndex}`);
let intervalTimeKey = 'intervalTime_' + formId;
let intervalTime = await DataStoreUtil.getInstance(globalThis.photosGlobalContext).getData(intervalTimeKey, 0) as number;
this.logger.debug(`The value of intervalTime is ${intervalTime}`);
let isShowKey = 'isShow_' + formId;
let isShow = await DataStoreUtil.getInstance(globalThis.photosGlobalContext).getData(isShowKey, 0) as number;
this.logger.debug(`The value of isShow is ${isShow}`);
let arkUriKey = 'arkUri_' + formId;
let arkUri = await DataStoreUtil.getInstance(globalThis.photosGlobalContext).getData(arkUriKey, 0) as number;
this.logger.debug(`The value of arkUri is ${arkUri}`);
if (arkUri == 0) {
arkUri = 1;
} else {
arkUri = 0;
}
this.mediaData = new MediaData(formId, displayName, albumName, albumId,
currentUri, currentIndex, intervalTime, isShow, arkUri);
}
this.logger.debug('storageRead end!');
}
async storageSet() {
this.logger.debug('storageSet start!');
let formIdKey = 'formId_' + this.mediaData.formId;
await DataStoreUtil.getInstance(globalThis.photosGlobalContext).putData(formIdKey, this.mediaData.formId);
let displayNameKey = 'displayName_' + this.mediaData.formId;
await DataStoreUtil.getInstance(globalThis.photosGlobalContext).putData(displayNameKey, this.mediaData.displayName);
let albumNameKey = 'albumName_' + this.mediaData.formId;
await DataStoreUtil.getInstance(globalThis.photosGlobalContext).putData(albumNameKey, this.mediaData.albumName);
let albumIdKey = 'albumId_' + this.mediaData.formId;
await DataStoreUtil.getInstance(globalThis.photosGlobalContext).putData(albumIdKey, this.mediaData.albumId);
let currentUriKey = 'currentUri_' + this.mediaData.formId;
await DataStoreUtil.getInstance(globalThis.photosGlobalContext).putData(currentUriKey, this.mediaData.currentUri);
let currentIndexKey = 'currentIndex_' + this.mediaData.formId;
await DataStoreUtil.getInstance(globalThis.photosGlobalContext).putData(currentIndexKey, this.mediaData.currentIndex);
let intervalTimeKey = 'intervalTime_' + this.mediaData.formId;
await DataStoreUtil.getInstance(globalThis.photosGlobalContext).putData(intervalTimeKey, this.mediaData.intervalTime);
let isShowKey = 'isShow_' + this.mediaData.formId;
await DataStoreUtil.getInstance(globalThis.photosGlobalContext).putData(isShowKey, this.mediaData.isShowAlbumName);
let arkUriKey = 'arkUri_' + this.mediaData.formId;
await DataStoreUtil.getInstance(globalThis.photosGlobalContext).putData(arkUriKey, this.mediaData.arkUri);
await DataStoreUtil.getInstance(globalThis.photosGlobalContext).flush();
this.logger.debug('storageSet end!');
}
async storageDelete() {
this.logger.debug('storageDelete start!');
let formIdKey = 'formId_' + this.mediaData.formId;
if (await DataStoreUtil.getInstance(globalThis.photosGlobalContext).hasData(formIdKey)) {
this.logger.debug('storageDelete formId');
await DataStoreUtil.getInstance(globalThis.photosGlobalContext).delData(formIdKey);
}
let displayNameKey = 'displayName_' + this.mediaData.formId;
if (await DataStoreUtil.getInstance(globalThis.photosGlobalContext).hasData(displayNameKey)) {
this.logger.debug('storageDelete displayName');
await DataStoreUtil.getInstance(globalThis.photosGlobalContext).delData(displayNameKey);
}
let albumNameKey = 'albumName_' + this.mediaData.formId;
if (await DataStoreUtil.getInstance(globalThis.photosGlobalContext).hasData(albumNameKey)) {
this.logger.debug('storageDelete albumName');
await DataStoreUtil.getInstance(globalThis.photosGlobalContext).delData(albumNameKey);
}
let albumIdKey = 'albumId_' + this.mediaData.formId;
if (await DataStoreUtil.getInstance(globalThis.photosGlobalContext).hasData(albumIdKey)) {
this.logger.debug('storageDelete albumId');
await DataStoreUtil.getInstance(globalThis.photosGlobalContext).delData(albumIdKey);
}
let currentUriKey = 'currentUri_' + this.mediaData.formId;
if (await DataStoreUtil.getInstance(globalThis.photosGlobalContext).hasData(currentUriKey)) {
this.logger.debug('storageDelete currentUri');
await DataStoreUtil.getInstance(globalThis.photosGlobalContext).delData(currentUriKey);
}
let currentIndexKey = 'currentIndex_' + this.mediaData.formId;
if (await DataStoreUtil.getInstance(globalThis.photosGlobalContext).hasData(currentIndexKey)) {
this.logger.debug('storageDelete currentIndex');
await DataStoreUtil.getInstance(globalThis.photosGlobalContext).delData(currentIndexKey);
}
let intervalTimeKey = 'intervalTime_' + this.mediaData.formId;
if (await DataStoreUtil.getInstance(globalThis.photosGlobalContext).hasData(intervalTimeKey)) {
this.logger.debug('storageDelete intervalTime');
await DataStoreUtil.getInstance(globalThis.photosGlobalContext).delData(intervalTimeKey);
}
let isShowKey = 'isShow_' + this.mediaData.formId;
if (await DataStoreUtil.getInstance(globalThis.photosGlobalContext).hasData(isShowKey)) {
this.logger.debug('storageDelete isShowAlbumName');
await DataStoreUtil.getInstance(globalThis.photosGlobalContext).delData(isShowKey);
}
let arkUriKey = 'arkUri_' + this.mediaData.formId;
if (await DataStoreUtil.getInstance(globalThis.photosGlobalContext).hasData(arkUriKey)) {
this.logger.debug('storageDelete arkUri');
await DataStoreUtil.getInstance(globalThis.photosGlobalContext).delData(arkUriKey);
}
await DataStoreUtil.getInstance(globalThis.photosGlobalContext).flush();
this.logger.debug('storageDelete end!');
}
setMediaData(displayName:string, albumName: string, currentUri: string, intervalTime: number) {
this.logger.debug('setAlbumNameAndUri start!');
if (this.mediaData != null) {
this.mediaData.currentUri = currentUri;
if (this.mediaData.currentUri == '') {
this.mediaData.currentIndex = 0;
}
this.mediaData.intervalTime = intervalTime;
if (this.mediaData.albumName != albumName) {
this.mediaData.albumName = albumName;
this.loadData();
} else {
this.saveData();
}
}
this.logger.debug('setAlbumNameAndUri end!');
}
filterOutVideoMediaData() {
this.logger.debug('filterOutVideoMediaData start!');
if (this.items.length == 0) {
return;
}
if (this.items[this.mediaData.currentIndex].mediaType == MediaLibraryAccess.MEDIA_TYPE_IMAGE) {
return;
}
let currentIndex = this.mediaData.currentIndex;
for (let i = currentIndex; i < this.items.length; i++) {
let type = this.items[i].mediaType;
if (type == MediaLibraryAccess.MEDIA_TYPE_IMAGE) {
this.mediaData.currentIndex = i;
return;
}
}
if (currentIndex != 0) {
for (let i = 0; i < this.items.length; i++) {
let type = this.items[i].mediaType;
if (type == MediaLibraryAccess.MEDIA_TYPE_IMAGE) {
this.mediaData.currentIndex = i;
return;
}
}
}
this.mediaData.currentIndex = 0;
this.logger.debug('filterOutVideoMediaData end!');
}
updateMediaData() {
this.logger.debug('updateMediaData start! index ${this.mediaData.currentIndex}');
if (this.mediaData.currentIndex == -1) {
this.mediaData.currentIndex = 0;
this.isNextFag = false;
} else {
this.isNextFag = true;
}
if (this.mediaData.currentUri != '') {
let isExist = false;
for (let i = 0; i < this.items.length; i++) {
let uri = this.items[i].uri;
if (uri == this.mediaData.currentUri) {
this.mediaData.currentIndex = i;
isExist = true;
}
}
if (!isExist) {
if ((this.items.length !=0) && (this.mediaData.currentIndex < this.items.length)) {
this.mediaData.currentUri = this.items[this.mediaData.currentIndex].uri;
this.isUpdate = true;
}
if ((this.items.length == 0) || (this.mediaData.isShowAlbumName == 0)) {
this.mediaData.currentUri = '';
}
}
} else {
if ((this.items.length !=0) &&
(this.mediaData.currentIndex < this.items.length) &&
(this.mediaData.isShowAlbumName != 0)) {
this.mediaData.currentUri = this.items[this.mediaData.currentIndex].uri;
}
}
this.logger.debug('updateMediaData end!');
}
getUpdateTag() {
return this.isUpdate;
}
setUpdateTag(isUpdate: boolean) {
this.isUpdate = isUpdate;
}
getCurrentItem(): any {
if ((this.mediaData.currentIndex < this.items.length) &&
(this.mediaData.currentUri != '')) {
return this.items[this.mediaData.currentIndex];
} else {
return null;
}
}
getCurrentAlbumName(): string {
return this.mediaData.displayName;
}
getCurrentIndex(): number {
return this.mediaData.currentIndex;
}
getIsShowAlbumName(): boolean {
return this.mediaData.isShowAlbumName == 1? true: false;
}
getIntervalTime(): number {
this.logger.debug(`getIntervalTime time ${this.mediaData.intervalTime}`);
return this.mediaData.intervalTime;
}
setNextIndex() {
this.logger.debug(`setNextIndex start old index ${this.mediaData.currentIndex} flag ${this.isNextFag}`);
if (this.isNextFag) {
let index = this.mediaData.currentIndex;
if ((this.items.length != 0) && (index < this.items.length - 1)) {
index = index + 1;
} else {
index = 0;
}
this.mediaData.currentIndex = index;
if (this.items.length >= 1) {
this.mediaData.currentUri = this.items[index].uri;
} else {
this.mediaData.currentUri = '';
}
}
this.logger.debug(`setNextIndex index ${this.mediaData.currentIndex} uri ${this.mediaData.currentUri}`);
this.saveData();
this.logger.debug('setNextIndex end!');
}
getMediaData(): MediaData {
return this.mediaData;
}
async openCurrentFd(): Promise<number> {
let fileAsset = this.getCurrentItem();
this.logger.info(`openCurrentFd uri: ${this.mediaData.currentUri}`);
let fd = (fileAsset != null) ? await MediaLibraryAccess.getInstance().openAsset('R', fileAsset): -1;
this.logger.info(`openCurrentFd the fd: ${fd}`);
return fd;
}
getCurrentFd(): number {
return this.fd;
}
async closeFd() {
this.logger.info(`close the fd: ${this.fd}`);
let fileAsset = this.getCurrentItem();
if (fileAsset != null && this.fd != -1) {
await MediaLibraryAccess.getInstance().closeAsset(this.fd, fileAsset);
this.fd = -1;
}
}
async loadData() {
this.logger.debug('loadData start!');
this.items = await this.getItems(this.mediaData.albumId);
if (this.items == null) {
this.items = [];
}
this.logger.info(`get album objects: Name:${this.mediaData.albumName} length: ${this.items.length}`);
await this.saveData();
this.logger.debug('loadData end!');
}
async getItems(albumId: string, startIndex?: number, count?:number, deviceId?) {
this.logger.info('getItems start!');
let fetchOpt = AlbumDefine.getFileFetchOpt(albumId, deviceId, startIndex, count);
switch (albumId){
case AlbumDefine.ALBUM_ID_ALL:
let allObject = await MediaLibraryAccess.getInstance().getAllObject(fetchOpt);
return allObject;
break;
default:
return await MediaLibraryAccess.getInstance().getEntityAlbumObject(AlbumDefine.getAlbumFetchOpt(
albumId, deviceId), fetchOpt);
break;
}
}
}

View File

@ -14,83 +14,121 @@
*/
import Ability from '@ohos.application.Ability'
import bundle from '@ohos.bundle';
import abilityAccessCtrl from '@ohos.abilityAccessCtrl'
import wantConstant from '@ohos.ability.wantConstant'
import {Logger} from '../common/utils/Logger'
import {ScreenManager} from '../common/model/common/ScreenManager'
import {PixelMapManager} from '../common/model/common/PixelMapManager'
import {StatusBarColorController} from '../common/model/common/StatusBarColorController';
import {StatusBarColorController} from '../common/model/common/StatusBarColorController'
import {MediaLibraryAccess} from '../common/access/MediaLibraryAccess'
import {TimelineDataSourceManager} from '../feature/timeline/model/TimelineDataSourceManager';
import {TimelineDataSourceManager} from '../feature/timeline/model/TimelineDataSourceManager'
import {Constants} from '../common/model/common/Constants'
import {MediaDataSource} from '../common/model/browser/photo/MediaDataSource'
import {BroadCastManager} from '../common/model/common/BroadCastManager';
import {TraceControllerUtils} from '../common/utils/TraceControllerUtils';
import {BroadCastConstants} from '../common/model/common/BroadCastConstants'
import router from '@system.router'
const appLogger: Logger = new Logger('app');
let isFromCard = false;
let isFromCamera = false;
let appBroadCast = BroadCastManager.getInstance().getBroadCast();
export default class MainAbility extends Ability {
private static readonly RETRY_MAX_TIMES = 100;
private static readonly ACTION_URI_SINGLE_SELECT = 'singleselect';
private static readonly ACTION_URI_MULTIPLE_SELECT = 'multipleselect';
private static readonly ACTION_URI_PHOTO_DETAIL = 'photodetail';
onCreate(want, launchParam) {
appLogger.info('Application onCreate');
TraceControllerUtils.startTrace('onCreate');
// Ability is creating, initialize resources for this ability
globalThis.photosAbilityContext = this.context;
let action = want.parameters;
if (action != null && action != undefined && action.uri == 'photodetail') {
AppStorage.SetOrCreate('entryFromHap', 1);
} else if (action != null && action != undefined && action.uri == 'singleselect') {
AppStorage.SetOrCreate('entryFromHap', 2);
} else if (action != null && action != undefined && action.uri == 'multipleselect') {
AppStorage.SetOrCreate('entryFromHap', 3);
} else {
AppStorage.SetOrCreate('entryFromHap', 0);
if (action != null && action != undefined && action.uri == MainAbility.ACTION_URI_PHOTO_DETAIL) {
isFromCamera = true;
AppStorage.SetOrCreate(Constants.ENTRY_FROM_HAP, Constants.ENTRY_FROM_CAMERA);
} else if (action != null && action != undefined && action.uri == MainAbility.ACTION_URI_SINGLE_SELECT) {
AppStorage.SetOrCreate(Constants.ENTRY_FROM_HAP, Constants.ENTRY_FROM_SINGLE_SELECT);
} else if (action != null && action != undefined && action.uri == MainAbility.ACTION_URI_MULTIPLE_SELECT) {
AppStorage.SetOrCreate(Constants.ENTRY_FROM_HAP, Constants.ENTRY_FROM_MULTIPLE_SELECT);
} else if (action != null && action != undefined && action.uri == Constants.ACTION_URI_FORM_ABILITY) {
isFromCard = true;
AppStorage.SetOrCreate(Constants.ENTRY_FROM_HAP, Constants.ENTRY_FROM_FORM_ABILITY);
AppStorage.SetOrCreate(Constants.FROM_ALBUM_ID, action.albumId);
AppStorage.SetOrCreate(Constants.FROM_CURRENT_INDEX, action.currentIndex);
} else if (action != null && action != undefined && action.uri == Constants.ACTION_URI_FORM_ABILITY_NONE) {
AppStorage.SetOrCreate(Constants.ENTRY_FROM_HAP, Constants.ENTRY_FROM_FORM_ABILITY_NONE);
} else if (action != null && action != undefined && action['formId'] != null) {
AppStorage.SetOrCreate(Constants.FA_SETTING_FROM_ID, action['formId']);
AppStorage.SetOrCreate(Constants.ENTRY_FROM_HAP, Constants.ENTRY_FROM_FORM_FORM_EDITOR);
} else if (want.action == wantConstant.Action.ACTION_VIEW_DATA) {
AppStorage.SetOrCreate(Constants.ENTRY_FROM_HAP, Constants.ENTRY_FROM_VIEW_DATA);
AppStorage.SetOrCreate(Constants.VIEW_DATA_URI, want.uri);
action && AppStorage.SetOrCreate(Constants.VIEW_DATA_POS, action.index);
} else {
AppStorage.SetOrCreate(Constants.ENTRY_FROM_HAP, Constants.ENTRY_FROM_NONE);
}
let requestPermissionList: Array<string> = [
"ohos.permission.READ_MEDIA",
"ohos.permission.WRITE_MEDIA",
"ohos.permission.MEDIA_LOCATION"
"ohos.permission.MEDIA_LOCATION",
"ohos.permission.DISTRIBUTED_DATASYNC"
];
bundle.getApplicationInfo('com.ohos.photos', 0, 100).then((appInfo) => {
let accessTokenId = appInfo.accessTokenId
let promiseStatus: Array<Promise<number>> = []
let requestList: Array<string> = []
let accessCtrl = abilityAccessCtrl.createAtManager()
for (let i=0; i<requestPermissionList.length; i++) {
promiseStatus.push(accessCtrl.verifyAccessToken(accessTokenId, requestPermissionList[i]))
TraceControllerUtils.startTrace('requestPermissionsFromUser');
globalThis.photosAbilityContext.requestPermissionsFromUser(requestPermissionList).then(function (data) {
appLogger.info(`requestPermissionsFromUser data: ${JSON.stringify(data)}`)
let result = 0
for (let i = 0; i < data.authResults.length; i++) {
result += data.authResults[i]
}
Promise.all(promiseStatus).then((status) => {
for (let i=0; i<status.length; i++) {
if (status[i] == abilityAccessCtrl.GrantStatus.PERMISSION_DENIED) {
requestList.push(requestPermissionList[i])
}
}
if (requestList.length != 0) {
globalThis.photosAbilityContext.requestPermissionsFromUser(requestList).then(function (data) {
let result = 0
for (let i = 0; i < data.authResults.length; i++) {
result += data.authResults[i]
}
if (result >= -1) {
AppStorage.SetOrCreate('permissionStatus', true);
} else {
AppStorage.SetOrCreate('permissionStatus', false);
}
}, (err) => {
AppStorage.SetOrCreate('permissionStatus', false);
});
if (result >= 0) {
// Improve cold startup performance. Initialize the timeline in advance
AppStorage.SetOrCreate(Constants.PERMISSION_STATUS, true);
TraceControllerUtils.finishTrace('requestPermissionsFromUser');
MediaLibraryAccess.getInstance().onCreate(globalThis.photosAbilityContext)
if (!isFromCard && !isFromCamera) {
TraceControllerUtils.finishTrace('onCreate');
TimelineDataSourceManager.getInstance();
} else {
AppStorage.SetOrCreate('permissionStatus', true);
TraceControllerUtils.finishTrace('onCreate');
}
})
})
} else {
AppStorage.SetOrCreate(Constants.PERMISSION_STATUS, false);
}
}, (err) => {
appLogger.error(`Failed to requestPermissionsFromUser, ${err.code}`);
});
appBroadCast.on(BroadCastConstants.THIRD_ROUTE_PAGE, this.thirdRouterPage.bind(this));
appLogger.info('Application onCreate end');
}
onNewWant(want) {
TraceControllerUtils.startTrace('onNewWant');
let action = want.parameters;
if (action != null && action != undefined && action.uri == 'photodetail') {
AppStorage.SetOrCreate('entryFromHap', 1);
} else if (action != null && action != undefined && action.uri == 'singleselect') {
AppStorage.SetOrCreate('entryFromHap', 2);
} else if (action != null && action != undefined && action.uri == 'multipleselect') {
AppStorage.SetOrCreate('entryFromHap', 3);
} else {
AppStorage.SetOrCreate('entryFromHap', 0);
if (action != null && action != undefined && action.uri == MainAbility.ACTION_URI_PHOTO_DETAIL) {
AppStorage.SetOrCreate(Constants.ENTRY_FROM_HAP, Constants.ENTRY_FROM_CAMERA);
} else if (action != null && action != undefined && action.uri == MainAbility.ACTION_URI_SINGLE_SELECT) {
AppStorage.SetOrCreate(Constants.ENTRY_FROM_HAP, Constants.ENTRY_FROM_SINGLE_SELECT);
} else if (action != null && action != undefined && action.uri == MainAbility.ACTION_URI_MULTIPLE_SELECT) {
AppStorage.SetOrCreate(Constants.ENTRY_FROM_HAP, Constants.ENTRY_FROM_MULTIPLE_SELECT);
} else if (action != null && action != undefined && action.uri == Constants.ACTION_URI_FORM_ABILITY) {
AppStorage.SetOrCreate(Constants.ENTRY_FROM_HAP, Constants.ENTRY_FROM_FORM_ABILITY);
AppStorage.SetOrCreate(Constants.FROM_ALBUM_ID, action.albumId);
AppStorage.SetOrCreate(Constants.FROM_CURRENT_INDEX, action.currentIndex);
} else if (action != null && action != undefined && action.uri == Constants.ACTION_URI_FORM_ABILITY_NONE) {
AppStorage.SetOrCreate(Constants.ENTRY_FROM_HAP, Constants.ENTRY_FROM_FORM_ABILITY_NONE);
} else if (action != null && action != undefined && action['formId'] != null) {
AppStorage.SetOrCreate(Constants.FA_SETTING_FROM_ID, action['formId']);
AppStorage.SetOrCreate(Constants.ENTRY_FROM_HAP, Constants.ENTRY_FROM_FORM_FORM_EDITOR);
} else if (want.action == wantConstant.Action.ACTION_VIEW_DATA) {
AppStorage.SetOrCreate(Constants.ENTRY_FROM_HAP, Constants.ENTRY_FROM_VIEW_DATA);
AppStorage.SetOrCreate(Constants.VIEW_DATA_URI, want.uri);
action && AppStorage.SetOrCreate(Constants.VIEW_DATA_POS, action.index);
} else {
AppStorage.SetOrCreate(Constants.ENTRY_FROM_HAP, Constants.ENTRY_FROM_NONE);
}
TraceControllerUtils.finishTrace('onNewWant');
}
onDestroy() {
@ -100,35 +138,57 @@ export default class MainAbility extends Ability {
pixelMapManager.release();
let statusBarColorController: StatusBarColorController = StatusBarColorController.getInstance();
statusBarColorController.release();
AppStorage.Delete('entryFromHap');
MediaLibraryAccess.onDestroy();
AppStorage.Delete(Constants.ENTRY_FROM_HAP);
MediaLibraryAccess.getInstance().onDestroy();
}
onWindowStageCreate(windowStage) {
TraceControllerUtils.startTrace('onWindowStageCreate');
// Main window is created, set main page for this ability
appLogger.info('Application onCreate');
;
MediaLibraryAccess.onCreate();
// Improve cold startup performance. Initialize the timeline in advance
TimelineDataSourceManager.getInstance();
appLogger.info('Application onWindowStageCreate');
globalThis.photosWindowStage = windowStage;
ScreenManager.getInstance().on(ScreenManager.ON_LEFT_BLANK_CHANGED, data => {
appLogger.info(`onleftBlankChanged: ${data}`);
AppStorage.SetOrCreate('leftBlank', data);
AppStorage.SetOrCreate(Constants.LEFT_BLANK, data);
});
ScreenManager.getInstance().on(ScreenManager.ON_SPLIT_MODE_CHANGED, mode => {
appLogger.info(`onSplitModeChanged: ${JSON.stringify(mode)}`);
AppStorage.SetOrCreate('isSplitMode', mode);
AppStorage.SetOrCreate(Constants.IS_SPLIT_MODE, mode);
});
MediaLibraryAccess.getPublicDirectory();
appLogger.info('Application onCreate finish');
TraceControllerUtils.startTrace('getMainWindow');
windowStage.getMainWindow().then((win) => {
AppStorage.SetOrCreate('mainWindow', win);
ScreenManager.getInstance().getAvoidArea();
windowStage.setUIContent(this.context, 'product/phone/view/index', null);
AppStorage.SetOrCreate(Constants.MAIN_WINDOW, win);
TraceControllerUtils.finishTrace('getMainWindow');
TraceControllerUtils.startTrace('initializationSize');
ScreenManager.getInstance().initializationSize(win).then(() => {
TraceControllerUtils.finishTrace('initializationSize');
if (isFromCard) {
MediaLibraryAccess.getInstance().getPublicDirectory().then(() => {
let dataSource: MediaDataSource = new MediaDataSource(Constants.DEFAULT_SLIDING_WIN_SIZE);
dataSource.setAlbumId(AppStorage.Get(Constants.FROM_ALBUM_ID));
dataSource.initialize();
let times = 0;
//该场景是卡片跳转到大图指定图片,需要等大图数据获取完成再跳转,否则组件无法跳转。
let intervalId = setInterval(() => {
appLogger.info(`setInterval go`);
if (dataSource.getRawData(0) || times >= MainAbility.RETRY_MAX_TIMES) {
AppStorage.SetOrCreate(Constants.APP_KEY_PHOTO_BROWSER, dataSource);
windowStage.setUIContent(this.context, 'feature/browser/view/photo/PhotoBrowser', null);
ScreenManager.getInstance().initWindowMode();
clearInterval(intervalId);
}
times++;
}, 50)
});
} else {
windowStage.setUIContent(this.context, 'product/phone/view/index', null);
ScreenManager.getInstance().initWindowMode();
}
TraceControllerUtils.finishTrace('onWindowStageCreate');
}).catch(() => {
appLogger.error(`get device screen info failed.`);
});
});
globalThis.photosWindowStage = windowStage;
}
onWindowStageDestroy() {
@ -139,4 +199,88 @@ export default class MainAbility extends Ability {
onBackground() {
}
thirdRouterPage() {
TraceControllerUtils.startTrace('thirdRouterPage');
let entryFrom = AppStorage.Get(Constants.ENTRY_FROM_HAP);
let permission = AppStorage.Get(Constants.PERMISSION_STATUS);
appLogger.info(`thirdRouterPage entryFromHap: ${entryFrom} permission: ${permission}`);
if (entryFrom == Constants.ENTRY_FROM_NONE || !permission) {
return;
}
if (entryFrom == Constants.ENTRY_FROM_CAMERA) {
let options = {
uri: 'feature/browser/view/photo/PhotoBrowser',
params: {
pageFrom: Constants.ENTRY_FROM.CAMERA
}
};
router.replace(options);
} else if (entryFrom == Constants.ENTRY_FROM_SINGLE_SELECT) {
let options = {
uri: 'feature/thirdSelect/view/ThirdSelectAlbumSetPage',
params: {
isMultiPick: false,
}
};
router.replace(options);
} else if (entryFrom == Constants.ENTRY_FROM_MULTIPLE_SELECT) {
let options = {
uri: 'feature/thirdSelect/view/ThirdSelectAlbumSetPage',
params: {
isMultiPick: true,
}
};
router.replace(options);
} else if (entryFrom == Constants.ENTRY_FROM_FORM_ABILITY) {
let dataSource: MediaDataSource = new MediaDataSource(Constants.DEFAULT_SLIDING_WIN_SIZE);
dataSource.setAlbumId(AppStorage.Get(Constants.FROM_ALBUM_ID));
dataSource.initialize();
let times = 0;
//该场景是卡片跳转到大图指定图片,需要等大图数据获取完成再跳转,否则组件无法跳转。
let intervalId = setInterval(() => {
if (dataSource.getRawData(0) || times >= MainAbility.RETRY_MAX_TIMES) {
AppStorage.SetOrCreate(Constants.APP_KEY_PHOTO_BROWSER, dataSource);
let options = {
uri: 'feature/browser/view/photo/PhotoBrowser',
params: {
pageFrom: Constants.ENTRY_FROM.CARD,
albumId: AppStorage.Get(Constants.FROM_ALBUM_ID),
position: AppStorage.Get(Constants.FROM_CURRENT_INDEX)
}
};
router.replace(options);
clearInterval(intervalId);
}
times++;
}, 50)
} else if (entryFrom == Constants.ENTRY_FROM_FORM_ABILITY_NONE) {
let options = {
uri: 'product/phone/view/index'
}
router.replace(options);
} else if (entryFrom == Constants.ENTRY_FROM_FORM_FORM_EDITOR) {
let options = {
uri: 'feature/formEditor/view/FormEditorPage'
}
router.replace(options);
} else if (entryFrom == Constants.ENTRY_FROM_VIEW_DATA) {
let options = {
uri: 'feature/browser/view/photo/PhotoBrowser',
params: {
pageFrom: Constants.ENTRY_FROM.VIEW_DATA,
viewData: AppStorage.Get(Constants.VIEW_DATA_URI),
position: AppStorage.Get(Constants.VIEW_DATA_POS),
}
};
router.replace(options);
}
//router.clear()需要等页面跳转完成后调用,如果不延时调用会发生崩溃。
setTimeout(() => {
router.clear();
AppStorage.SetOrCreate(Constants.ENTRY_FROM_HAP, 0)
}, 50);
TraceControllerUtils.finishTrace('thirdRouterPage');
}
}

View File

@ -15,48 +15,80 @@
import {Logger} from '../utils/Logger'
import MediaLib from '@ohos.multimedia.mediaLibrary';
import {AlbumInfo} from '../model/browser/album/AlbumInfo.ets';
import {Constants} from '../model/common/Constants'
import { TraceControllerUtils } from '../utils/TraceControllerUtils';
export class MediaLibraryAccess {
static logger: Logger = new Logger('MediaLibraryAccess');
private logger: Logger = new Logger('MediaLibraryAccess');
static readonly MEDIA_TYPE_IMAGE = MediaLib.MediaType.IMAGE;
static readonly MEDIA_TYPE_VIDEO = MediaLib.MediaType.VIDEO;
static readonly DIRECTORY_TYPE_IMAGE = MediaLib.DirectoryType.DIR_IMAGE;
static readonly DIRECTORY_TYPE_VIDEO = MediaLib.DirectoryType.DIR_VIDEO;
static readonly DIRECTORY_TYPE_CAMERA = MediaLib.DirectoryType.DIR_CAMERA;
static readonly FILE_KEY_ID = MediaLib.FileKey.ID;
static readonly FILE_KEY_MEDIA_TYPE = MediaLib.FileKey.MEDIA_TYPE;
static readonly FILE_KEY_ALBUM_NAME = MediaLib.FileKey.ALBUM_NAME;
static readonly FILE_KEY_ALBUM_ID = MediaLib.FileKey.ALBUM_ID;
static readonly FILE_KEY_DISPLAY_NAME = MediaLib.FileKey.DISPLAY_NAME;
static readonly FILE_KEY_RELATIVE_PATH = MediaLib.FileKey.RELATIVE_PATH;
static readonly FILE_KEY_DATE_TAKEN = MediaLib.FileKey.DATE_ADDED; // TODO dateTaken is not supported, use dateAdded
static readonly FILE_KEY_DATE_TRASHED = 'date_trashed' //TODO dataTrashed is not define in FileKey
private static media = globalThis.__MediaLibraryAccess_media === undefined ? null : globalThis.__MediaLibraryAccess_media;
PUBLIC_PATH_IMAGE = '';
PUBLIC_PATH_CAMERA = '';
static onCreate() {
this.logger.debug(`Photos_MediaLibraryAccess onCreate ${globalThis.photosAbilityContext}`);
MediaLibraryAccess.media = MediaLib.getMediaLibrary(globalThis.photosAbilityContext);
private media = null;
private requestTime: number;
public static getInstance(): MediaLibraryAccess {
if (AppStorage.Get(Constants.APP_KEY_INSTANCE_MEDIA_LIBRARY_ACCESS) == null) {
AppStorage.SetOrCreate(Constants.APP_KEY_INSTANCE_MEDIA_LIBRARY_ACCESS, new MediaLibraryAccess());
}
return AppStorage.Get(Constants.APP_KEY_INSTANCE_MEDIA_LIBRARY_ACCESS);
}
constructor() {
this.requestTime = Date.now();
}
onCreate(context) {
this.logger.debug(`Photos_MediaLibraryAccess onCreate ${context}`);
if (this.media) {
this.logger.debug(`Photos_MediaLibraryAccess onCreate already`);
return;
}
this.media = MediaLib.getMediaLibrary(context);
this.logger.debug('Photos_MediaLibraryAccess onCreate end');
if (MediaLibraryAccess.media == null || MediaLibraryAccess.media == undefined) {
if (this.media == null || this.media == undefined) {
this.logger.error('get media library instance failed!');
}
globalThis.__MediaLibraryAccess_media = MediaLibraryAccess.media;
this.getPublicDirectory();
this.logger.info('onCreate done');
}
static onDestroy() {
MediaLibraryAccess.media.release();
this.logger.info('onDestroy done');
onDestroy() {
try {
this.media && this.media.release();
this.media = null;
this.logger.info('onDestroy done');
} catch (e) {
this.logger.error(`onDestroy error: ${e}`);
}
}
static getMediaLibrary() {
return MediaLibraryAccess.media;
getMediaLibrary() {
return this.media;
}
static async getAllObject(fetchOpt) {
async getAllObject(fetchOpt) {
this.logger.info(`getAllObject: ${JSON.stringify(fetchOpt)}`);
try {
let dataList = await MediaLibraryAccess.media.getFileAssets(fetchOpt);
TraceControllerUtils.startTraceWithTaskId('getAllObject', this.requestTime);
let dataList = await this.media.getFileAssets(fetchOpt);
if (dataList == null) {
this.logger.warn('get all Object Data with empty dataList');
return [];
@ -68,17 +100,19 @@ export class MediaLibraryAccess {
let result = await dataList.getAllObject();
dataList.close();
TraceControllerUtils.finishTraceWithTaskId('getAllObject', this.requestTime);
return result;
} catch (error) {
this.logger.error(`getAllObject error: ${error}`);
return null;
return [];
}
}
static async getCount(fetchOpt) {
async getCount(fetchOpt) {
this.logger.info(`getCount: ${JSON.stringify(fetchOpt)}`);
try {
let dataList = await MediaLibraryAccess.media.getFileAssets(fetchOpt);
TraceControllerUtils.startTraceWithTaskId('getCount', this.requestTime);
let dataList = await this.media.getFileAssets(fetchOpt);
if (dataList == null) {
this.logger.warn('get count dataList is 0');
return 0;
@ -86,6 +120,7 @@ export class MediaLibraryAccess {
this.logger.debug(`get count raw data size: ${dataList.getCount()}`);
let result = dataList.getCount();
dataList.close();
TraceControllerUtils.finishTraceWithTaskId('getCount', this.requestTime);
return result ;
} catch (error) {
this.logger.error(`get Count error: ${error}`);
@ -93,14 +128,15 @@ export class MediaLibraryAccess {
}
}
static async getFirstObject(fetchOpt) {
async getFirstObject(fetchOpt) {
let result = {
count: 0,
obj: null,
}
this.logger.info(`getFirstObject: ${JSON.stringify(fetchOpt)}`);
try {
let fileResult = await MediaLibraryAccess.media.getFileAssets(fetchOpt);
TraceControllerUtils.startTraceWithTaskId('getFirstObject', this.requestTime);
let fileResult = await this.media.getFileAssets(fetchOpt);
if (fileResult != undefined) {
result.count = fileResult.getCount();
this.logger.error(`getFirstObject count is ${result.count}`);
@ -116,6 +152,7 @@ export class MediaLibraryAccess {
}
fileResult.close();
}
TraceControllerUtils.finishTraceWithTaskId('getFirstObject', this.requestTime);
return result;
} catch (error) {
this.logger.error(`getFirstObject loadData error: ${error}`);
@ -123,46 +160,26 @@ export class MediaLibraryAccess {
}
}
static deleteAsset(uri: string, callback): void {
if (uri == null) {
this.logger.error('deleteAsset with empty uris');
return;
}
async deleteAsset(uri: string){
this.logger.debug(`deleteAsset uri: ${uri}`);
MediaLibraryAccess.media.deleteAsset(uri, (err) => {
this.logger.debug('deleteAsset end');
if (err) {
this.logger.error(`deleteAsset error: ${err}`);
if (callback != null) {
callback.onError();
}
return;
}
this.logger.debug(`deleteAsset end`);
if (callback != null) {
callback.onCompleted();
}
});
await this.media.deleteAsset(uri);
}
static async getPublicDirectory() {
let publicPathImage =
await MediaLibraryAccess.media.getPublicDirectory(MediaLibraryAccess.DIRECTORY_TYPE_IMAGE);
let publicPathVideo =
await MediaLibraryAccess.media.getPublicDirectory(MediaLibraryAccess.DIRECTORY_TYPE_VIDEO);
globalThis.__MediaLibraryAccess_PUBLIC_PATH_IMAGE = publicPathImage;
globalThis.__MediaLibraryAccess_PUBLIC_PATH_VIDEO = publicPathVideo;
async getPublicDirectory() {
this.PUBLIC_PATH_IMAGE =
await this.media.getPublicDirectory(MediaLibraryAccess.DIRECTORY_TYPE_IMAGE);
this.PUBLIC_PATH_CAMERA =
await this.media.getPublicDirectory(MediaLibraryAccess.DIRECTORY_TYPE_CAMERA);
}
static async createAsset(mediaType: any, displayName: string, relativePath: string) {
async createAsset(mediaType: any, displayName: string, relativePath: string) {
this.logger.debug('createAsset start');
if (relativePath == null || relativePath == undefined) {
this.logger.error('createAsset with empty relativePath');
return null;
}
this.logger.info(`createAsset ${mediaType} ${displayName} ${relativePath}`);
let fileAsset = await MediaLibraryAccess.media.createAsset(mediaType, displayName, relativePath);
let fileAsset = await this.media.createAsset(mediaType, displayName, relativePath);
this.logger.debug(`createAsset end. new fileAsset: ${fileAsset}`);
if (fileAsset == null || fileAsset == undefined) {
this.logger.error('createAsset Fail');
@ -171,7 +188,7 @@ export class MediaLibraryAccess {
return fileAsset;
}
static async openAsset(mode: string, fileAsset: any) {
async openAsset(mode: string, fileAsset: any) {
this.logger.debug('openAsset start');
let fd = await fileAsset.open(mode);
this.logger.info(`openAsset end. fd: ${fd}`);
@ -182,33 +199,20 @@ export class MediaLibraryAccess {
return fd;
}
static async closeAsset(fd: number, fileAsset: any) {
async closeAsset(fd: number, fileAsset: any) {
this.logger.debug('closeAsset start');
if (fd <= 0) {
this.logger.error('closeAsset fd is invalid');
return;
}
try {
await fileAsset.close(fd);
} catch(error) {
this.logger.error(`closeAsset fail mag: ${error}, code: ${JSON.stringify(error)}`);
}
await fileAsset.close(fd);
}
static async trashAsset(isTrash: boolean, fileAsset: any) {
async trashAsset(isTrash: boolean, fileAsset: any) {
this.logger.debug('trashAsset start');
try {
await fileAsset.trash(isTrash);
this.logger.info('trashAsset end');
} catch(error) {
this.logger.error(`trashAsset fail ${error}`);
}
await fileAsset.trash(isTrash);
}
static async getFavoriteObject(fetchOpt) {
async getFavoriteObject(fetchOpt) {
this.logger.info(`Get favorite object: ${JSON.stringify(fetchOpt)}`);
try {
let albums = await MediaLibraryAccess.media.getPrivateAlbum(MediaLib.PrivateAlbumType.TYPE_FAVORITE);
let albums = await this.media.getPrivateAlbum(MediaLib.PrivateAlbumType.TYPE_FAVORITE);
this.logger.debug(`[getFavoriteObject] get smart albums length:${albums.length} name:${albums[0].albumName}`);
let fileResult = await albums[0].getFileAssets(fetchOpt);
this.logger.debug(`[getFavoriteObject] object count :${fileResult.getCount()}`);
@ -222,10 +226,10 @@ export class MediaLibraryAccess {
}
}
static async getTrashObject(fetchOpt) {
async getTrashObject(fetchOpt) {
this.logger.info(`Get trash object: ${JSON.stringify(fetchOpt)}`);
try {
let albums = await MediaLibraryAccess.media.getPrivateAlbum(MediaLib.PrivateAlbumType.TYPE_TRASH);
let albums = await this.media.getPrivateAlbum(MediaLib.PrivateAlbumType.TYPE_TRASH);
this.logger.debug(`[getTrashObject] get smart albums length:${albums.length} name:${albums[0].albumName}`);
let fileResult = await albums[0].getFileAssets(fetchOpt);
this.logger.debug(`[getTrashObject] object count :${fileResult.getCount()}`);
@ -239,20 +243,20 @@ export class MediaLibraryAccess {
}
}
static async getEntityAlbumObject(fetchOpt, fileFetchOpt) {
async getEntityAlbumObject(fetchOpt, fileFetchOpt) {
this.logger.info(`getEntityAlbumObject opt${JSON.stringify(fetchOpt)} fileOpt${JSON.stringify(fileFetchOpt)}`);
try {
let albums = await MediaLibraryAccess.media.getAlbums(fetchOpt);
let albums = await this.media.getAlbums(fetchOpt);
this.logger.debug(`[getEntityAlbumObject]Get Albums done`);
this.logger.debug(`[getEntityAlbumObject]Album length:${albums.length}`);
if (albums.length == 0) {
return null;
return []
}
this.logger.debug(`[getEntityAlbumObject]Albums name:${albums[0].albumName}`);
let fileResult = await albums[0].getFileAssets(fileFetchOpt);
this.logger.debug(`[getEntityAlbumObject]objects count :${fileResult.getCount()}`);
if (fileResult.getCount() == 0) {
return null
return []
}
let objects = await fileResult.getAllObject();
this.logger.debug(`[getEntityAlbumObject]Get objects done`);
@ -264,7 +268,7 @@ export class MediaLibraryAccess {
}
}
static async getFavoriteCount() {
async getFavoriteCount() {
this.logger.debug(`getFavoriteCount`);
let fetchOpt = {
selections: '',
@ -272,7 +276,7 @@ export class MediaLibraryAccess {
order: ''
}
try {
let albums = await MediaLibraryAccess.media.getPrivateAlbum(MediaLib.PrivateAlbumType.TYPE_FAVORITE);
let albums = await this.media.getPrivateAlbum(MediaLib.PrivateAlbumType.TYPE_FAVORITE);
this.logger.debug(`[getFavoriteCount]Get smart Albums length:${albums.length} name:${albums[0].albumName}`);
let fileResult = await albums[0].getFileAssets(fetchOpt);
this.logger.debug(`[getFavoriteCount]Get objects done`);
@ -285,7 +289,7 @@ export class MediaLibraryAccess {
}
}
static async getTrashCount() {
async getTrashCount() {
this.logger.debug(`getTrashCount`);
let fetchOpt = {
selections: '',
@ -293,7 +297,7 @@ export class MediaLibraryAccess {
order: ''
}
try {
let albums = await MediaLibraryAccess.media.getPrivateAlbum(MediaLib.PrivateAlbumType.TYPE_TRASH);
let albums = await this.media.getPrivateAlbum(MediaLib.PrivateAlbumType.TYPE_TRASH);
this.logger.debug(`[getTrashCount]Get smart Albums length:${albums.length} name:${albums[0].albumName}`);
let fileResult = await albums[0].getFileAssets(fetchOpt);
this.logger.debug(`[getTrashCount]Get objects done`);
@ -306,11 +310,11 @@ export class MediaLibraryAccess {
}
}
static async getEntityAlbumCount(fetchOpt, fileFetchOpt?) {
async getEntityAlbumCount(fetchOpt, fileFetchOpt?) {
this.logger.info(`getEntityAlbumCount opt: ${JSON.stringify(fetchOpt)}`);
try {
let albums = await MediaLibraryAccess.media.getAlbums(fetchOpt);
this.logger.debug(`[getEntityAlbumCount]Get smart Albums length:${albums.length} name:${albums[0].albumName}`);
let albums = await this.media.getAlbums(fetchOpt);
this.logger.debug(`[getEntityAlbumCount]Get entity Albums length:${albums.length} name:${albums[0].albumName}`);
let fileFetchOp;
if (fileFetchOpt == undefined) {
fileFetchOp = {
@ -332,10 +336,10 @@ export class MediaLibraryAccess {
}
}
static async getAlbums(fetchOpt) {
async getAlbums(fetchOpt) {
this.logger.info(`getAlbums ${JSON.stringify(fetchOpt)}`);
try {
let albums = await MediaLibraryAccess.media.getAlbums(fetchOpt);
let albums = await this.media.getAlbums(fetchOpt);
this.logger.debug(`[getAlbums]Get Albums done`);
this.logger.debug(`[getAlbums]length :${albums.length}`);
return albums;
@ -345,14 +349,14 @@ export class MediaLibraryAccess {
}
}
static async getFavoriteAlbum(fetchOpt) {
async getFavoriteAlbum(fetchOpt) {
this.logger.debug(`getFavoriteObject`);
let result = {
count: 0,
file: undefined,
}
try {
let albums = await MediaLibraryAccess.media.getPrivateAlbum(MediaLib.PrivateAlbumType.TYPE_FAVORITE);
let albums = await this.media.getPrivateAlbum(MediaLib.PrivateAlbumType.TYPE_FAVORITE);
this.logger.debug(`[getFavoriteAlbum]Get smart Albums done`);
this.logger.debug(`[getFavoriteAlbum]Albums length:${albums.length}`);
if (albums.length > 0) {
@ -367,18 +371,18 @@ export class MediaLibraryAccess {
return result;
} catch(err) {
this.logger.error(`Get Favorite album exception! msg: ${err}`);
return null;
return result;
}
}
static async getTrashAlbum(fetchOpt) {
async getTrashAlbum(fetchOpt) {
this.logger.debug(`getTrashAlbum`);
let result = {
count: 0,
file: undefined,
}
try {
let albums = await MediaLibraryAccess.media.getPrivateAlbum(MediaLib.PrivateAlbumType.TYPE_TRASH);
let albums = await this.media.getPrivateAlbum(MediaLib.PrivateAlbumType.TYPE_TRASH);
this.logger.debug(`[getTrashAlbum]Get smart Albums done`);
this.logger.debug(`[getTrashAlbum]Albums length:${albums.length}`);
if (albums.length > 0) {
@ -393,14 +397,14 @@ export class MediaLibraryAccess {
return result;
} catch(err) {
this.logger.error(`Get Trash album exception! msg: ${err}`);
return null;
return result;
}
}
static async getConnectedRemoteDevice() {
async getConnectedRemoteDevice() {
this.logger.debug(`getConnectedRemoteDevice`);
try {
let result = await MediaLibraryAccess.media.getActivePeers();
let result = await this.media.getActivePeers();
this.logger.debug(`[getConnectedRemoteDevice]device count: ${result.length}`);
return result;
} catch(err) {
@ -408,4 +412,97 @@ export class MediaLibraryAccess {
return[];
}
}
}
export class FetchOptionBuilder {
private fetchOption = {
selections: '',
selectionArgs: [],
order:''
}
constructor(fetchOpt?){
if (fetchOpt){
this.fetchOption = fetchOpt;
}
}
build(): any{
return this.fetchOption;
}
media(mediaType: string){
this.fetchOption.selections = `${this.prefix(this.fetchOption.selections)}${MediaLibraryAccess.FILE_KEY_MEDIA_TYPE} =?`;
this.fetchOption.selectionArgs.push(mediaType);
return this;
}
order(key:string, isAsc = true){
let order = isAsc ? '' : ' DESC';
this.fetchOption.order = `${this.prefix(this.fetchOption.order)}${key}${order}`;
return this;
}
select(start: number, count: number){
this.fetchOption.order = `${this.prefix(this.fetchOption.order)}LIMIT ${start},${count}`
return this;
}
device(deviceId: string){
this.fetchOption['networkId'] = deviceId;
return this;
}
fileId(id: string){
this.fetchOption.selections = `${this.prefix(this.fetchOption.selections)}${MediaLibraryAccess.FILE_KEY_ID} =?`;
this.fetchOption.selectionArgs.push(id);
return this;
}
albumId(id: string){
this.fetchOption.selections = `${this.prefix(this.fetchOption.selections)}${MediaLibraryAccess.FILE_KEY_ALBUM_ID} =?`;
this.fetchOption.selectionArgs.push(id);
return this;
}
relativePath(path: string){
this.fetchOption.selections = `${this.prefix(this.fetchOption.selections)}${MediaLibraryAccess.FILE_KEY_RELATIVE_PATH} =?`;
this.fetchOption.selectionArgs.push(path);
return this;
}
albumName(name: string){
this.fetchOption.selections = `${this.prefix(this.fetchOption.selections)}${MediaLibraryAccess.FILE_KEY_ALBUM_NAME} =?`;
this.fetchOption.selectionArgs.push(name);
return this;
}
displayName(name: string){
this.fetchOption.selections = `${this.prefix(this.fetchOption.selections)}${MediaLibraryAccess.FILE_KEY_DISPLAY_NAME} =?`;
this.fetchOption.selectionArgs.push(name);
return this;
}
logicalAnd(){
this.fetchOption.selections = `${this.prefix(this.fetchOption.selections)}AND`;
return this;
}
logicalOr(){
this.fetchOption.selections = `${this.prefix(this.fetchOption.selections)}OR`;
return this;
}
parentheses(){
this.fetchOption.selections = `(${this.fetchOption.selections})`
return this;
}
private prefix(str: string){
if (str.length > 0){
return `${str} `;
}
return str;
}
}

View File

@ -13,21 +13,22 @@
* limitations under the License.
*/
import { TimelineDataImpl } from '../photo/TimelineDataImpl.ets';
import { PhotoDataImpl } from '../photo/PhotoDataImpl.ets';
import { AlbumDataImpl } from '../album/AlbumDataImpl.ets';
import { DistributedDataImpl } from '../album/DistributedDataImpl.ets'
import { TimelineDataImpl } from '../model/browser/photo/TimelineDataImpl';
import { PhotoDataImpl } from '../model/browser/photo/PhotoDataImpl';
import { AlbumDataImpl } from '../model/browser/album/AlbumDataImpl';
import { DistributedDataImpl } from '../model/browser/album/DistributedDataImpl'
import {BrowserDataInterface} from './BrowserDataInterface'
export class BrowserDataFactory {
static readonly TYPE_PHOTO = 'photo';
static readonly TYPE_ALBUM = 'album';
static readonly TYPE_ALBUM_SET = 'album_set';
static readonly TYPE_GROUP = 'group';
static readonly TYPE_DISTRIBUTED = 'distributed';
static getFeature(type: string, param? : any) {
if (type == BrowserDataFactory.TYPE_ALBUM_SET) {
static getFeature(type: string, param? : any): BrowserDataInterface {
if (type == BrowserDataFactory.TYPE_ALBUM) {
return new AlbumDataImpl(param);
}else if (type == BrowserDataFactory.TYPE_ALBUM) {
}else if (type == BrowserDataFactory.TYPE_PHOTO) {
return new PhotoDataImpl();
}else if (type == BrowserDataFactory.TYPE_GROUP) {
return new TimelineDataImpl();

View File

@ -14,6 +14,8 @@
*/
export interface BrowserDataInterface {
getData(callback:any, param:any): Promise<void>;
getMediaItemCount(callback:any, param:any): void;
getData(callback:any, param:any): void;
getDataCount(callback:any, param:any): void;
getDataById(id: any, deviceId? :any): any;
getDataByName(name: string, albumInfo: any): any;
}

View File

@ -12,14 +12,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { OperationImpl } from '../operation/OperationImpl.ets'
import {AlbumOperationImpl} from '../operation/AlbumOperationImpl.ets'
import { OperationImpl } from '../model/browser/photo/OperationImpl'
import {AlbumOperationImpl} from '../model/browser/album/AlbumOperationImpl'
import {BrowserOperationInterface} from './BrowserOperationInterface'
export class BrowserOperationFactory {
static readonly TYPE_PHOTO = 'photo';
static readonly TYPE_ALBUM = 'album';
static getFeature(type: string): OperationImpl {
static getFeature(type: string): BrowserOperationInterface {
if (type == BrowserOperationFactory.TYPE_PHOTO) {
return new OperationImpl();
}else if (type == BrowserOperationFactory.TYPE_ALBUM) {

View File

@ -14,13 +14,13 @@
*/
export interface BrowserOperationInterface {
create(param: any): any;
delete(uri: string): any;
trash(uri: string, isTrash: boolean): any;
copy(source: any, target: any): any;
favor(uri: string, isFavor: boolean): void;
delete(uri: string, callback: any): void;
move(uri: string, albumInfo: any, callback: any, isReplace: boolean, replaceUri?: string): void;
copy(uri: string, albumInfo: any, callback: any, isReplace: boolean): void;
trash(uri: string, callback: any): void;
rename(oldName:any, newName:any): void;
remark(): void;
setName(source: any, name: string): void;
setOrientation(source: any, orientation: number): void;
setRelativePath(source: any, relativePath: string): void;
commitChanges(source :any): any;
}

View File

@ -13,10 +13,10 @@
* limitations under the License.
*/
import {MenuOperation} from '../operation/MenuOperation'
import {MenuContext} from '../operation/MenuContext.ets'
import {Logger} from '../../../utils/Logger.ets'
import {Constants} from '../../common/Constants.ets'
import {MenuOperation} from '../view/browserOperation/MenuOperation'
import {MenuContext} from '../view/browserOperation/MenuContext'
import {Logger} from '../utils/Logger'
import {Constants} from '../model/common/Constants'
export class MenuOperationFactory {
private logger: Logger = new Logger('MenuOperationFactory');

View File

@ -13,7 +13,7 @@
* limitations under the License.
*/
import {Logger} from '../../utils/Logger.ets'
import {Logger} from '../../utils/Logger'
import {LoadingListener} from './LoadingListener'
// Abs DataSource

View File

@ -12,180 +12,160 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {MediaLibraryAccess} from '../../access/MediaLibraryAccess.ets';
import {MediaLibraryAccess, FetchOptionBuilder} from '../../access/MediaLibraryAccess'
export class AlbumDefine {
static readonly ALBUM_NAME_ALL = 'default_all';
static readonly ALBUM_NAME_CAMERA = 'default_camera';
static readonly ALBUM_NAME_VIDEO = 'default_video';
static readonly ALBUM_NAME_RECYCLE = 'default_recycle';
static readonly ALBUM_NAME_FAVOR = 'default_favor';
static readonly ALBUM_NAME_SNAPSHOT = 'default_snapshot';
static readonly ALBUM_NAME_REMOTE = 'FromOtherDevices';
static readonly ALBUM_ID_ALL = 'default_all';
static readonly ALBUM_ID_CAMERA = 'default_camera';
static readonly ALBUM_ID_VIDEO = 'default_video';
static readonly ALBUM_ID_RECYCLE = 'default_recycle';
static readonly ALBUM_ID_FAVOR = 'default_favor';
static readonly ALBUM_ID_SNAPSHOT = 'default_snapshot';
static readonly ALBUM_ID_REMOTE = 'default_remote';
static readonly ALBUM_DISABLE_COPY_LIST = new Set ([
AlbumDefine.ALBUM_NAME_ALL,
AlbumDefine.ALBUM_NAME_VIDEO,
AlbumDefine.ALBUM_NAME_RECYCLE,
AlbumDefine.ALBUM_NAME_FAVOR
AlbumDefine.ALBUM_ID_ALL,
AlbumDefine.ALBUM_ID_VIDEO,
AlbumDefine.ALBUM_ID_RECYCLE,
AlbumDefine.ALBUM_ID_FAVOR
]);
static readonly ALBUM_DISABLE_DELETE_LIST = new Set ([
AlbumDefine.ALBUM_NAME_ALL,
AlbumDefine.ALBUM_NAME_CAMERA,
AlbumDefine.ALBUM_NAME_VIDEO,
AlbumDefine.ALBUM_NAME_RECYCLE,
AlbumDefine.ALBUM_NAME_FAVOR,
AlbumDefine.ALBUM_NAME_SNAPSHOT
AlbumDefine.ALBUM_ID_ALL,
AlbumDefine.ALBUM_ID_CAMERA,
AlbumDefine.ALBUM_ID_VIDEO,
AlbumDefine.ALBUM_ID_RECYCLE,
AlbumDefine.ALBUM_ID_FAVOR
]);
static readonly ALBUM_DISABLE_NEW_LIST = new Set ([
AlbumDefine.ALBUM_ID_ALL,
AlbumDefine.ALBUM_ID_CAMERA,
AlbumDefine.ALBUM_ID_VIDEO,
AlbumDefine.ALBUM_ID_RECYCLE,
AlbumDefine.ALBUM_ID_FAVOR,
AlbumDefine.ALBUM_ID_SNAPSHOT
]);
static readonly ALBUM_DISABLE_RENAME_LIST = new Set ([
AlbumDefine.ALBUM_NAME_ALL,
AlbumDefine.ALBUM_NAME_CAMERA,
AlbumDefine.ALBUM_NAME_VIDEO,
AlbumDefine.ALBUM_NAME_RECYCLE,
AlbumDefine.ALBUM_NAME_FAVOR,
AlbumDefine.ALBUM_NAME_SNAPSHOT
AlbumDefine.ALBUM_ID_ALL,
AlbumDefine.ALBUM_ID_CAMERA,
AlbumDefine.ALBUM_ID_VIDEO,
AlbumDefine.ALBUM_ID_RECYCLE,
AlbumDefine.ALBUM_ID_FAVOR,
AlbumDefine.ALBUM_ID_SNAPSHOT
]);
static readonly ALBUM_DEFAULT_SORT_LIST = [
AlbumDefine.ALBUM_NAME_CAMERA,
AlbumDefine.ALBUM_NAME_ALL,
AlbumDefine.ALBUM_NAME_VIDEO,
AlbumDefine.ALBUM_NAME_FAVOR
AlbumDefine.ALBUM_ID_CAMERA,
AlbumDefine.ALBUM_ID_ALL,
AlbumDefine.ALBUM_ID_VIDEO,
AlbumDefine.ALBUM_ID_SNAPSHOT,
AlbumDefine.ALBUM_ID_FAVOR
];
static readonly QUERY_ORDER_BASE = 'date_added DESC'; // TODO dateTaken is not supported, use dateAdded
static readonly CAMERA_ALBUM_PATH = 'Camera'
static readonly REMOTE_ALBUM_PATH = 'FromOtherDevices'
static readonly SNAPSHOT_ALBUM_PATH = 'Screenshots'
private static readonly DEFAULT_ALBUM_FETCH_OPTIONS = new Map([
[
AlbumDefine.ALBUM_NAME_ALL,
{
selections: `${MediaLibraryAccess.FILE_KEY_MEDIA_TYPE} =? OR ${MediaLibraryAccess.FILE_KEY_MEDIA_TYPE} =?`,
selectionArgs: [MediaLibraryAccess.MEDIA_TYPE_IMAGE.toString(), MediaLibraryAccess.MEDIA_TYPE_VIDEO.toString()],
order: AlbumDefine.QUERY_ORDER_BASE
}
],
[
AlbumDefine.ALBUM_NAME_VIDEO,
{
selections: `${MediaLibraryAccess.FILE_KEY_MEDIA_TYPE} =?`,
selectionArgs: [MediaLibraryAccess.MEDIA_TYPE_VIDEO.toString()],
order: AlbumDefine.QUERY_ORDER_BASE
}
],
[
AlbumDefine.ALBUM_NAME_FAVOR,
{
selections: '',
selectionArgs: [],
order: AlbumDefine.QUERY_ORDER_BASE
}
],
[
AlbumDefine.ALBUM_NAME_RECYCLE,
{
selections: '',
selectionArgs: [],
order: 'date_trashed DESC'
}
],
[
AlbumDefine.ALBUM_NAME_CAMERA,
{
selections: 'relative_path =? AND bucket_display_name =?',
selectionArgs: ['', AlbumDefine.CAMERA_ALBUM_PATH],
}
]
]);
static getFileFetchOpt(albumId: string, deviceId?, startIndex?: number, count?: number){
let builder = new FetchOptionBuilder();
static getFetchOpt(albumName: string, deviceId?) {
let opt = AlbumDefine.DEFAULT_ALBUM_FETCH_OPTIONS.get(albumName);
let fetchOpt = {
selections: '',
selectionArgs: [],
order: ''
};
if (opt) {
fetchOpt = {
selections: opt.selections,
selectionArgs: opt.selectionArgs,
order: opt.order
};
} else {
fetchOpt = {
selections: `bucket_display_name =?`,
selectionArgs: [`${albumName}`],
order: AlbumDefine.QUERY_ORDER_BASE
};
switch (albumId) {
case AlbumDefine.ALBUM_ID_VIDEO:
builder
.media(MediaLibraryAccess.MEDIA_TYPE_VIDEO.toString())
.order(MediaLibraryAccess.FILE_KEY_DATE_TAKEN, false)
break;
case AlbumDefine.ALBUM_ID_RECYCLE:
builder
.media(MediaLibraryAccess.MEDIA_TYPE_IMAGE.toString())
.logicalOr()
.media(MediaLibraryAccess.MEDIA_TYPE_VIDEO.toString())
.order(MediaLibraryAccess.FILE_KEY_DATE_TRASHED, false)
break;
case AlbumDefine.ALBUM_ID_ALL:
case AlbumDefine.ALBUM_ID_FAVOR:
default:
builder
.media(MediaLibraryAccess.MEDIA_TYPE_IMAGE.toString())
.logicalOr()
.media(MediaLibraryAccess.MEDIA_TYPE_VIDEO.toString())
.order(MediaLibraryAccess.FILE_KEY_DATE_TAKEN, false)
break;
}
if (deviceId != undefined && deviceId != '') {
fetchOpt['networkId'] = deviceId;
if (startIndex != undefined && count != undefined && startIndex >= 0 && count >= 0) {
builder.select(startIndex, count);
}
return fetchOpt;
if(deviceId){
builder.device(deviceId);
}
return builder.build();
}
static getFileFetchOpt(fileId, deviceId?) {
let fetchOpt = {
selections : 'file_id =?',
selectionArgs : [`${fileId}`],
order: ''
};
static getFileFetchOptById(fileId: number, deviceId?: string) {
let builder = new FetchOptionBuilder().fileId(`${fileId}`);
if (deviceId != undefined && deviceId != '') {
fetchOpt['networkId'] = deviceId;
if(deviceId){
builder.device(deviceId);
}
return fetchOpt;
return builder.build();
}
static getFileFetchOptByName(displayName) {
let fetchOpt = {
selections: 'display_name =?',
selectionArgs: [`${displayName}`],
static getFileFetchOptByName(displayName: string, relativePath? :string) {
let builder = new FetchOptionBuilder().displayName(displayName);
if(relativePath){
builder.logicalAnd().relativePath(relativePath);
}
return fetchOpt;
return builder.build();
}
static getAlbumFetchOpt(displayName?, deviceId?) {
let fetchOpt = {
selections: '',
selectionArgs: []
};
static getAlbumFetchOptByName(name, relativePath){
let builder = new FetchOptionBuilder()
.albumName(name)
.logicalAnd()
.relativePath(relativePath);;
if (displayName != undefined && displayName != '') {
fetchOpt.selections = `bucket_display_name =?`,
fetchOpt.selectionArgs = [`${displayName}`]
}
return builder.build();
}
if (displayName == AlbumDefine.ALBUM_NAME_CAMERA) {
let opt = AlbumDefine.DEFAULT_ALBUM_FETCH_OPTIONS.get(displayName);
if (!opt.selectionArgs[0]) {
opt.selectionArgs[0] = globalThis.__MediaLibraryAccess_PUBLIC_PATH_IMAGE;
static getAlbumFetchOpt(id?, deviceId?) {
let builder = new FetchOptionBuilder()
.media(MediaLibraryAccess.MEDIA_TYPE_IMAGE.toString())
.logicalOr()
.media(MediaLibraryAccess.MEDIA_TYPE_VIDEO.toString())
.parentheses();
if (id){
if (id == AlbumDefine.ALBUM_ID_CAMERA){
builder
.logicalAnd()
.relativePath('')
.logicalAnd()
.albumName(`${MediaLibraryAccess.getInstance().PUBLIC_PATH_CAMERA.substr(0, MediaLibraryAccess.getInstance().PUBLIC_PATH_CAMERA.length - 1)}`)
}else{
builder.logicalAnd().albumId(id)
}
fetchOpt.selections = opt.selections;
fetchOpt.selectionArgs = opt.selectionArgs;
}
if (deviceId != undefined && deviceId != '') {
fetchOpt["networkId"] = deviceId;
if(deviceId){
builder.device(deviceId);
}
return fetchOpt;
return builder.build();
}
static getAlbumPath(albumName) {
if (albumName == AlbumDefine.ALBUM_NAME_CAMERA) {
return AlbumDefine.CAMERA_ALBUM_PATH;
static genAlbumRelativePath(albumName: string, isOrigin: boolean = false): string {
if (isOrigin){
return MediaLibraryAccess.getInstance().PUBLIC_PATH_CAMERA;
}
return albumName;
let path = `${MediaLibraryAccess.getInstance().PUBLIC_PATH_CAMERA}${albumName}/`;
return path;
}
}

View File

@ -12,99 +12,70 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {BrowserDataInterface} from './interface/BrowserDataInterface'
import {BrowserDataInterface} from '../../interface/BrowserDataInterface'
import {AlbumDefine} from './AlbumDefine'
import {Logger} from '../../utils/Logger.ets'
import {MediaLibraryAccess} from '../../access/MediaLibraryAccess.ets';
import {Logger} from '../../utils/Logger'
import {MediaLibraryAccess} from '../../access/MediaLibraryAccess';
export abstract class BrowserDataImpl implements BrowserDataInterface {
logger: Logger = new Logger('BrowserDataImpl');
static readonly THUMBNAIL_WIDTH = 256;
abstract getData(callback, param): Promise<void>;
abstract getMediaItemCount(callback, param): void;
abstract getData(callback, param): void;
abstract getDataCount(callback, param): void;
abstract getDataById(id: any, deviceId? :any): any;
abstract getDataByName(name: string, albumInfo: any): any;
async getAllObject(fetchOpt) {
this.logger.debug('getAllObject');
let allObject = await MediaLibraryAccess.getAllObject(fetchOpt);
let allObject = await MediaLibraryAccess.getInstance().getAllObject(fetchOpt);
return allObject;
}
async getCount(fetchOpt) {
let count = await MediaLibraryAccess.getCount(fetchOpt);
let count = await MediaLibraryAccess.getInstance().getCount(fetchOpt);
return count;
}
async getFirstObject(fetchOpt) {
this.logger.debug('getFirstObject');
let firstObject = await MediaLibraryAccess.getFirstObject(fetchOpt);
let firstObject = await MediaLibraryAccess.getInstance().getFirstObject(fetchOpt);
return firstObject;
}
async getItems(albumName: string, startIndex?: number, count?:number, deviceId?) {
let external_order = '';
if ( startIndex != undefined && count != undefined && startIndex >= 0 && count >= 0) {
external_order = ` LIMIT ${startIndex},${count}`;
}
let fetchOpt = AlbumDefine.getFetchOpt(albumName, deviceId);
fetchOpt.order += external_order;
switch (albumName) {
case AlbumDefine.ALBUM_NAME_ALL:
case AlbumDefine.ALBUM_NAME_VIDEO:
async getItems(albumId: string, startIndex?: number, count?:number, deviceId?) {
let fetchOpt = AlbumDefine.getFileFetchOpt(albumId, deviceId, startIndex, count);
switch (albumId) {
case AlbumDefine.ALBUM_ID_ALL:
case AlbumDefine.ALBUM_ID_VIDEO:
return await this.getAllObject(fetchOpt);
case AlbumDefine.ALBUM_NAME_FAVOR:
return await MediaLibraryAccess.getFavoriteObject(fetchOpt);
case AlbumDefine.ALBUM_NAME_RECYCLE:
return await MediaLibraryAccess.getTrashObject(fetchOpt);
case AlbumDefine.ALBUM_ID_FAVOR:
return await MediaLibraryAccess.getInstance().getFavoriteObject(fetchOpt);
case AlbumDefine.ALBUM_ID_RECYCLE:
return await MediaLibraryAccess.getInstance().getTrashObject(fetchOpt);
default:
let fileFetchOpt = {
selections: '',
selectionArgs: [],
order: AlbumDefine.QUERY_ORDER_BASE + external_order
}
if (deviceId != undefined && deviceId != '') {
fetchOpt['networkId'] = deviceId
}
return await MediaLibraryAccess.getEntityAlbumObject(
AlbumDefine.getAlbumFetchOpt(albumName, deviceId), fileFetchOpt);
return await MediaLibraryAccess.getInstance().getEntityAlbumObject(
AlbumDefine.getAlbumFetchOpt(albumId, deviceId), fetchOpt);
break;
}
}
async getItemsCount(albumName, deviceId?) {
switch (albumName) {
case AlbumDefine.ALBUM_NAME_ALL:
case AlbumDefine.ALBUM_NAME_VIDEO:
let fetchOpt = AlbumDefine.getFetchOpt(albumName, deviceId);
async getItemsCount(albumId, deviceId?) {
switch (albumId) {
case AlbumDefine.ALBUM_ID_ALL:
case AlbumDefine.ALBUM_ID_VIDEO:
let fetchOpt = AlbumDefine.getFileFetchOpt(albumId, deviceId);
return await this.getCount(fetchOpt);
case AlbumDefine.ALBUM_NAME_FAVOR:
return await MediaLibraryAccess.getFavoriteCount();
case AlbumDefine.ALBUM_NAME_RECYCLE:
return await MediaLibraryAccess.getTrashCount();
case AlbumDefine.ALBUM_ID_FAVOR:
return await MediaLibraryAccess.getInstance().getFavoriteCount();
case AlbumDefine.ALBUM_ID_RECYCLE:
return await MediaLibraryAccess.getInstance().getTrashCount();
default:
return await MediaLibraryAccess.getEntityAlbumCount(AlbumDefine.getAlbumFetchOpt(albumName, deviceId));
return await MediaLibraryAccess.getInstance().getEntityAlbumCount(AlbumDefine.getAlbumFetchOpt(albumId, deviceId), AlbumDefine.getFileFetchOpt(''));
break;
}
}
async getTrashObjectById(id) {
this.logger.info('getTrashObjectById');
try {
let result = await MediaLibraryAccess.getTrashObject(AlbumDefine.getFileFetchOpt(id));
if (result == null) {
this.logger.info('getTrashObjectByUri fail');
return null;
}
return result[0];
} catch (error) {
this.logger.error('getTrashObject error');
return null;
}
}
getThumbnailSafe(sourceUri: string, size?) {
this.logger.debug('getThumbnailSafe');
@ -115,7 +86,7 @@ export abstract class BrowserDataImpl implements BrowserDataInterface {
return `${sourceUri}/thumbnail/${BrowserDataImpl.THUMBNAIL_WIDTH}/${BrowserDataImpl.THUMBNAIL_WIDTH}`;
}
} catch (err) {
this.logger.warn(`get Thumbnail Failed! msg:${err}`);
this.logger.error(`get Thumbnail Failed! msg:${err}`);
return null;
}
}

View File

@ -13,13 +13,13 @@
* limitations under the License.
*/
import {TimelineData} from './photo/TimelineData.ets'
import {Logger} from '../../utils/Logger.ets'
import {MediaItem} from './photo/MediaItem.ets'
import {TimelineData} from './photo/TimelineData'
import {Logger} from '../../utils/Logger'
import {MediaItem} from './photo/MediaItem'
import {AsyncCallback} from '../common/AsyncCallback'
import {AlbumDefine} from './AlbumDefine'
import {BrowserDataFactory} from './interface/BrowserDataFactory.ets'
import {BrowserDataInterface} from './interface/BrowserDataInterface'
import {BrowserDataFactory} from '../../interface/BrowserDataFactory'
import {BrowserDataInterface} from '../../interface/BrowserDataInterface'
export class BucketSelectionEntry {
private groupId = -1;
@ -69,7 +69,7 @@ export class BucketSelectionEntry {
this.clickedSet.clear();
}
public deSelectAll() {
public unselectAll() {
this.inverseSelection = false;
this.groupSelect = false;
this.clickedSet.clear();
@ -91,8 +91,8 @@ export class BucketSelectionEntry {
*/
public changeSelectMode(isInverseMode: boolean) {
isInverseMode
? (this.getSelectedCount() == 0 ? this.selectAll() : this.deSelectAll())
: (this.inSelectAllMode() ? this.deSelectAll() : this.selectAll())
? (this.getSelectedCount() == 0 ? this.selectAll() : this.unselectAll())
: (this.inSelectAllMode() ? this.unselectAll() : this.selectAll())
}
public getInverseSelection() {
@ -137,7 +137,7 @@ export class SelectManager {
mCallbacks = {};
photoDataImpl: BrowserDataInterface;
selectManagerCallback;
albumName = undefined;
albumId = undefined;
deviceId = undefined;
constructor() {
@ -147,14 +147,23 @@ export class SelectManager {
public setTotalCount(count: number) {
this.totalCount = count;
this.mCallbacks['updateCount'] && this.mCallbacks['updateCount'](this.getSelectedCount());
if (this.isAllSelected) {
this.isAllSelected = false;
this.mCallbacks['allSelect'] && this.mCallbacks['allSelect'](false);
}
if (this.totalCount == this.getSelectedCount()) {
this.isAllSelected = true;
this.mCallbacks['allSelect'] && this.mCallbacks['allSelect'](true);
}
}
public setPhotoDataImpl() {
this.photoDataImpl = BrowserDataFactory.getFeature(BrowserDataFactory.TYPE_ALBUM);
this.photoDataImpl = BrowserDataFactory.getFeature(BrowserDataFactory.TYPE_PHOTO);
}
public setAlbumName(albumName) {
this.albumName = albumName;
public setAlbumId(albumId) {
this.albumId = albumId;
}
public setDeviceId(deviceId) {
@ -208,7 +217,7 @@ export class SelectManager {
this.mCallbacks['updateCount'] && this.mCallbacks['updateCount'](this.getSelectedCount());
}
public deSelectAll() {
public unselectAll() {
this.inverseSelection = false;
this.isAllSelected = false;
this.clickedSet.clear();
@ -241,7 +250,7 @@ export class SelectManager {
if (this.inverseSelection) {
this.selectManagerCallback.setSubCallback(callback);
this.photoDataImpl.getData(this.selectManagerCallback, {
name: this.albumName,
id: this.albumId,
deviceId: this.deviceId
});
} else {
@ -255,7 +264,7 @@ export class SelectManager {
if (this.inverseSelection) {
this.selectManagerCallback.setSubCallback(callback);
this.photoDataImpl.getData(this.selectManagerCallback, {
name: AlbumDefine.ALBUM_NAME_RECYCLE
id: AlbumDefine.ALBUM_ID_RECYCLE
});
} else {
let result = [];
@ -296,21 +305,20 @@ export class SelectManager {
}
public async getItems(photoDataImpl: BrowserDataInterface,
start: number, count: number, callback: Function): Promise<void> {
start: number, count: number, callbackFunc: Function): Promise<void> {
this.logger.info(`getItems start: ${start} count: ${count}`);
let cb: AsyncCallback<MediaItem[]> = {
callback(t: MediaItem[]) {
callback(t);
callback: (t: MediaItem[]) => {
callbackFunc(t);
}
}
if (this.albumName) {
if (this.albumId) {
await photoDataImpl.getData(cb,
{name: this.albumName, start: start, count: count, deviceId: this.deviceId});
{id: this.albumId, start: start, count: count, deviceId: this.deviceId});
} else {
await photoDataImpl.getData(cb,
{name: AlbumDefine.ALBUM_NAME_ALL, start: start, count: count, deviceId: this.deviceId});
{id: AlbumDefine.ALBUM_ID_ALL, start: start, count: count, deviceId: this.deviceId});
}
}
}
@ -385,7 +393,7 @@ export class TimelineSelectManager extends SelectManager {
this.mCallbacks['updateCount'] && this.mCallbacks['updateCount'](this.getSelectedCount());
}
public deSelectAll() {
public unselectAll() {
this.inverseSelection = false;
this.isAllSelected = false;
this.clearEntryArray();

View File

@ -15,28 +15,31 @@
import {AlbumDefine} from '../AlbumDefine'
import {AlbumInfo} from './AlbumInfo'
import {AsyncCallback} from '../../common/AsyncCallback'
import {BrowserDataImpl} from '../BrowserDataImpl.ets'
import {MediaLibraryAccess} from '../../../access/MediaLibraryAccess.ets'
import {Logger} from '../../../utils/Logger.ets'
import {BrowserDataImpl} from '../BrowserDataImpl'
import {MediaLibraryAccess} from '../../../access/MediaLibraryAccess'
import {Logger} from '../../../utils/Logger'
import {UiUtil} from '../../../utils/UiUtil'
export class AlbumDataImpl extends BrowserDataImpl {
logger = new Logger('AlbumDataImpl');
private virtualAlbumList = [
AlbumDefine.ALBUM_NAME_ALL,
AlbumDefine.ALBUM_NAME_VIDEO,
AlbumDefine.ALBUM_ID_ALL,
AlbumDefine.ALBUM_ID_VIDEO,
];
private entityAlbumList = new Map([
[AlbumDefine.CAMERA_ALBUM_PATH, AlbumDefine.ALBUM_NAME_CAMERA],
[AlbumDefine.ALBUM_NAME_REMOTE, AlbumDefine.ALBUM_NAME_REMOTE],
[`${MediaLibraryAccess.getInstance().PUBLIC_PATH_CAMERA}`, AlbumDefine.ALBUM_ID_CAMERA],
[`${MediaLibraryAccess.getInstance().PUBLIC_PATH_CAMERA}${AlbumDefine.REMOTE_ALBUM_PATH}/`, AlbumDefine.ALBUM_ID_REMOTE],
[`${MediaLibraryAccess.getInstance().PUBLIC_PATH_IMAGE}${AlbumDefine.SNAPSHOT_ALBUM_PATH}/`, AlbumDefine.ALBUM_ID_SNAPSHOT],
]);
private deviceId:string = '';
private deviceName:string = '';
private moreInfo: boolean = false;
constructor(param) {
super();
if (param) {
if (param && param.deviceId) {
this.logger.debug(`Remote networkId: ${param.deviceId}`);
this.deviceId = param.deviceId;
this.deviceName = param.deviceName;
@ -44,22 +47,47 @@ export class AlbumDataImpl extends BrowserDataImpl {
this.logger.debug(`Local`);
}
if (param && param.moreInfo){
this.moreInfo = param.moreInfo
}
this.logger = new Logger(`AlbumDataImpl[${this.deviceId}]`);
}
async getData(callback, param) : Promise<void> {
return new Promise((resolve) => {
if (param == null) {
this.buildAlbums(callback);
} else {
this.genAlbumsInfo(callback,param);
}
resolve();
});
getData(callback, param) : void {
if (param == null) {
this.buildAlbums(callback);
} else {
this.genAlbumsInfo(callback,param);
}
}
private async genAlbumsInfo(cb, uris) {
this.logger.debug(`genAlbumsInfo uris: ${JSON.stringify(uris)}`);
async getDataById(id: any, deviceId? :any) {
let albums = await MediaLibraryAccess.getInstance().getAlbums(AlbumDefine.getAlbumFetchOpt(id, deviceId));
if (albums && albums.length > 0){
return albums[0];
}else{
return null;
}
}
async getDataByName(name: string, albumInfo: any) {
let albums = await MediaLibraryAccess.getInstance().getAlbums(AlbumDefine.getAlbumFetchOptByName(name, albumInfo.relativePath));
if (albums && albums.length > 0){
let fileResult = await albums[0].getFileAssets(AlbumDefine.getFileFetchOpt(''));
let count = fileResult.getCount();
if (count <= 0) {
this.logger.warn(`Not valid album Name: ${albums[0].albumName} URI: ${albums[0].albumUri} relativePath: ${albums[0].relativePath} id: ${albums[0].albumId}`);
return null;
}
return albums[0];
}else{
return null;
}
}
private async genAlbumsInfo(cb, ids) {
this.logger.debug(`genAlbumsInfo ids: ${JSON.stringify(ids)}`);
let res = {
uris: [],
@ -67,15 +95,15 @@ export class AlbumDataImpl extends BrowserDataImpl {
videoCount: 0,
};
for (let name of uris) {
let objects = await super.getItems(name, -1, -1, this.deviceId);
this.logger.debug(`get album objects: Name:${name} length: ${objects.length}`);
for (let id of ids) {
let objects = await super.getItems(id, -1, -1, this.deviceId);
this.logger.debug(`get album objects: id:${id} length: ${objects.length}`);
res.count += objects.length;
for (let item of objects) {
res.uris.push(item.uri);
}
let tmpAlbum = new AlbumInfo('', name, '', 0, '');
let tmpAlbum = new AlbumInfo(id, '', '', '', 0, '', '');
await this.updateAlbumVideoCount(tmpAlbum);
this.logger.debug(`get album objects: vcount: ${tmpAlbum.videoCount}`);
res.videoCount += tmpAlbum.videoCount;
@ -113,15 +141,17 @@ export class AlbumDataImpl extends BrowserDataImpl {
return;
}
for (let name of this.virtualAlbumList) {
let file = await this.getFirstObject(AlbumDefine.getFetchOpt(name, this.deviceId));
for (let id of this.virtualAlbumList) {
let file = await this.getFirstObject(AlbumDefine.getFileFetchOpt(id, this.deviceId));
if (file.count > 0) {
let data = new AlbumInfo(this.getThumbnailSafe(file.obj.uri),
name, this.getAlbumDisplayName(name), file.count, this.deviceId);
let data = new AlbumInfo(id, this.getThumbnailSafe(file.obj.uri),
id, await this.getAlbumDisplayName(id), file.count, this.deviceId, '');
data.coverOrientation = file.obj.orientation;
data.deviceName = this.deviceName;
data.isDisableDelete = AlbumDefine.ALBUM_DISABLE_DELETE_LIST.has(name);
data.isDisableRename = AlbumDefine.ALBUM_DISABLE_RENAME_LIST.has(name);
albumList.set(data.name, data);
data.innerId = id;
data.isDisableDelete = AlbumDefine.ALBUM_DISABLE_DELETE_LIST.has(data.innerId);
data.isDisableRename = AlbumDefine.ALBUM_DISABLE_RENAME_LIST.has(data.innerId);
albumList.set(data.innerId, data);
}
}
@ -133,12 +163,15 @@ export class AlbumDataImpl extends BrowserDataImpl {
return;
}
let favAlbum = await MediaLibraryAccess.getFavoriteAlbum(AlbumDefine.getFetchOpt(AlbumDefine.ALBUM_NAME_FAVOR));
let favAlbum = await MediaLibraryAccess.getInstance().getFavoriteAlbum(AlbumDefine.getFileFetchOpt(AlbumDefine.ALBUM_ID_FAVOR));
if (favAlbum.count > 0) {
let fav = new AlbumInfo(await this.getThumbnailSafe(favAlbum.file.uri), AlbumDefine.ALBUM_NAME_FAVOR, this.getAlbumDisplayName(AlbumDefine.ALBUM_NAME_FAVOR), favAlbum.count, this.deviceId);
fav.isDisableDelete = AlbumDefine.ALBUM_DISABLE_DELETE_LIST.has(fav.name);
fav.isDisableRename = AlbumDefine.ALBUM_DISABLE_RENAME_LIST.has(fav.name);
albumList.set(fav.name, fav);
let fav = new AlbumInfo(AlbumDefine.ALBUM_ID_FAVOR, this.getThumbnailSafe(favAlbum.file.uri), AlbumDefine.ALBUM_ID_FAVOR,
await this.getAlbumDisplayName(AlbumDefine.ALBUM_ID_FAVOR), favAlbum.count, this.deviceId, '');
fav.coverOrientation = favAlbum.file.orientation;
fav.innerId = fav.id;
fav.isDisableDelete = AlbumDefine.ALBUM_DISABLE_DELETE_LIST.has(fav.innerId);
fav.isDisableRename = AlbumDefine.ALBUM_DISABLE_RENAME_LIST.has(fav.innerId);
albumList.set(fav.innerId, fav);
}
}
@ -147,12 +180,14 @@ export class AlbumDataImpl extends BrowserDataImpl {
return;
}
let trashAlbum = await MediaLibraryAccess.getTrashAlbum(AlbumDefine.getFetchOpt(AlbumDefine.ALBUM_NAME_RECYCLE));
let trashAlbum = await MediaLibraryAccess.getInstance().getTrashAlbum(AlbumDefine.getFileFetchOpt(AlbumDefine.ALBUM_ID_RECYCLE));
if (trashAlbum.count > 0) {
let trash = new AlbumInfo(await this.getThumbnailSafe(trashAlbum.file.uri), AlbumDefine.ALBUM_NAME_RECYCLE,
this.getAlbumDisplayName(AlbumDefine.ALBUM_NAME_RECYCLE), trashAlbum.count, this.deviceId);
trash.isDisableDelete = AlbumDefine.ALBUM_DISABLE_DELETE_LIST.has(trash.name);
trash.isDisableRename = AlbumDefine.ALBUM_DISABLE_RENAME_LIST.has(trash.name);
let trash = new AlbumInfo(AlbumDefine.ALBUM_ID_RECYCLE, this.getThumbnailSafe(trashAlbum.file.uri), AlbumDefine.ALBUM_ID_RECYCLE,
await this.getAlbumDisplayName(AlbumDefine.ALBUM_ID_RECYCLE), trashAlbum.count, this.deviceId, '');
trash.coverOrientation = trashAlbum.file.orientation;
trash.innerId = trash.id;
trash.isDisableDelete = AlbumDefine.ALBUM_DISABLE_DELETE_LIST.has(trash.innerId);
trash.isDisableRename = AlbumDefine.ALBUM_DISABLE_RENAME_LIST.has(trash.innerId);
albumList.push(trash);
}
@ -161,35 +196,34 @@ export class AlbumDataImpl extends BrowserDataImpl {
private async getEntityAlbumSourceData(output) {
this.logger.debug('getEntityAlbumSourceData');
let fileFetchOpt = {
selections: '',
selectionArgs: [],
order: AlbumDefine.QUERY_ORDER_BASE
};
let albums = await MediaLibraryAccess.getAlbums(AlbumDefine.getAlbumFetchOpt('', this.deviceId));
let albums = await MediaLibraryAccess.getInstance().getAlbums(AlbumDefine.getAlbumFetchOpt('', this.deviceId));
if (albums) {
for (let item of albums) {
let fileResult = await item.getFileAssets(fileFetchOpt);
let fileResult = await item.getFileAssets(AlbumDefine.getFileFetchOpt(''));
let count = fileResult.getCount();
if (count <= 0) {
this.logger.warn(`Not valid album Name: ${item.albumName} URI: ${item.albumUri}`);
this.logger.warn(`Not valid album Name: ${item.albumName} URI: ${item.albumUri} relativePath: ${item.relativePath} id: ${item.albumId}`);
continue;
}
let obj = await fileResult.getFirstObject();
this.logger.debug(`albumName: ${item.albumName} file count: ${count} coverUri:${obj.uri}`);
this.logger.debug(`albumName: ${item.albumName} file count: ${count} coverUri:${obj.uri} relativePath: ${item.relativePath} id: ${item.albumId}`);
let album = new AlbumInfo(this.getThumbnailSafe(obj.uri),
item.albumName, item.albumName, count, this.deviceId);
let album = new AlbumInfo(`${item.albumId}`, this.getThumbnailSafe(obj.uri),
item.albumName, item.albumName, count, this.deviceId, obj.relativePath);
album.coverOrientation = obj.orientation;
album.uri = item.albumUri;
album.deviceName = this.deviceName;
album.innerId = album.id;
this.fixDefaultEntityAlbum(album, obj);
await this.fixDefaultEntityAlbum(album);
album.isDisableDelete = AlbumDefine.ALBUM_DISABLE_DELETE_LIST.has(album.name);
album.isDisableRename = AlbumDefine.ALBUM_DISABLE_RENAME_LIST.has(album.name);
await this.updateAlbumVideoCount(album);
output.set(album.name, album);
album.isDisableDelete = AlbumDefine.ALBUM_DISABLE_DELETE_LIST.has(album.innerId);
album.isDisableRename = AlbumDefine.ALBUM_DISABLE_RENAME_LIST.has(album.innerId);
if (this.moreInfo){
await this.updateAlbumVideoCount(album);
}
output.set(album.innerId, album);
fileResult.close();
}
@ -200,31 +234,33 @@ export class AlbumDataImpl extends BrowserDataImpl {
this.logger.debug('get entity album done');
}
private getAlbumDisplayName(name) {
private async getAlbumDisplayName(name) {
switch (name) {
case AlbumDefine.ALBUM_NAME_ALL:
return $r('app.string.album_all');
case AlbumDefine.ALBUM_NAME_VIDEO:
return $r('app.string.album_video');
case AlbumDefine.ALBUM_NAME_RECYCLE:
return $r('app.string.album_recycle');
case AlbumDefine.ALBUM_NAME_CAMERA:
return $r('app.string.album_camera');
case AlbumDefine.ALBUM_NAME_FAVOR:
return $r('app.string.album_favor');
case AlbumDefine.ALBUM_NAME_REMOTE:
return $r('app.string.album_remote_device');
case AlbumDefine.ALBUM_ID_ALL:
return await UiUtil.getResourceString($r('app.string.album_all'));
case AlbumDefine.ALBUM_ID_VIDEO:
return await UiUtil.getResourceString($r('app.string.album_video'));
case AlbumDefine.ALBUM_ID_RECYCLE:
return await UiUtil.getResourceString($r('app.string.album_recycle'));
case AlbumDefine.ALBUM_ID_CAMERA:
return await UiUtil.getResourceString($r('app.string.album_camera'));
case AlbumDefine.ALBUM_ID_FAVOR:
return await UiUtil.getResourceString($r('app.string.album_favor'));
case AlbumDefine.ALBUM_ID_REMOTE:
return await UiUtil.getResourceString($r('app.string.album_remote_device'));
case AlbumDefine.ALBUM_ID_SNAPSHOT:
return await UiUtil.getResourceString($r('app.string.album_screen_shot'));
default:
break;
}
return null;
}
private fixDefaultEntityAlbum(album, src) {
let value = this.entityAlbumList.get(album.name);
if (value != undefined && src.relativePath == `${globalThis.__MediaLibraryAccess_PUBLIC_PATH_IMAGE}${album.name}/`) {
album.displayName = this.getAlbumDisplayName(value);
album.name = value;
private async fixDefaultEntityAlbum(album: AlbumInfo) {
let value = this.entityAlbumList.get(album.relativePath);
if (value != undefined) {
album.displayName = await this.getAlbumDisplayName(value);
album.innerId = value;
}
}
@ -252,23 +288,23 @@ export class AlbumDataImpl extends BrowserDataImpl {
return AlbumDefine.ALBUM_DEFAULT_SORT_LIST;
}
getMediaItemCount(callback, albumInfo) {
getDataCount(callback, albumInfo) {
this.updateAlbumVideoCount(albumInfo);
}
async updateAlbumVideoCount(albumInfo: AlbumInfo) {
this.logger.debug(`updateAlbumVideoCount ${albumInfo.name}`);
switch (albumInfo.name) {
case AlbumDefine.ALBUM_NAME_ALL:
albumInfo.videoCount = await super.getCount(AlbumDefine.getFetchOpt(AlbumDefine.ALBUM_NAME_VIDEO));
this.logger.debug(`updateAlbumVideoCount ${albumInfo.id}`);
switch (albumInfo.id) {
case AlbumDefine.ALBUM_ID_ALL:
albumInfo.videoCount = await super.getCount(AlbumDefine.getFileFetchOpt(AlbumDefine.ALBUM_ID_VIDEO));
break;
case AlbumDefine.ALBUM_NAME_VIDEO:
case AlbumDefine.ALBUM_ID_VIDEO:
albumInfo.videoCount = albumInfo.count;
break;
default:
albumInfo.videoCount
= await MediaLibraryAccess.getEntityAlbumCount(AlbumDefine.getAlbumFetchOpt(albumInfo.name),
AlbumDefine.getFetchOpt(AlbumDefine.ALBUM_NAME_VIDEO));
= await MediaLibraryAccess.getInstance().getEntityAlbumCount(AlbumDefine.getAlbumFetchOpt(albumInfo.id),
AlbumDefine.getFileFetchOpt(AlbumDefine.ALBUM_ID_VIDEO));
break;
}
}

View File

@ -14,18 +14,23 @@
*/
export class AlbumInfo {
id: string;
coverUri: any;
coverOrientation: number;
name: string;
uri: string;
displayName: Resource;
displayName: string;
count: number;
videoCount: number;
isDisableRename: boolean;
isDisableDelete: boolean;
deviceId: string;
deviceName: string;
relativePath: string;
innerId: string;
constructor(uri, name, displayName, count, deviceId) {
constructor(id, uri, name, displayName, count, deviceId, relativePath) {
this.id = id;
this.coverUri = uri;
this.name = name;
this.displayName = displayName;
@ -34,5 +39,6 @@ export class AlbumInfo {
this.isDisableDelete = false;
this.videoCount = 0;
this.deviceId = deviceId;
this.relativePath = relativePath;
}
}

View File

@ -0,0 +1,36 @@
/*
* 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 {BrowserOperationInterface} from '../../../interface/BrowserOperationInterface'
import {Logger} from '../../../utils/Logger'
export class AlbumOperationImpl implements BrowserOperationInterface {
logger: Logger = new Logger('AlbumOperationImpl');
setName(album: any, name: string): void {
album.albumName = name;
}
async commitChanges(album :any) {
await album.commitModify();
}
favor(uri: string, isFavor: boolean): void{}
delete(uri: string): any{}
copy(source: any, target: any): any{}
trash(uri: string, isTrash: boolean): void{}
create(param: any): any{}
setOrientation(source: any, orientation: number): void{}
setRelativePath(source: any, relativePath: string): void{}
}

View File

@ -15,8 +15,8 @@
import {AlbumSetDataSource} from './AlbumSetDataSource'
import {AsyncCallback} from '../../common/AsyncCallback'
import { TraceControllerUtils } from '../../../utils/TraceControllerUtils.ets';
import { AlbumInfo } from './AlbumInfo.ets';
import { TraceControllerUtils } from '../../../utils/TraceControllerUtils';
import { AlbumInfo } from './AlbumInfo';
export class AlbumSetCallback implements AsyncCallback<AlbumInfo[]> {
source: AlbumSetDataSource;

View File

@ -13,15 +13,15 @@
* limitations under the License.
*/
import { AlbumSetCallback } from './AlbumSetCallback.ets';
import { TraceControllerUtils } from '../../../utils/TraceControllerUtils.ets';
import { BrowserDataFactory } from '../interface/BrowserDataFactory.ets';
import { BrowserDataInterface } from '../interface/BrowserDataInterface';
import { BroadCast } from '../../../utils/BroadCast.ets';
import { Logger } from '../../../utils/Logger.ets';
import { AlbumInfo } from './AlbumInfo.ets';
import { AbsDataSource } from '../AbsDataSource.ets';
import { Constants } from '../../common/Constants.ets';
import { AlbumSetCallback } from './AlbumSetCallback';
import { TraceControllerUtils } from '../../../utils/TraceControllerUtils';
import { BrowserDataFactory } from '../../../interface/BrowserDataFactory';
import { BrowserDataInterface } from '../../../interface/BrowserDataInterface';
import { BroadCast } from '../../../utils/BroadCast';
import { Logger } from '../../../utils/Logger';
import { AlbumInfo } from './AlbumInfo';
import { AbsDataSource } from '../AbsDataSource';
import { Constants } from '../../common/Constants';
export class AlbumSetDataSource extends AbsDataSource {
logger: Logger = new Logger('AlbumSetDataSource');
@ -34,15 +34,15 @@ export class AlbumSetDataSource extends AbsDataSource {
private blackList: Array<string> = [];
private deviceId = ''
constructor(broadCast: BroadCast, device?) {
constructor(broadCast: BroadCast, param?) {
super();
this.logger.debug(`constructor ${JSON.stringify(device)}`);
this.logger.debug(`constructor ${JSON.stringify(param)}`);
this.broadCast_ = broadCast;
this.albumBrowserDataImpl = BrowserDataFactory.getFeature(BrowserDataFactory.TYPE_ALBUM_SET, device);
this.albumBrowserDataImpl = BrowserDataFactory.getFeature(BrowserDataFactory.TYPE_ALBUM, param);
if (device != undefined){
this.deviceId = device.deviceId;
if (param && param.deviceId){
this.deviceId = param.deviceId;
}
}
@ -52,13 +52,12 @@ export class AlbumSetDataSource extends AbsDataSource {
this.loadData();
}
loadData(): Promise<void> {
loadData(): void {
this.logger.info('load data');
if (this.albumBrowserDataImpl != null) {
let callback: AlbumSetCallback = new AlbumSetCallback(this);
return this.albumBrowserDataImpl.getData(callback, null);
this.albumBrowserDataImpl.getData(callback, null);
}
return new Promise((resolve) => {resolve()})
}
totalCount(): number {
@ -101,7 +100,7 @@ export class AlbumSetDataSource extends AbsDataSource {
}
this.logger.debug(`BlackList: albums name ${JSON.stringify(this.blackList)}.`);
let res = mediaSetList.filter((item) => {
return this.blackList.indexOf(item.name) < 0;
return this.blackList.indexOf(item.id) < 0;
});
this.logger.debug(`BlackList: old albums length ${mediaSetList.length}, new albums length ${res.length}.`);
return res;
@ -109,11 +108,11 @@ export class AlbumSetDataSource extends AbsDataSource {
onChange(mediaType: string) {
if(this.deviceId == '' || this.deviceId == undefined) {
if (mediaType == 'image' || mediaType == 'video' || mediaType == 'album'){
if (mediaType == Constants.MEDIA_TYPE_IMAGE || mediaType == Constants.MEDIA_TYPE_VIDEO || mediaType == Constants.MEDIA_TYPE_ALBUM){
super.onChange(mediaType);
}
}else{
if (mediaType == 'remote'){
if (mediaType == Constants.MEDIA_TYPE_REMOTE){
super.onChange(mediaType);
}
}
@ -121,50 +120,10 @@ export class AlbumSetDataSource extends AbsDataSource {
updateAlbumMediaCount() {
for (let album of this.mediaSetList) {
this.albumBrowserDataImpl.getMediaItemCount(null, album);
this.albumBrowserDataImpl.getDataCount(null, album);
}
}
getNewAlbumDefaultName(prefixName : string) : string {
let numbers = [];
for (let album of this.mediaSetList) {
let res = album.name.match(new RegExp(`${prefixName}[1-9][0-9]*`));
if (res != null) {
let number = res[0].match(new RegExp(`[1-9][0-9]*`));
numbers.push(parseInt(number[0]));
}
}
if (numbers.length <= 0) {
return `${prefixName}1`;
} else if (numbers.length == 1) {
if (numbers[0] - 1 > 0) {
return `${prefixName}${numbers[0] - 1}`;
} else {
return `${prefixName}${numbers[0] + 1}`;
}
}
numbers.sort(function(a, b) { return a - b; });
for (let i = 1; i < numbers.length; i++) {
let res = numbers[i - 1] + 1;
if (res < numbers[i]) {
return `${prefixName}${res}`;
}
}
return `${prefixName}${numbers[numbers.length - 1] + 1}`;
}
isRepeatedName(albumName) {
for (let album of this.mediaSetList) {
if (album.name == albumName) {
return true;
}
}
return false;
}
setBlackList(albums: Array<string>) {
this.blackList = albums;
this.logger.debug(`BlackList: set blacklist ${JSON.stringify(this.blackList)}.`);

View File

@ -12,11 +12,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {BrowserDataImpl} from '../BrowserDataImpl.ets'
import {BrowserDataImpl} from '../BrowserDataImpl'
import {PeerInfo} from './PeerInfo'
import {MediaLibraryAccess} from '../../../access/MediaLibraryAccess.ets';
import {MediaLibraryAccess} from '../../../access/MediaLibraryAccess';
import {AlbumDefine} from '../AlbumDefine'
import {Logger} from '../../../utils/Logger.ets'
import {Logger} from '../../../utils/Logger'
export class DistributedDataImpl extends BrowserDataImpl {
constructor() {
@ -24,27 +24,28 @@ export class DistributedDataImpl extends BrowserDataImpl {
this.logger = new Logger('DistributedDataImpl');
}
async getData(callback:any, param:any): Promise<void> {
getData(callback:any, param:any): void{
let result : PeerInfo[] = [];
let devices = await MediaLibraryAccess.getConnectedRemoteDevice();
for (let dev of devices) {
this.logger.info(`Online remote Device Name:${dev.deviceName} networkID: ${dev.networkId}`);
let peerInfo = new PeerInfo(null, dev.deviceName, 0, dev.networkId);
let file = await this.getFirstObject(AlbumDefine.getFetchOpt(AlbumDefine.ALBUM_NAME_ALL, dev.networkId));
MediaLibraryAccess.getInstance().getConnectedRemoteDevice().then(async (devices) => {
for (let dev of devices) {
this.logger.info(`Online remote Device Name:${dev.deviceName} networkID: ${dev.networkId}`);
let peerInfo = new PeerInfo(null, dev.deviceName, 0, dev.networkId);
let file = await this.getFirstObject(AlbumDefine.getFileFetchOpt(AlbumDefine.ALBUM_ID_ALL, dev.networkId));
if (file.count > 0) {
peerInfo.coverUri = this.getThumbnailSafe(file.obj.uri);
peerInfo.count = file.count;
if (file.count > 0) {
peerInfo.coverUri = this.getThumbnailSafe(file.obj.uri);
peerInfo.count = file.count;
}
result.push(peerInfo);
}
result.push(peerInfo);
}
callback(result);
return new Promise((resolve) => { resolve(); });
callback(result);
});
}
getMediaItemCount(callback:any, param:any): void {}
getDataCount(callback:any, param:any): void {}
getDataById(id: any, deviceId? :any): any{}
getDataByName(name: string, albumInfo: any): any{}
}

View File

@ -14,14 +14,15 @@
*/
import {PeerInfo} from './PeerInfo'
import {Logger} from '../../../utils/Logger.ets'
import {AbsDataSource} from '../AbsDataSource.ets'
import { BroadCast } from '../../../utils/BroadCast.ets';
import { BrowserDataFactory } from '../interface/BrowserDataFactory.ets';
import { BrowserDataInterface } from '../interface/BrowserDataInterface';
import {Logger} from '../../../utils/Logger'
import {AbsDataSource} from '../AbsDataSource'
import { BroadCast } from '../../../utils/BroadCast';
import { BrowserDataFactory } from '../../../interface/BrowserDataFactory';
import { BrowserDataInterface } from '../../../interface/BrowserDataInterface';
import {BroadCastConstants} from '../../common/BroadCastConstants.ets'
import {BroadCastManager} from '../../common/BroadCastManager.ets'
import {BroadCastConstants} from '../../common/BroadCastConstants'
import {BroadCastManager} from '../../common/BroadCastManager'
import {Constants} from '../../common/Constants';
export class DistributedDataSource extends AbsDataSource {
logger: Logger = new Logger('DistributedDataSource');
@ -75,7 +76,7 @@ export class DistributedDataSource extends AbsDataSource {
}
onChange(mediaType: string) {
if (mediaType == 'device'|| mediaType == 'remote') {
if (mediaType == Constants.MEDIA_TYPE_DEVICE|| mediaType == Constants.MEDIA_TYPE_REMOTE) {
this.logger.info(`onChange: ${mediaType}`);
this.lastChangeTime = Date.now();
this.loadData();
@ -90,16 +91,16 @@ export class DistributedDataSource extends AbsDataSource {
private getDevicesStatus(devices, params) {
if (this.peerInfoList.length <= 0) {
params.push('online');
params.push(Constants.DEVICE_STATE_ONLINE);
params.push('');
}
for (let device of this.peerInfoList) {
if (!this.hasDevice(device.networkId, devices)) {
this.logger.debug(`offline: ${device.networkId}`);
params.push('offline');
params.push(Constants.DEVICE_STATE_OFFLINE);
}else{
params.push('changed');
params.push(Constants.DEVICE_STATE_CHANGE);
}
params.push(device.networkId);
}

View File

@ -14,7 +14,7 @@
*/
import {MediaObserverCallback} from './MediaObserverCallback';
import {Logger} from '../../../utils/Logger.ets'
import {Logger} from '../../../utils/Logger'
import {Constants} from '../../common/Constants'
import {MediaLibraryAccess} from '../../../access/MediaLibraryAccess'
@ -22,6 +22,12 @@ export class MediaObserver {
private logger: Logger = new Logger('MediaObserver');
callbacks: MediaObserverCallback[] = [];
private static readonly OBSERVER_IMAGE_CHANGE : string = 'imageChange'
private static readonly OBSERVER_VIDEO_CHANGE : string = 'videoChange'
private static readonly OBSERVER_DEVICE_CHANGE : string = 'deviceChange'
private static readonly OBSERVER_ALBUM_CHANGE : string = 'albumChange'
private static readonly OBSERVER_REMOTE_FILE_CHANGE : string = 'remoteFileChange'
static getInstance(): MediaObserver {
if (AppStorage.Get(Constants.APP_KEY_MENU_MEDIA_OBSERVER) == null) {
AppStorage.SetOrCreate(Constants.APP_KEY_MENU_MEDIA_OBSERVER, new MediaObserver());
@ -45,25 +51,25 @@ export class MediaObserver {
if (this.callbacks.length == 1) {
this.logger.info('registerObserver register media');
MediaLibraryAccess.getMediaLibrary().on('imageChange', () => {
MediaLibraryAccess.getInstance().getMediaLibrary().on(MediaObserver.OBSERVER_IMAGE_CHANGE, () => {
this.logger.info('registerObserver on image');
this.sendNotify('image');
this.sendNotify(Constants.MEDIA_TYPE_IMAGE);
})
MediaLibraryAccess.getMediaLibrary().on('videoChange', () => {
MediaLibraryAccess.getInstance().getMediaLibrary().on(MediaObserver.OBSERVER_VIDEO_CHANGE, () => {
this.logger.info('registerObserver on video');
this.sendNotify('video');
this.sendNotify(Constants.MEDIA_TYPE_VIDEO);
})
MediaLibraryAccess.getMediaLibrary().on('deviceChange', () => {
MediaLibraryAccess.getInstance().getMediaLibrary().on(MediaObserver.OBSERVER_DEVICE_CHANGE, () => {
this.logger.info('registerObserver on device');
this.sendNotify('device');
this.sendNotify(Constants.MEDIA_TYPE_DEVICE);
})
MediaLibraryAccess.getMediaLibrary().on('albumChange', () => {
MediaLibraryAccess.getInstance().getMediaLibrary().on(MediaObserver.OBSERVER_ALBUM_CHANGE, () => {
this.logger.info('registerObserver on album');
this.sendNotify('album');
this.sendNotify(Constants.MEDIA_TYPE_ALBUM);
})
MediaLibraryAccess.getMediaLibrary().on('remoteFileChange', () => {
MediaLibraryAccess.getInstance().getMediaLibrary().on(MediaObserver.OBSERVER_REMOTE_FILE_CHANGE, () => {
this.logger.info('registerObserver on remoteFile');
this.sendNotify('remote');
this.sendNotify(Constants.MEDIA_TYPE_REMOTE);
})
}
}

View File

@ -1,49 +0,0 @@
/*
* 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 {OperationImpl} from './OperationImpl'
import {Logger} from '../../../utils/Logger.ets'
import {MediaLibraryAccess} from '../../../access/MediaLibraryAccess.ets'
import {AlbumDefine} from '../AlbumDefine.ets'
import { BroadCastConstants } from '../../common/BroadCastConstants.ets';
import { BroadCastManager } from '../../common/BroadCastManager.ets'
import { UiUtil } from '../../../utils/UiUtil.ets'
export class AlbumOperationImpl extends OperationImpl {
logger: Logger = new Logger('AlbumOperationImpl');
name: Resource;
constructor() {
super()
}
async rename(oldName:any, newName:any) {
try{
let targetAlbum = await MediaLibraryAccess.getAlbums(AlbumDefine.getAlbumFetchOpt(newName));
if (targetAlbum.length > 0) {
UiUtil.showToast($r('app.string.name_already_use'));
return;
}
let sourceAlbum = await MediaLibraryAccess.getAlbums(AlbumDefine.getAlbumFetchOpt(oldName));
this.logger.debug(`result length:${sourceAlbum.length} old Album name:${sourceAlbum[0].albumName}`);
sourceAlbum[0].albumName = newName;
await sourceAlbum[0].commitModify();
} catch (err) {
this.logger.error(`rename ex: ${err}`);
}
}
}

View File

@ -1,68 +0,0 @@
/*
* 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 {Logger} from '../../../utils/Logger'
import {MenuOperationCallback} from './MenuOperationCallback'
import MediaLib from '@ohos.multimedia.mediaLibrary';
export class MenuOperationUtil {
// logger
static logger: Logger = new Logger('MenuOperationUtil');
static requestFavorite(uris: string[], value: boolean, callback?: MenuOperationCallback): void {
if (uris == null) {
this.logger.error('setFavorite with empty uris');
return;
}
this.logger.debug(`setFavorite size: ${uris.length} value: ${value}`);
MediaLib.getMediaLibrary().requestFavorite(uris, value, (err, data) => {
if (err) {
this.logger.error(`requestFavorite error: ${JSON.stringify(err)}`);
if (callback != null) {
callback.onError();
}
return;
}
this.logger.debug(`requestFavorite data: ${JSON.stringify(data)}`);
if (callback != null) {
callback.onCompleted();
}
});
}
static requestDelete(uris: string[], callback?: MenuOperationCallback): void {
if (uris == null) {
this.logger.error('requestDelete with empty uris');
return;
}
this.logger.debug(`requestDelete size: ${uris.length}`);
MediaLib.getMediaLibrary().commitDeletion(uris, (err, data) => {
if (err) {
this.logger.error(`requestDelete error: ${JSON.stringify(err)}`);
if (callback != null) {
callback.onError();
}
return;
}
this.logger.debug(`requestDelete data: ${JSON.stringify(data)}`);
if (callback != null) {
callback.onCompleted();
}
});
}
}

View File

@ -1,359 +0,0 @@
/*
* 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 {BrowserOperationInterface} from '../interface/BrowserOperationInterface'
import {Logger} from '../../../utils/Logger.ets'
import {MediaLibraryAccess} from '../../../access/MediaLibraryAccess.ets';
import fileio from '@ohos.fileio';
import {AlbumDefine} from '../AlbumDefine.ets'
export class OperationImpl implements BrowserOperationInterface {
logger: Logger = new Logger('OperationImpl');
async favor(id, isFavor) {
this.logger.info('favor');
try {
let fileAsset = await this.getFileAssetById(id);
fileAsset.favorite(isFavor);
return true;
} catch(e) {
this.logger.info(`favor error ${e}`);
return false;
}
}
delete(uri: string, callback): void {
if (uri == null) {
this.logger.error('requestDelete with empty uri');
return;
}
this.logger.debug(`requestDelete uri: ${uri}`);
MediaLibraryAccess.deleteAsset(uri, callback);
}
async move(uri: string, albumName: string, callback, isReplace: boolean, replaceUri?: string) {
this.logger.info('move start');
let lastIndex = uri.lastIndexOf('/');
let id = uri.substring(lastIndex + 1, uri.length);
let fileAsset = await this.getFileAssetById(id);
if (isReplace) {
let delCallback = {
onCompleted: () => {
this.logger.info('delete completed');
let path = this.getPathByMediaTypeAndAlbumName(AlbumDefine.getAlbumPath(albumName));
fileAsset.relativePath = path;
this.logger.info(`move commitModify start ${path}`);
fileAsset.commitModify().then(() => {
this.logger.info('move get result finish');
callback && callback.onCompleted();
}).catch((err) => {
this.logger.error(`move replace error msg: ${err}`);
});
},
onError: () => {
this.logger.error('move replace error');
callback && callback.onError();
},
};
MediaLibraryAccess.deleteAsset(replaceUri, delCallback);
} else {
let path = this.getPathByMediaTypeAndAlbumName(AlbumDefine.getAlbumPath(albumName));
fileAsset.relativePath = path;
this.logger.debug(`move commitModify start ${path}`);
try {
await fileAsset.commitModify();
this.logger.info('move get result');
callback && callback.onCompleted();
} catch(err) {
this.logger.error(`move error msg: ${err}`);
callback && callback.onError();
}
}
}
getPathByMediaTypeAndAlbumName(albumName: string): string {
let path = '';
let publicPath = '';
publicPath = globalThis.__MediaLibraryAccess_PUBLIC_PATH_IMAGE
if (albumName != '') {
path = `${publicPath}${albumName}/`
}
this.logger.info(`getPathByMediaTypeAndAlbumName path: ${path}`);
return path;
}
async getExistTargetInTargetAlbum(uri: string, albumName: string, deviceId?) {
this.logger.debug('isExistInTargetAlbum start');
let numId = this.getIdByUri(uri)
let fileAsset = await this.getFileAssetById(numId, deviceId);
let targetAsset = await this.getFileAsset(fileAsset, albumName);
if (targetAsset == null || targetAsset == undefined) {
this.logger.debug('targetAsset is null');
return null;
}
this.logger.debug('isExistInTargetAlbum true');
return {fileAsset: fileAsset, targetAsset: targetAsset};
}
async hasSameNameAsset(numId: number, name: string) {
this.logger.debug('isExistInTargetAlbum start');
let fileAsset = await this.getFileAssetById(numId);
let displayName = fileAsset.displayName;
let index = displayName.lastIndexOf('.');
displayName = name + displayName.slice(index);
let targetAsset;
let fileAssetList = await MediaLibraryAccess.getAllObject(AlbumDefine.getFileFetchOptByName(displayName));
this.logger.debug(`isExistInTargetAlbum fileAssetList count: ${fileAssetList.length}`);
for (let item of fileAssetList) {
if (fileAsset.relativePath == item.relativePath) {
this.logger.debug(`isExistInTargetAlbum has same name`);
targetAsset = item;
break;
}
}
if (targetAsset == null || targetAsset == undefined) {
this.logger.debug('targetAsset is null');
return false;
}
this.logger.debug('isExistInTargetAlbum true');
return true;
}
async getFileAsset(fileAsset: any, albumName: string) {
this.logger.debug('getFileAsset start');
let dataList = await MediaLibraryAccess.getEntityAlbumObject(AlbumDefine.getAlbumFetchOpt(albumName),
AlbumDefine.getFileFetchOptByName(fileAsset.displayName));
if (dataList != null) {
if (dataList.length > 0) {
return dataList[0];
} else {
this.logger.info('fileAsset is null');
return null;
}
}
this.logger.debug('getFileAsset end');
return null;
}
async getTargetFileAsset(fileAsset: any, albumName: string, isReplace: boolean, hasSame?: boolean) {
this.logger.debug(`getTargetFileAsset start isReplace ${isReplace}`);
if (isReplace) {
return await this.getFileAsset(fileAsset, albumName);
} else {
let showPath = this.getPathByMediaTypeAndAlbumName(AlbumDefine.getAlbumPath(albumName));
let displayName = fileAsset.displayName;
let index = displayName.lastIndexOf('.');
displayName = `${displayName.slice(0, index)}${new Date().getTime()}${displayName.slice(index)}`;
let targetAsset = await MediaLibraryAccess.createAsset(fileAsset.mediaType,
hasSame ? displayName : fileAsset.displayName, showPath);
this.logger.debug('getTargetFileAsset end');
return targetAsset;
}
}
async readAndWriteData(srcFd: number, targetFd: number) {
this.logger.debug('readAndWriteData start!')
let stat = await fileio.fstat(srcFd);
this.logger.debug(`readAndWriteData read stat.size ${stat.size}`)
if (stat.size == 0) {
return;
}
let step = 10000000;
let last = stat.size % step;
let count = (stat.size - last)/step;
if (last > 0) {
count = count + 1;
}
this.logger.debug(`readAndWriteData read count ${count} last ${last}`)
for (let i = 0; i < count; i++) {
let rwSize = 0;
if (i == (count - 1)) {
rwSize = last;
} else {
rwSize = step;
}
let buf = new ArrayBuffer(rwSize);
let readOptions = {
offset: 0,
length: rwSize,
position: i * step
}
await fileio.read(srcFd, buf, readOptions);
let writeOptions = {
offset: 0,
length: rwSize,
position: i * step,
encoding: 'utf-8'
}
await fileio.write(targetFd, buf, writeOptions);
}
this.logger.debug('readAndWriteData end!')
}
async copy(uri: string, albumName: string, callback: any, isReplace: boolean, deviceId?, hasSame?) {
this.logger.debug(`copy start ${JSON.stringify(uri)}`);
if (callback == null || callback == undefined) {
this.logger.debug('create callback is null or undefined');
return;
}
try {
let numId = this.getIdByUri(uri);
let fileAsset = await this.getFileAssetById(numId, deviceId);
if (fileAsset == null || fileAsset == undefined) {
this.logger.error('Failed to get fileAsset');
callback.onError();
return;
}
let fd = await MediaLibraryAccess.openAsset('R', fileAsset);
if (fd <= 0) {
this.logger.error('fd is invalid');
callback.onError();
return;
}
let targetAsset = await this.getTargetFileAsset(fileAsset, albumName, isReplace, hasSame)
if (targetAsset == null || targetAsset == undefined) {
this.logger.error('Failed to get targetAsset');
callback.onError();
return;
}
let targetFd = await MediaLibraryAccess.openAsset('RW', targetAsset);
if (targetFd <= 0) {
this.logger.error('targetFd is invalid');
callback.onError();
return;
}
await this.readAndWriteData(fd, targetFd);
await fileAsset.close(fd);
await targetAsset.close(targetFd);
} catch (error) {
this.logger.error(`create error: ${error}`);
callback.onError();
return;
}
callback.onCompleted();
this.logger.debug('copy end')
}
rename(oldName:any, newName:any): void {}
remark(): void {}
async trash(uri: string, callback: any) {
this.logger.debug(`trash start ${JSON.stringify(uri)}`);
if (callback == null || callback == undefined) {
this.logger.debug('trash callback is null or undefined');
return;
}
try{
let numId = this.getIdByUri(uri);
let fileAsset = await this.getFileAssetById(numId);
if (fileAsset == null || fileAsset == undefined) {
this.logger.error('Failed to get fileAsset');
callback.onError();
return;
}
await MediaLibraryAccess.trashAsset(true, fileAsset);
this.logger.debug('trash end');
callback.onCompleted();
} catch (error) {
this.logger.error(`trash error: ${error}`);
callback.onError();
return;
}
}
async recover(uri: string, callback: any) {
this.logger.debug(`recover start ${JSON.stringify(uri)}`);
if (callback == null || callback == undefined) {
this.logger.debug('recover callback is null or undefined');
return;
}
try{
let numId = this.getIdByUri(uri);
let fileAsset = await MediaLibraryAccess.getTrashObject(AlbumDefine.getFileFetchOpt(numId));
if (fileAsset[0] == null || fileAsset[0] == undefined) {
this.logger.error('Failed to get fileAsset');
callback.onError();
return;
}
await MediaLibraryAccess.trashAsset(false, fileAsset[0]);
this.logger.debug('recover end');
callback.onCompleted();
} catch (error) {
this.logger.error(`create error: ${error}`);
callback.onError();
return;
}
}
async renameSinglePhoto(id, name) {
this.logger.info('renameSinglePhoto start');
let fileAsset = await this.getFileAssetById(id);
fileAsset.title = name;
let displayName = fileAsset.displayName;
let index = displayName.lastIndexOf('.');
displayName = name + displayName.slice(index);
fileAsset.displayName = displayName;
this.logger.info(`renameSinglePhoto title: ${name}, displayName: ${displayName}`);
await fileAsset.commitModify();
fileAsset = await this.getFileAssetById(id);
return [fileAsset.title, fileAsset.displayName];
}
getIdByUri(uri:string): number {
let srcIndex = uri.lastIndexOf('/');
let srcEnd = uri.length;
let srcId = uri.substring(srcIndex + 1, srcEnd);
let numId = new Number(srcId);
this.logger.info(`getIdByUri numId: ${numId}`);
return numId.valueOf();
}
async changeOrientation(id, orientation) {
this.logger.info('changeOrientation start');
let fileAsset = await this.getFileAssetById(id);
fileAsset.orientation = orientation;
this.logger.info('changeOrientation commitModify start');
await fileAsset.commitModify();
this.logger.info('changeOrientation finish');
}
async getFileAssetById(id, deviceId?) {
this.logger.info('getFileAssetById');
try {
let result = await MediaLibraryAccess.getFirstObject(AlbumDefine.getFileFetchOpt(id, deviceId));
if (result == null) {
this.logger.info('getFileAssetByUri fail');
return null;
}
return result.obj;
} catch (error) {
this.logger.error('getFileAssetById error');
return null;
}
}
}

View File

@ -74,6 +74,12 @@ export class Constants {
// delete photo
static readonly DELETE = 'single_photo_delete';
// photo show state
static readonly PHOTO_SHOW_STATE = 'single_photo_show_state';
// set swiper can swipe
static readonly SET_DISABLE_SWIPE = 'set_disable_swipe';
// Scale lower limit
static readonly COMPONENT_SCALE_FLOOR = 0.5;
@ -111,4 +117,6 @@ export class Constants {
static readonly NUMBER_3 = 3;
static readonly NUMBER_12 = 12;
static readonly NUMBER_13 = 13;
static readonly DEFAULT_TRANSITION_ID: string = 'default_id';
}

View File

@ -14,13 +14,13 @@
*/
import Matrix4 from '@ohos.matrix4'
import {MediaItem} from './MediaItem.ets'
import {Logger} from '../../../utils/Logger.ets'
import {MediaItem} from './MediaItem'
import {Logger} from '../../../utils/Logger'
import {BroadCast} from '../../../utils/BroadCast'
import {MathUtil} from '../../../utils/MathUtil'
import {Constants as PhotoConstants} from './Constants.ets'
import {Constants as PhotoConstants} from './Constants'
import {ScreenManager} from '../../common/ScreenManager'
import {Constants} from './Constants.ets'
import {Constants} from './Constants'
export class EventPipeline {
// logger
@ -97,16 +97,16 @@ export class EventPipeline {
constructor(broadCastParam: BroadCast, item: MediaItem) {
this.broadCast = broadCastParam;
this.item = item;
this.width = this.item.width == 0 ? Constants.DEFAULT_SIZE : this.item.width;
this.height = this.item.height == 0 ? Constants.DEFAULT_SIZE : this.item.height;
this.width = this.item.imgWidth == 0 ? Constants.DEFAULT_SIZE : this.item.imgWidth;
this.height = this.item.imgHeight == 0 ? Constants.DEFAULT_SIZE : this.item.imgHeight;
this.orientation = this.item.orientation || 0;
this.evaluateScales();
}
onDataChanged(item: MediaItem) {
this.item = item;
this.width = this.item.width == 0 ? Constants.DEFAULT_SIZE : this.item.width;
this.height = this.item.height == 0 ? Constants.DEFAULT_SIZE : this.item.height;
this.width = this.item.imgWidth == 0 ? Constants.DEFAULT_SIZE : this.item.imgWidth;
this.height = this.item.imgHeight == 0 ? Constants.DEFAULT_SIZE : this.item.imgHeight;
this.orientation = this.item.orientation || 0;
this.evaluateScales();
}
@ -167,10 +167,7 @@ export class EventPipeline {
} else {
direction = PanDirection.Vertical;
}
this.logger.debug(`emitDirectionChange reaches: ${[this.hasReachLeft, this.hasReachRight]}, scale ${scale}, direction: ${direction}`);
if (this.isExiting) {
return;
}
if ((this.orientation == Constants.ROTATE_ONCE || this.orientation == Constants.ROTATE_THRICE) && isEnlarged) {
if (!this.hasReachTop && !this.hasReachBottom) {
direction = PanDirection.All;
@ -190,17 +187,25 @@ export class EventPipeline {
direction = PanDirection.Vertical;
}
}
this.logger.info(`emitDirectionChange reaches: ${[this.hasReachLeft, this.hasReachRight, this.hasReachTop, this.hasReachBottom]}, scale ${scale}, direction: ${direction}`);
if (this.isExiting) {
return;
}
if (direction == PanDirection.Vertical || direction == (PanDirection.Vertical | PanDirection.Left) ||
direction == (PanDirection.Vertical | PanDirection.Right)) {
this.broadCast.emit(PhotoConstants.SET_DISABLE_SWIPE, [false]);
} else {
this.broadCast.emit(PhotoConstants.SET_DISABLE_SWIPE, [true]);
}
this.broadCast.emit(PhotoConstants.DIRECTION_CHANGE + this.item.uri, [direction]);
}
private evaluateOffset(): [number, number] {
this.logger.debug(`evaluateOffset lastOffset: ${this.lastOffset}, offset: ${this.offset}`);
this.logger.info(`evaluateOffset lastOffset: ${this.lastOffset}, offset: ${this.offset}`);
let centerX = (this.center[0] - PhotoConstants.CENTER_DEFAULT) * this.componentWidth * (this.defaultScale - this.scale) * this.lastScale;
let centerY = (this.center[1] - PhotoConstants.CENTER_DEFAULT) * this.componentHeight * (this.defaultScale - this.scale) * this.lastScale;
if (this.orientation == Constants.ROTATE_ONCE || this.orientation == Constants.ROTATE_THRICE) {
centerX = (this.center[0] - PhotoConstants.CENTER_DEFAULT) * this.componentHeight * (this.defaultScale - this.scale) * this.lastScale;
centerY = (this.center[1] - PhotoConstants.CENTER_DEFAULT) * this.componentWidth * (this.defaultScale - this.scale) * this.lastScale;
}
let offsetX = this.lastOffset[0] + this.offset[0] + centerX;
let offsetY = this.lastOffset[1] + this.offset[1] + centerY;
this.logger.debug(`evaluateOffset offsetX: ${offsetX}, offsetY: ${offsetY}`);
@ -252,7 +257,7 @@ export class EventPipeline {
})
.copy();
this.logger.debug(`emitTouchEvent lastOffset: ${this.lastOffset}, offset: ${this.offset},\
center: ${this.center}, scale: ${[this.lastScale, this.scale]}, matrix: ${matrix.matrix4x4}`);
center: ${this.center}, scale: ${[this.lastScale, this.scale]}`);
this.broadCast.emit(PhotoConstants.TOUCH_EVENT + this.item.uri, [matrix]);
this.evaluateBounds();
}
@ -305,16 +310,13 @@ export class EventPipeline {
private evaluateImgDisplaySize(): [number, number] {
let screenScale = 1;
if (this.orientation == Constants.ROTATE_ONCE || this.orientation == Constants.ROTATE_THRICE) {
let widthScale = this.componentWidth / this.item.height;
let heightScale = this.componentHeight / this.item.width;
screenScale = widthScale > heightScale ? heightScale : widthScale;
} else {
let widthScale = this.componentWidth / this.item.width;
let heightScale = this.componentHeight / this.item.height;
screenScale = widthScale > heightScale ? heightScale : widthScale;
}
let widthScale = this.componentWidth / this.item.imgWidth;
let heightScale = this.componentHeight / this.item.imgHeight;
screenScale = widthScale > heightScale ? heightScale : widthScale;
let scale = this.lastScale * this.scale * screenScale;
if (this.orientation == Constants.ROTATE_ONCE || this.orientation == Constants.ROTATE_THRICE) {
scale = this.lastScale * this.scale;
}
let imgDisplayWidth = 0;
let imgDisplayHeight = 0;
imgDisplayWidth = this.width * scale;
@ -381,12 +383,12 @@ export class EventPipeline {
let result: [number, number, number, number] = [0, 0, 0, 0];
let screenScale = 1;
if (this.orientation == Constants.ROTATE_ONCE || this.orientation == Constants.ROTATE_THRICE) {
let widthScale = this.componentWidth / this.item.height;
let heightScale = this.componentHeight / this.item.width;
let widthScale = this.componentWidth / this.item.imgHeight;
let heightScale = this.componentHeight / this.item.imgWidth;
screenScale = widthScale > heightScale ? heightScale : widthScale;
} else {
let widthScale = this.componentWidth / this.item.width;
let heightScale = this.componentHeight / this.item.height;
let widthScale = this.componentWidth / this.item.imgWidth;
let heightScale = this.componentHeight / this.item.imgHeight;
screenScale = widthScale > heightScale ? heightScale : widthScale;
}
let left = (screenScale * scale * this.width - this.componentWidth) / PhotoConstants.NUMBER_2;
@ -657,7 +659,7 @@ export class EventPipeline {
y: offset[1]
})
.copy();
this.logger.debug(`evaluateAnimeMatrix scale:${scale}, center:${center}, result:${animationEndMatrix.matrix4x4}`);
this.logger.debug(`evaluateAnimeMatrix scale:${scale}, center:${center}`);
return animationEndMatrix;
}
@ -738,13 +740,15 @@ export class EventPipeline {
* @param animationEndMatrix Transformation matrix at end
*/
onAnimationEnd(animationEndMatrix: any): void{
this.logger.info(`onAnimationEnd: ${animationEndMatrix.matrix4x4}`);
this.lastScale = animationEndMatrix.matrix4x4[0];
this.scale = 1;
this.lastOffset = [animationEndMatrix.matrix4x4[PhotoConstants.NUMBER_12], animationEndMatrix.matrix4x4[PhotoConstants.NUMBER_13]];
this.offset = [0, 0];
this.evaluateBounds();
this.isInAnimation = false;
this.emitDirectionChange();
if (animationEndMatrix) {
this.logger.info(`onAnimationEnd: ${animationEndMatrix.matrix4x4}`);
this.lastScale = animationEndMatrix.matrix4x4[0];
this.scale = 1;
this.lastOffset = [animationEndMatrix.matrix4x4[PhotoConstants.NUMBER_12], animationEndMatrix.matrix4x4[PhotoConstants.NUMBER_13]];
this.offset = [0, 0];
this.evaluateBounds();
this.isInAnimation = false;
this.emitDirectionChange();
}
}
}

View File

@ -13,7 +13,7 @@
* limitations under the License.
*/
import {Logger} from '../../../utils/Logger.ets'
import {Logger} from '../../../utils/Logger'
import {Releasable} from '../../common/Releasable'
export class FifoCache <T extends Releasable> {

View File

@ -14,10 +14,10 @@
*/
import {AsyncCallback} from '../../common/AsyncCallback'
import {MediaItem} from './MediaItem.ets'
import {MediaDataSource} from './MediaDataSource.ets'
import {Logger} from '../../../utils/Logger.ets'
import {TraceControllerUtils} from '../../../utils/TraceControllerUtils.ets'
import {MediaItem} from './MediaItem'
import {MediaDataSource} from './MediaDataSource'
import {Logger} from '../../../utils/Logger'
import {TraceControllerUtils} from '../../../utils/TraceControllerUtils'
// Datasource requests media mediaItem callback
export class GetItemsCallback implements AsyncCallback<MediaItem[]> {

View File

@ -14,9 +14,9 @@
*/
import {AsyncCallback} from '../../common/AsyncCallback'
import {MediaDataSource} from './MediaDataSource.ets'
import {Logger} from '../../../utils/Logger.ets'
import {TraceControllerUtils} from '../../../utils/TraceControllerUtils.ets'
import {MediaDataSource} from './MediaDataSource'
import {Logger} from '../../../utils/Logger'
import {TraceControllerUtils} from '../../../utils/TraceControllerUtils'
// DataSource request media photo quantity callback
export class GetMediaCountCallback implements AsyncCallback<number> {

View File

@ -17,17 +17,17 @@ import {MediaItem} from './MediaItem'
import {AbsDataSource} from '../AbsDataSource'
import {GetItemsCallback} from './GetItemsCallback'
import {GetMediaCountCallback} from './GetMediaCountCallback'
import {Logger} from '../../../utils/Logger.ets'
import { BroadCastConstants } from '../../common/BroadCastConstants.ets';
import { BroadCast } from '../../../utils/BroadCast.ets';
import {BroadCastManager} from '../../common/BroadCastManager.ets'
import {Constants} from '../../common/Constants.ets'
import {Logger} from '../../../utils/Logger'
import { BroadCastConstants } from '../../common/BroadCastConstants';
import { BroadCast } from '../../../utils/BroadCast';
import {BroadCastManager} from '../../common/BroadCastManager'
import {Constants} from '../../common/Constants'
import {PendingTask} from './PendingTask'
import {PendingCondition} from './PendingCondition'
import {TraceControllerUtils} from '../../../utils/TraceControllerUtils.ets'
import {AlbumDefine} from '../AlbumDefine.ets'
import {BrowserDataFactory} from '../interface/BrowserDataFactory.ets'
import {BrowserDataInterface} from '../interface/BrowserDataInterface'
import {TraceControllerUtils} from '../../../utils/TraceControllerUtils'
import {AlbumDefine} from '../AlbumDefine'
import {BrowserDataFactory} from '../../../interface/BrowserDataFactory'
import {BrowserDataInterface} from '../../../interface/BrowserDataInterface'
export class MediaDataSource extends AbsDataSource {
// Number of first pictures loaded during initialization
@ -83,13 +83,17 @@ export class MediaDataSource extends AbsDataSource {
// Request time of the first batch of data
firstPatchDataRequestTime: number;
albumName: string = AlbumDefine.ALBUM_NAME_ALL;
albumId: string = AlbumDefine.ALBUM_ID_ALL;
deviceId: string = undefined;
isRefresh: boolean = false;
isEditSaveReload: boolean = false;
constructor(windowSize: number) {
super();
this.photoDataImpl = BrowserDataFactory.getFeature(BrowserDataFactory.TYPE_ALBUM);
this.photoDataImpl = BrowserDataFactory.getFeature(BrowserDataFactory.TYPE_PHOTO);
this.windowSize = windowSize;
this.activeEnd = windowSize;
this.items = new Array(windowSize);
@ -127,6 +131,16 @@ export class MediaDataSource extends AbsDataSource {
return Constants.NOT_FOUND;
}
// get DataIndex with item
getDataIndexById(id: number): number {
for (let i = 0; i < this.items.length; i++) {
if (this.items[i] != undefined && this.items[i].id == id) {
return i + this.activeStart;
}
}
return Constants.NOT_FOUND;
}
getMediaCount(): number {
return this.mediaCount;
}
@ -151,22 +165,21 @@ export class MediaDataSource extends AbsDataSource {
this.lastUpdateTime = this.firstPatchDataRequestTime;
let firstPatchDataCallback: any = {
callback: (assets: MediaItem[]) => {
TraceControllerUtils.finishTraceWithTaskId('getMediaItems', this.firstPatchDataRequestTime);
this.logger.info(`took ${(Date.now() - this.firstPatchDataRequestTime)}\
milliseconds to load first batch: ${(assets == null ? 0 : assets.length)}`);
this.updateMediaData(this.firstPatchDataRequestTime, start, assets);
this.broadCast && this.broadCast.emit(Constants.FIRST_PATCH_LOAD_FINISH, []);
let secondPatchDataCallback: GetItemsCallback = new GetItemsCallback(this, limit);
this.photoDataImpl.getData(secondPatchDataCallback, {
name: this.albumName,
id: this.albumId,
start: limit,
count: this.windowSize - limit,
deviceId: this.deviceId
});
}
};
TraceControllerUtils.startTraceWithTaskId('getMediaItems', this.firstPatchDataRequestTime);
this.photoDataImpl.getData(firstPatchDataCallback,
{name: this.albumName, start: start, count: limit, deviceId: this.deviceId});
{id: this.albumId, start: start, count: limit, deviceId: this.deviceId});
this.loadData();
}
@ -175,7 +188,7 @@ export class MediaDataSource extends AbsDataSource {
this.logger.info(`loadData`);
let initCountCallback: GetMediaCountCallback = new GetMediaCountCallback(this);
this.photoDataImpl.getMediaItemCount(initCountCallback, { name: this.albumName, deviceId: this.deviceId });
this.photoDataImpl.getDataCount(initCountCallback, { id: this.albumId, deviceId: this.deviceId });
}
// update media count
@ -239,16 +252,18 @@ export class MediaDataSource extends AbsDataSource {
if (this.mediaCount == 0) {
this.hasNewChange = false;
this.onDataReloaded();
} else {
} else if(this.isEditSaveReload || this.isCountChanged || this.isRefresh) {
// dirty data, need to get data again
this.logger.info('dirty data, need to get data again');
let callback: GetItemsCallback = new GetItemsCallback(this, this.activeStart);
this.photoDataImpl.getData(callback, {
name: this.albumName,
id: this.albumId,
start: this.activeStart,
count: this.windowSize,
deviceId: this.deviceId
});
} else {
this.hasNewChange = false;
}
}
this.emitCountUpdateCallbacks();
@ -327,8 +342,9 @@ export class MediaDataSource extends AbsDataSource {
this.logger.debug(`updateMediaData ${this.layoutIndexes[i]}`);
// !this.isCountChanged && this.onDataChanged(this.layoutIndexes[i]);
}
if (this.isCountChanged) {
if (this.photosBroadCast && this.isCountReduced) {
if (this.isCountChanged || this.isRefresh) {
if (this.photosBroadCast && (this.isCountReduced || this.isRefresh)) {
this.photosBroadCast.emit(BroadCastConstants.ON_DATA_RELOADED, [])
} else if (this.broadCast) {
this.broadCast.emit(BroadCastConstants.ON_DATA_RELOADED, [])
@ -338,13 +354,19 @@ export class MediaDataSource extends AbsDataSource {
this.isCountChanged = false;
this.isCountReduced = false;
this.isRefresh = false;
} else {
for (let i = fromIndex; i < endIndex; i++) {
this.onDataChanged(this.layoutIndexes[i]);
}
}
if (this.isEditSaveReload) {
this.photosBroadCast && this.photosBroadCast.emit(BroadCastConstants.ON_DATA_RELOADED_WITH_EDIT, []);
} else {
this.notifyDataLoadingFinished();
}
TraceControllerUtils.finishTraceWithTaskId('updateMediaData', requestTime);
this.notifyDataLoadingFinished();
}
// Update sliding window
@ -374,22 +396,20 @@ export class MediaDataSource extends AbsDataSource {
this.lastUpdateTime = this.firstPatchDataRequestTime;
let firstPatchDataCallback: any = {
callback: (assets: MediaItem[]) => {
TraceControllerUtils.finishTraceWithTaskId('getMediaItems', this.firstPatchDataRequestTime);
this.logger.info(`took ${(Date.now() - this.firstPatchDataRequestTime)}\
milliseconds to load first batch: ${(assets == null ? 0 : assets.length)}`);
this.updateMediaData(this.firstPatchDataRequestTime, start, assets);
let secondPatchDataCallback: GetItemsCallback = new GetItemsCallback(this, newActiveStart);
this.photoDataImpl.getData(secondPatchDataCallback, {
name: this.albumName,
id: this.albumId,
start: newActiveStart,
count: this.windowSize,
deviceId: this.deviceId
});
}
};
TraceControllerUtils.startTraceWithTaskId('getMediaItems', this.firstPatchDataRequestTime);
this.photoDataImpl.getData(firstPatchDataCallback,
{name: this.albumName, start: start, count: limit, deviceId: this.deviceId });
{id: this.albumId, start: start, count: limit, deviceId: this.deviceId });
}
if (newActiveEnd < this.activeEnd && newActiveEnd > this.activeStart) {
@ -408,7 +428,7 @@ export class MediaDataSource extends AbsDataSource {
this.logger.info(`trigger data fetch start: ${requestStart}, count: ${requestCount}`);
let callback: GetItemsCallback = new GetItemsCallback(this, requestStart);
this.photoDataImpl.getData(callback,
{name: this.albumName, start: requestStart, count: requestCount, deviceId: this.deviceId });
{id: this.albumId, start: requestStart, count: requestCount, deviceId: this.deviceId });
}
private getWindowActiveStart(dataIndex: number, windowCenter: number): number{
@ -465,9 +485,9 @@ export class MediaDataSource extends AbsDataSource {
return result;
}
setAlbumName(name: string) {
this.logger.info(`setAlbumName: ${name}`)
this.albumName = name;
setAlbumId(id: string) {
this.logger.info(`setAlbumId: ${id}`)
this.albumId = id;
}
setBroadCast(broadCastParam: BroadCast) {
@ -490,6 +510,13 @@ export class MediaDataSource extends AbsDataSource {
} else {
this.onInActive();
}
} else if (transition == Constants.PHOTO_TRANSITION_EDIT) {
if (isActive) {
this.isEditSaveReload = true;
this.onActive();
} else {
this.isEditSaveReload = false;
}
}
}
@ -503,39 +530,26 @@ export class MediaDataSource extends AbsDataSource {
return -1;
}
deleteData(uris: string[]): void {
try {
this.loadData();
} catch(err) {
this.logger.info(`deleteData items err: ${err} `);
}
this.logger.info(`deleteData items ${this.items.length} `);
}
getIndexByUri(uri: string): number {
for (let index = 0; index < this.items.length; index++) {
if (uri == this.items[index].uri) {
return index;
}
}
return -1;
}
getPositionByIndex(index: number): number {
return index;
}
onChange(mediaType: string) {
if(this.deviceId == '' || this.deviceId == undefined) {
if (mediaType == 'image' || mediaType == 'video' || mediaType == 'album') {
if (mediaType == Constants.MEDIA_TYPE_IMAGE || mediaType == Constants.MEDIA_TYPE_VIDEO || mediaType == Constants.MEDIA_TYPE_ALBUM) {
this.logger.debug(`local onChange ${mediaType}`);
super.onChange(mediaType);
}
} else {
if (mediaType == 'remote') {
if (mediaType == Constants.MEDIA_TYPE_REMOTE) {
this.logger.debug(`remote onChange`);
this.switchRefreshOn()
super.onChange(mediaType);
}
}
}
switchRefreshOn() {
this.isRefresh = true
}
}

View File

@ -13,6 +13,8 @@
* limitations under the License.
*/
import { DateUtil } from '../../../utils/DateUtil';
import { Constants } from '../../common/Constants'
export class MediaItem {
index?: number;
id: number;
@ -27,6 +29,8 @@ export class MediaItem {
orientation: number;
width: number;
height: number;
imgWidth: number;
imgHeight: number;
isFavor: boolean;
type: string;
displayName: string;
@ -45,15 +49,17 @@ export class MediaItem {
this.title = data.title;
this.size = data.size;
this.dateTaken = data.dateAdded * DateUtil.MILLISECONDS_PER_SECOND; // TODO dateTaken is not supported, use dateAdded
this.dateModified = data.dateModified * 1000;
this.dateModified = data.dateModified * DateUtil.MILLISECONDS_PER_SECOND;
this.orientation = data.orientation;
if (this.orientation == 90 || this.orientation == 270) {
if (this.orientation == Constants.ANGLE_90 || this.orientation == Constants.ANGLE_270) {
this.width = data.height;
this.height = data.width;
} else {
this.width = data.width;
this.height = data.height;
}
this.imgWidth = this.width;
this.imgHeight = this.height;
this.displayName = data.displayName;
this.path = data.relativePath;
}

View File

@ -0,0 +1,157 @@
/*
* 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 {BrowserOperationInterface} from '../../../interface/BrowserOperationInterface'
import {Logger} from '../../../utils/Logger'
import {MediaLibraryAccess} from '../../../access/MediaLibraryAccess';
import fileio from '@ohos.fileio';
import {AlbumDefine} from '../AlbumDefine'
import {StringUtil} from '../../../utils/StringUtil'
import {TraceControllerUtils} from '../../../utils/TraceControllerUtils';
export class OperationImpl implements BrowserOperationInterface {
logger: Logger = new Logger('OperationImpl');
async favor(id, isFavor) {
this.logger.info('favor');
try {
let fileAsset = (await MediaLibraryAccess.getInstance().getFirstObject(AlbumDefine.getFileFetchOptById(id))).obj
fileAsset.favorite(isFavor);
return true;
} catch(e) {
this.logger.error(`favor error ${e}`);
return false;
}
}
async delete(uri: string) {
await MediaLibraryAccess.getInstance().deleteAsset(uri);
}
async copy(source: any, target: any) {
this.logger.info(`copy start: src:${source.uri} target: ${target.uri}`);
TraceControllerUtils.startTrace('openAssetR')
let fd = await MediaLibraryAccess.getInstance().openAsset('R', source);
TraceControllerUtils.finishTrace('openAsset')
if (fd <= 0) {
throw 'fd is invalid'
return;
}
TraceControllerUtils.startTrace('openAssetRW')
let targetFd = await MediaLibraryAccess.getInstance().openAsset('RW', target);
TraceControllerUtils.finishTrace('openAssetRW')
if (targetFd <= 0) {
throw 'targetFd is invalid'
return;
}
TraceControllerUtils.startTrace('readAndWriteData')
await this.readAndWriteData(fd, targetFd);
TraceControllerUtils.finishTrace('readAndWriteData')
TraceControllerUtils.startTrace('sourceClose')
await source.close(fd);
TraceControllerUtils.finishTrace('sourceClose')
TraceControllerUtils.startTrace('targetClose')
await target.close(targetFd);
TraceControllerUtils.finishTrace('targetClose')
this.logger.debug('copy end')
}
async trash(uri: string, isTrash: boolean) {
this.logger.debug(`trash start ${JSON.stringify(uri)}`);
let fileId = StringUtil.getIdFromUri(uri);
let fileAsset;
if (isTrash) {
fileAsset = (await MediaLibraryAccess.getInstance().getFirstObject(AlbumDefine.getFileFetchOptById(fileId))).obj;
}else{
fileAsset = (await MediaLibraryAccess.getInstance().getTrashObject(AlbumDefine.getFileFetchOptById(fileId)))[0];
}
await MediaLibraryAccess.getInstance().trashAsset(isTrash, fileAsset);
this.logger.debug(`trash end: ${isTrash}`);
}
async create(param: any){
return await MediaLibraryAccess.getInstance().createAsset(param.mediaType, param.name, param.path);
}
async commitChanges(file){
await file.commitModify();
}
setName(source: any, name: string): void {
let displayName = source.displayName;
let index = displayName.lastIndexOf('.');
displayName = name + displayName.slice(index);
source.displayName = displayName;
source.title = name;
this.logger.info(`setName title: ${name}, displayName: ${displayName}`);
}
setOrientation(source: any, orientation: number): void {
source.orientation = orientation;
}
setRelativePath(source: any, relativePath: string): void {
source.relativePath = relativePath;
}
async readAndWriteData(srcFd: number, targetFd: number) {
this.logger.debug('readAndWriteData start!')
let stat = await fileio.fstat(srcFd);
this.logger.debug(`readAndWriteData read stat.size ${stat.size}`)
if (stat.size == 0) {
return;
}
let step = 10000000;
let last = stat.size % step;
let count = (stat.size - last)/step;
if (last > 0) {
count = count + 1;
}
this.logger.debug(`readAndWriteData read count ${count} last ${last}`)
for (let i = 0; i < count; i++) {
let rwSize = 0;
if (i == (count - 1)) {
rwSize = last;
} else {
rwSize = step;
}
let buf = new ArrayBuffer(rwSize);
let readOptions = {
offset: 0,
length: rwSize,
position: i * step
}
await fileio.read(srcFd, buf, readOptions);
let writeOptions = {
offset: 0,
length: rwSize,
position: i * step,
encoding: 'utf-8'
}
await fileio.write(targetFd, buf, writeOptions);
}
this.logger.debug('readAndWriteData end!')
}
}

View File

@ -13,11 +13,13 @@
* limitations under the License.
*/
import {AlbumDefine} from '../AlbumDefine.ets'
import {BrowserDataImpl} from '../BrowserDataImpl.ets'
import {Logger} from '../../../utils/Logger.ets'
import {AlbumDefine} from '../AlbumDefine'
import {BrowserDataImpl} from '../BrowserDataImpl'
import {Logger} from '../../../utils/Logger'
import {AsyncCallback} from '../../common/AsyncCallback'
import {MediaItem} from './MediaItem.ets'
import {MediaItem} from './MediaItem'
import {MediaLibraryAccess} from '../../../access/MediaLibraryAccess'
import {TraceControllerUtils} from '../../../utils/TraceControllerUtils';
export class PhotoDataImpl extends BrowserDataImpl {
logger: Logger = new Logger('PhotoDataImpl');
@ -27,7 +29,7 @@ export class PhotoDataImpl extends BrowserDataImpl {
super()
}
getData(callback: AsyncCallback<MediaItem[]>, param): Promise<void>{
getData(callback: AsyncCallback<MediaItem[]>, param): void{
this.logger.info(`getMediaItem start ${JSON.stringify(param)}`);
if (callback == null) {
this.logger.error('getMediaItem, param or callback is null, return!');
@ -36,7 +38,7 @@ export class PhotoDataImpl extends BrowserDataImpl {
// Querying MediaLibrary data
let mediaItemList: MediaItem[] = [];
this.getItems(param.name, param.start, param.count, param.deviceId).then(async (dataList) => {
this.getItems(param.id, param.start, param.count, param.deviceId).then((dataList) => {
this.logger.info(`getMediaItem coming`);
if (dataList != null) {
let promiseStatus: Array<Promise<boolean>> = []
@ -48,7 +50,9 @@ export class PhotoDataImpl extends BrowserDataImpl {
this.logger.error(`getItems error: ${err}`);
}
}
TraceControllerUtils.startTraceWithTaskId('getFavorInfo', dataList.length);
Promise.all(this.handlePromise(promiseStatus)).then((favor: any) => {
TraceControllerUtils.finishTraceWithTaskId('getFavorInfo', dataList.length);
for (let i = 0; i < promiseStatus.length; i++) {
try {
let item = dataList[i];
@ -78,29 +82,49 @@ export class PhotoDataImpl extends BrowserDataImpl {
(err) => ({status: 'failed', err})))
}
getMediaItemCount(callback: AsyncCallback<number>, param: any): void {
getDataCount(callback: AsyncCallback<number>, param: any): void {
this.logger.debug(`getMediaItemCount: ${JSON.stringify(param)}`);
this.getItemsCount(param.name, param.deviceId).then((count) => {
this.getItemsCount(param.id, param.deviceId).then((count) => {
this.logger.debug(`getMediaItemCount callback: ${count}`);
callback.callback(count);
});
}
async getObjectById(id, deviceId, isTrash: boolean = false) {
this.logger.debug(`getObjectById: ${id} deviceID: ${deviceId} isTrash: ${isTrash}`);
if (isTrash) {
return await this.getTrashObjectById(id);
} else {
let obj = await this.getFirstObject(AlbumDefine.getFileFetchOpt(id, deviceId));
if (obj == null) {
this.logger.error('getFirstObject fail!');
return null;
}
return obj.obj;
}
}
getThumbnail(sourceUri: string, size?) {
return this.getThumbnailSafe(sourceUri, size);
}
async getDataById(id: any, deviceId? :any){
this.logger.debug('getFileAssetById');
try {
let result = await MediaLibraryAccess.getInstance().getFirstObject(AlbumDefine.getFileFetchOptById(id, deviceId));
return result.obj;
} catch (error) {
this.logger.error('getFileAssetById error');
return null;
}
}
async getDataByName(name: string, albumInfo: any){
this.logger.debug('getFileByName');
let dataList;
if (albumInfo.id){
dataList = await MediaLibraryAccess.getInstance().getEntityAlbumObject(AlbumDefine.getAlbumFetchOpt(albumInfo.id),
AlbumDefine.getFileFetchOptByName(name))
}else{
dataList = await MediaLibraryAccess.getInstance().getAllObject(AlbumDefine.getFileFetchOptByName(name, albumInfo.relativePath))
}
if (dataList != null) {
if (dataList.length > 0) {
return dataList[0];
} else {
this.logger.info('fileAsset is null');
return null;
}
}
this.logger.debug('getFileAsset end');
return null;
}
}

View File

@ -13,33 +13,40 @@
* limitations under the License.
*/
import {Logger} from '../../../utils/Logger.ets'
import {MediaDataSource} from './MediaDataSource.ets'
import {Logger} from '../../../utils/Logger'
import {MediaDataSource} from './MediaDataSource'
import {LoadingListener} from '../LoadingListener'
import {BroadCast} from '../../../utils/BroadCast'
import {Constants as PhotoConstants} from './Constants'
import {MediaItem} from './MediaItem'
import {Constants} from '../../common/Constants.ets'
import {Constants} from '../../common/Constants'
import {PixelMapManager} from '../../common/PixelMapManager'
import {BrowserDataFactory} from '../interface/BrowserDataFactory.ets';
import {BrowserDataFactory} from '../../../interface/BrowserDataFactory';
import {AlbumDefine} from '../AlbumDefine'
import {BroadCastManager} from '../../common/BroadCastManager';
import {ImageUtil} from '../../../utils/ImageUtil';
import {ScreenManager} from '../../common/ScreenManager';
// DataSource
export class PhotoDataSource implements IDataSource, LoadingListener {
private logger: Logger = new Logger('PhotoDataSource');
protected logger: Logger = new Logger('PhotoDataSource');
private albumDataSource: MediaDataSource;
private broadCast: BroadCast;
private currentIndex = 0;
private pixelMapManager: PixelMapManager;
private appBroadCast: BroadCast = BroadCastManager.getInstance().getBroadCast();
// Data change listener
private listeners: DataChangeListener[] = [];
private albumName: string = 'Camera'
private albumId: string = AlbumDefine.ALBUM_ID_CAMERA
private deviceId: string = ''
private photoDataImpl;
protected photoDataImpl;
totalCount(): number {
let totalCount = this.albumDataSource.mediaCount;
this.logger.debug(`totalCount: ${totalCount}`);
if (totalCount > 0 && !this.albumDataSource.getRawData(0)) {
return 0;
}
return totalCount || 0;
}
@ -48,18 +55,22 @@ export class PhotoDataSource implements IDataSource, LoadingListener {
return this.albumDataSource.getDataIndex(item);
}
constructor(albumName?: string) {
this.logger.debug('bind onMessage');
this.pixelMapManager = PixelMapManager.getInstance();
if (albumName) {
this.albumName = albumName;
}
this.photoDataImpl = BrowserDataFactory.getFeature(BrowserDataFactory.TYPE_ALBUM);
getDataIndexById(id: number) {
return this.albumDataSource.getDataIndexById(id);
}
setAlbumName(albumName: string) {
this.albumName = albumName;
constructor(albumId?: string) {
this.logger.debug('bind onMessage');
this.pixelMapManager = PixelMapManager.getInstance();
if (albumId) {
this.albumId = albumId;
}
this.photoDataImpl = BrowserDataFactory.getFeature(BrowserDataFactory.TYPE_PHOTO);
}
setAlbumId(albumId: string) {
this.albumId = albumId;
}
setDeviceId(deviceId: string) {
@ -71,7 +82,7 @@ export class PhotoDataSource implements IDataSource, LoadingListener {
initData() {
let dataSource: MediaDataSource = new MediaDataSource(Constants.DEFAULT_SLIDING_WIN_SIZE);
dataSource.setAlbumName(this.albumName);
dataSource.setAlbumId(this.albumId);
dataSource.initData();
this.setAlbumDataSource(dataSource);
}
@ -81,9 +92,28 @@ export class PhotoDataSource implements IDataSource, LoadingListener {
this.logger.info(`getData index ${index}`);
this.albumDataSource.updateSlidingWindow(index);
let mediaItem: MediaItem = this.albumDataSource.getRawData(index);
if (mediaItem.height == 0 || mediaItem.width == 0) {
this.getDataById(mediaItem.id).then((result) => {
mediaItem = new MediaItem(result);
if (mediaItem.height == 0 || mediaItem.width == 0) {
return;
}
let index = this.albumDataSource.getIndexByMediaItem(mediaItem);
if (index != -1) {
this.albumDataSource.onDataChanged(index);
}
this.onDataChanged(index);
})
}
let orientation = mediaItem.orientation || 0;
let imgWidth = orientation == 0 || orientation == PhotoConstants.ROTATE_TWICE ? mediaItem.width : mediaItem.height;
let imgHeight = orientation == 0 || orientation == PhotoConstants.ROTATE_TWICE ? mediaItem.height : mediaItem.width;
let scale = this.generateSampleSize(imgWidth, imgHeight, index);
mediaItem.imgWidth = Math.ceil(mediaItem.width / scale);
mediaItem.imgHeight = Math.ceil(mediaItem.height / scale);
imgWidth = Math.ceil(imgWidth / scale);
imgHeight = Math.ceil(imgHeight / scale);
return {
data: mediaItem,
pos: index,
@ -166,12 +196,17 @@ export class PhotoDataSource implements IDataSource, LoadingListener {
})
}
async getDataById(id) {
return await this.photoDataImpl.getDataById(id);
}
public release(): void {
this.albumDataSource.releasePhotoBroadCast();
this.albumDataSource.removeLoadingListener(this);
// cancel the mediaLibrary listening of albumDataSource when the large image is destroyed.
// cannot cancel it in unregisterDataChangeListener
this.albumDataSource && this.albumDataSource.unregisterObserver();
this.broadCast = null;
}
getPositionByIndex(index: number): number {
@ -181,4 +216,23 @@ export class PhotoDataSource implements IDataSource, LoadingListener {
onChange(changeType) {
this.albumDataSource.onChange(changeType);
}
switchRefreshOn(){
this.albumDataSource.switchRefreshOn();
};
private generateSampleSize(imageWidth: number, imageHeight: number, index: number): number {
let width = ScreenManager.getInstance().getWinWidth();
let height = ScreenManager.getInstance().getWinHeight();
width = width == 0 ? ScreenManager.DEFAULT_WIDTH : width;
height = height == 0 ? ScreenManager.DEFAULT_HEIGHT : height;
let maxNumOfPixels
if (this.currentIndex == index) {
maxNumOfPixels = 2 * width * height;
} else {
maxNumOfPixels = width * height;
}
let minSide = Math.min(width, height);
return ImageUtil.computeSampleSize(imageWidth, imageHeight, minSide, maxNumOfPixels);
}
}

View File

@ -12,15 +12,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {BrowserDataImpl} from '../BrowserDataImpl.ets'
import {BrowserDataImpl} from '../BrowserDataImpl'
import {AsyncCallback} from '../../common/AsyncCallback'
import {AlbumDefine} from '../AlbumDefine'
import {TimelineData} from './TimelineData.ets'
import {DateUtil} from '../../../utils/DateUtil.ets';
import {TimelineData} from './TimelineData'
import {DateUtil} from '../../../utils/DateUtil';
import {MediaItem} from './MediaItem'
export class TimelineDataImpl extends BrowserDataImpl {
getData(callback: AsyncCallback<TimelineData[]>, param): Promise<void>{
getData(callback: AsyncCallback<TimelineData[]>, param): void{
this.logger.info(`loadGroupData start ${param}`);
if (callback == null) {
this.logger.info('loadGroupData with empty args');
@ -28,14 +28,13 @@ export class TimelineDataImpl extends BrowserDataImpl {
}
let groupDataList: TimelineData[] = [];
let mediaItemList: MediaItem[] = [];
let start: number = undefined;
let count: number = undefined;
if (param) {
start = param.start;
count = param.count;
}
this.getItems(AlbumDefine.ALBUM_NAME_ALL, start, count).then(async (dataList) => {
this.getItems(AlbumDefine.ALBUM_ID_ALL, start, count).then((dataList) => {
if (dataList != null) {
if (dataList.length) {
let groupCount = 1;
@ -57,17 +56,20 @@ export class TimelineDataImpl extends BrowserDataImpl {
let groupData = new TimelineData(startTime, endTime, groupCount);
groupDataList.push(groupData);
} else {
this.logger.error(`getGroupData item size: ${mediaItemList.length}`);
this.logger.error(`getGroupData item size: ${groupDataList.length}`);
}
}
callback.callback(groupDataList);
})
}
getMediaItemCount(callback: AsyncCallback<number>, param): void {
this.getItemsCount(param.name).then((count) => {
getDataCount(callback: AsyncCallback<number>, param): void {
this.getItemsCount(param.id).then((count) => {
this.logger.info(`getMediaItemCount callback: ${count}`);
callback.callback(count);
});
}
getDataById(id: any, deviceId? :any): any{}
getDataByName(name: string, albumInfo: any): any{}
}

View File

@ -0,0 +1,101 @@
/*
* 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 {Logger} from '../../../utils/Logger'
import {PhotoDataSource} from './PhotoDataSource';
import {MediaItem} from './MediaItem'
import {Constants as PhotoConstants} from './Constants'
import {MediaLibraryAccess} from '../../../access/MediaLibraryAccess';
import {ScreenManager} from '../../common/ScreenManager'
class InnerMediaItem extends MediaItem {
static readonly MEDIA_ABILITY = 'dataAbility';
isHttp: boolean;
constructor(uri: string) {
super({
id: 0,
mediaType: MediaLibraryAccess.MEDIA_TYPE_IMAGE,
uri: uri,
duration:0,
title:"",
size: PhotoConstants.DEFAULT_SIZE,
thumbnail: uri,
dateTaken: 0,
dateModified: 0,
orientation: 0,
width: vp2px(ScreenManager.getInstance().getWinWidth()),
height: vp2px(ScreenManager.getInstance().getWinHeight()),
isFavor: false,
type: "",
displayName: "",
filePath: uri,
path: uri
})
this.isHttp = !uri.startsWith(InnerMediaItem.MEDIA_ABILITY);
}
}
export class UriDataSource extends PhotoDataSource {
protected logger: Logger = new Logger('UriDataSource');
private mItems: InnerMediaItem[] = [];
private static readonly URL_TAG = '-UriDataSource';
constructor(uriArr:string[]) {
super()
this.mItems = uriArr.map((uri) => {
let item = new InnerMediaItem(uri);
if (uri.startsWith(InnerMediaItem.MEDIA_ABILITY)) {
item.setThumbnail(this.photoDataImpl.getThumbnail(item.uri, {
height: item.height,
width: item.width
}));
} else {
item.setThumbnail(item.uri);
}
item.uri = item.uri + UriDataSource.URL_TAG;
return item;
})
this.logger.debug(`create items: ${JSON.stringify(this.mItems)}`);
}
initData() {}
totalCount(): number {
return this.mItems.length;
}
getData(index: number): { data:MediaItem, pos:number, thumbnail:string } {
return {
data: this.mItems[index],
pos: index,
thumbnail: this.mItems[index].thumbnail
};
}
getRawData(index: number): any {
return {
data: index < this.mItems.length ? this.mItems[index] : new MediaItem(null),
pos: index
};
}
registerDataChangeListener(listener: DataChangeListener): void {
this.logger.info('registerDataChangeListener');
}
unregisterDataChangeListener(listener: DataChangeListener): void {
this.logger.info('unregisterDataChangeListener');
}
}

View File

@ -13,7 +13,7 @@
* limitations under the License.
*/
import {ViewType} from './ViewType.ets'
import {ViewType} from './ViewType'
export class ViewData {
viewType: ViewType;

View File

@ -50,4 +50,8 @@ export class BroadCastConstants {
static readonly SAVE_FORM_EDITOR_DATA = 'save_form_editor_data';
static readonly INIT_DATE_TEXT = 'init_date_text';
static readonly THIRD_ROUTE_PAGE = 'third_route_page';
static readonly ON_DATA_RELOADED_WITH_EDIT = 'on_data_reloaded_with_edit';
static readonly PHOTO_EDIT_SAVE_ID: string = 'photo_edit_save_id';
static readonly PHOTO_EDIT_SAVE_COMPLETE: string = 'photo_edit_save_complete';
static readonly CHANGE_SWIPER_DURATION = 'change_swiper_duration';
}

View File

@ -13,8 +13,8 @@
* limitations under the License.
*/
import {Logger} from '../../utils/Logger.ets'
import {BroadCast} from '../../utils/BroadCast.ets'
import {Logger} from '../../utils/Logger'
import {BroadCast} from '../../utils/BroadCast'
import {Constants} from './Constants'
export class BroadCastManager {

View File

@ -41,6 +41,8 @@ export class Constants {
static readonly DEFAULT_ROTATE_VALUE = 90;
static readonly ROTATE_AROUND = 360;
static readonly ANGLE_90 = 90;
static readonly ANGLE_270 = 270;
// Step size. When the last obtained data index deviates from the center of the current sliding window by more
// than this step, adjust the start and end of the window and re initiate the data request
@ -59,17 +61,18 @@ export class Constants {
static readonly APP_KEY_NEW_ALBUM = 'app_key_new_album';
static readonly APP_KEY_NEW_ALBUM_TARGET = 'app_key_new_album_target';
static readonly APP_KEY_NEW_ALBUM_SELECTED = 'app_key_new_album_selected';
static readonly APP_KEY_INSTANCE_MEDIA_LIBRARY_ACCESS = 'app_key_instance_media_library_access';
static readonly FROM_DATA_STORE_UTIL = 'form_data_store_util';
// BroadCast
static readonly APP_KEY_EVENT_BUS = 'app_key_event_bus';
// Persistent storage of tabs index
static readonly APP_KEY_TABS_INDEX: string = 'app_key_tabs_index';
static readonly SCREEN_MANAGER = 'screen_manager';
static readonly PIXEL_MAP_MANAGER = 'pixel_map_manager';
// Load completion event
static readonly ON_LOADING_FINISHED = 'on_loading_finished';
static readonly FIRST_PATCH_LOAD_FINISH = 'first_patch_load_finish';
// Large jump source: timeline
static readonly PHOTO_TRANSITION_TIMELINE: string = 'TimelinePage';
@ -80,6 +83,8 @@ export class Constants {
// Large jump source: camera
static readonly PHOTO_TRANSITION_CAMERA: string = 'Camera';
static readonly PHOTO_TRANSITION_EDIT: string = 'EditPage';
// Timeline page index
static readonly TIMELINE_PAGE_INDEX: number = 0;
@ -96,16 +101,16 @@ export class Constants {
static readonly PRESS_ANIM_SCALE = 0.9;
// Default maximum number of external selection pages
static readonly DEFAULT_MAX_THIRD_SELECT_COUNT: number = 500;
static readonly DEFAULT_MAX_THIRD_SELECT_COUNT: number = 50;
// Horizontal and vertical screen flag
static readonly SCREEN_ORIENTATION_HORIZONTAL: string = 'isHorizontal';
// Sidebar flag
static readonly SCREEN_SIDEBAR: string = 'screen_sidebar';
static readonly SCREEN_SIDEBAR: string = 'isSidebar';
// Column flag
static readonly SCREEN_COLUMNS: string = 'screen_colums';
static readonly SCREEN_COLUMNS: string = 'screen_columns';
static readonly ADD_NOTES_MAX_LENGTH: number = 140;
@ -118,6 +123,10 @@ export class Constants {
static readonly ENTRY_FROM_RECYCLE = 4;
static readonly ENTRY_FROM_DISTRIBUTED = 5;
static readonly ENTRY_FROM_NORMAL = 6;
static readonly ENTRY_FROM_FORM_ABILITY = 7;
static readonly ENTRY_FROM_FORM_FORM_EDITOR = 8;
static readonly ENTRY_FROM_VIEW_DATA = 9;
static readonly ENTRY_FROM_FORM_ABILITY_NONE = 12;
static readonly ENTRY_FROM = {
NORMAL: 0,
@ -126,10 +135,11 @@ export class Constants {
MULTIPLE_SELECT: 3,
RECYCLE: 4,
DISTRIBUTED: 5,
CARD: 6
CARD: 6,
VIEW_DATA: 7
}
static readonly DIALOG_BOTTOM_OFFSET: number = 12;
static readonly DIALOG_BOTTOM_OFFSET: number = 16;
// Local tab index
static readonly LOCAL_TAB_INDEX: number = 0;
@ -184,6 +194,15 @@ export class Constants {
static readonly RULER_FILL_STYLE_40: string = '#66FFFFFF';
static readonly RULER_TEXT_ALIGN: string = 'center';
static readonly MEDIA_TYPE_IMAGE: string = 'image';
static readonly MEDIA_TYPE_VIDEO: string = 'video';
static readonly MEDIA_TYPE_ALBUM: string = 'album';
static readonly MEDIA_TYPE_DEVICE: string = 'device';
static readonly MEDIA_TYPE_REMOTE: string = 'remote';
static readonly DEVICE_STATE_ONLINE: string = 'online';
static readonly DEVICE_STATE_OFFLINE: string = 'offline';
static readonly DEVICE_STATE_CHANGE: string = 'change';
static readonly TOP_BAR_SIZE: number = 56;
static readonly TOOL_BAR_SIZE: number = 72;
static readonly BOTTOM_TOOL_BAR_SIZE: number = 196;
@ -204,7 +223,11 @@ export class Constants {
static readonly NUMBER_3: number = 3;
static readonly NUMBER_4: number = 4;
static readonly NUMBER_5: number = 5;
static readonly NUMBER_5_5: number = 5.5;
static readonly NUMBER_6: number = 6;
static readonly NUMBER_6_5: number = 6.5;
static readonly NUMBER_7: number = 7;
static readonly NUMBER_7_5: number = 7.5;
static readonly NUMBER_8: number = 8;
static readonly NUMBER_8_5: number = 8.5;
static readonly NUMBER_9: number = 9;
@ -227,10 +250,12 @@ export class Constants {
static readonly GRID_MAX_SIZE_RATIO: number = 1.2;
static readonly GRID_MIN_COUNT: number = 4;
static readonly SCROLL_BAR_SIDE_MIN_GAP: number = 12;
static readonly SCROLL_MARGIN: number = 24;
static readonly SCROLL_BAR_VISIBLE_THRESHOLD: number = 50;
// Column Constants
static readonly COLUMN_MARGIN: number = 24;
static readonly COLUMN_GUTTER: number = 24;
static readonly COLUMN_MARGIN: number = 12;
static readonly COLUMN_GUTTER: number = 12;
// Album Card Constants
static readonly CARD_ASPECT_RATIO: number = 0.75;
@ -250,9 +275,48 @@ export class Constants {
static readonly EMPTY_PAGE_DEFAULT_OFFSET: number = 300;
static readonly EMPTY_PAGE_MARGIN: number = 12;
// Dialog
static readonly DETAILS_DIALOG_PATH_MAX_LINE: number = 7;
static readonly DETAILS_DIALOG_NAME_MAX_LINE: number = 5;
static readonly PROGRESS_MAX: number = 100;
static readonly BYTE_TO_MB: number = 1024 * 1024;
static readonly BIG_SCREEN_WIDTH: number = 600;
static readonly BIG_EMPTY_ICON_SIZE: number = 160;
static readonly SMALL_EMPTY_ICON_SIZE: number = 120;
// Menu
static readonly MENU_DIVIDER_STROKE_WIDTH: number = 0.5;
static readonly MENU_DIVIDER_STROKE_WIDTH: number = 1;
// Duration
static readonly SHARE_TRANSITION_DURATION: number = 200;
static readonly DELETE_ANIMATE_DURATION: number = 300;
// Percent
static readonly PERCENT_HUNDRED: number = 100;
static readonly PERCENT_ONE_THIRD: string = `${100 / 3}%`;
// AppStorage constants
static readonly ENTRY_FROM_HAP: string = 'entryFromHap';
static readonly FROM_ALBUM_ID: string = 'form_albumId';
static readonly FROM_CURRENT_INDEX: string = 'form_currentIndex';
static readonly FA_SETTING_FROM_ID: string = 'FASetting_FormId';
static readonly VIEW_DATA_URI: string = 'viewDataUri';
static readonly VIEW_DATA_POS: string = 'viewDataPos';
static readonly PERMISSION_STATUS: string = 'permissionStatus';
static readonly LEFT_BLANK: string = 'leftBlank';
static readonly FROM_FORM_PHOTO_EDITOR: string = 'from_form_photo_editor';
static readonly FORM_ITEM_NAME: string = 'form_itemName';
static readonly FORM_ITEM_ALBUM_ID: string = 'form_itemAlbumId';
static readonly FORM_ITEM_DISPLAY_NAME: string = 'form_itemDisplayName';
static readonly MAIN_WINDOW: string = 'mainWindow';
static readonly IS_SPLIT_MODE: string = 'isSplitMode';
static readonly ACTION_URI_FORM_ABILITY: string = 'formAbility';
static readonly ACTION_URI_FORM_ABILITY_NONE: string = 'formAbilityNone';
static readonly PROGRESS_LENGTH_DIFF: number = 88;
static readonly ALBUM_NAME_MAX_LENGTH = 80;
static readonly BACK_FROM_FORM_DETAIL: string = 'back_from_form_detail';
}

View File

@ -13,7 +13,7 @@
* limitations under the License.
*/
import inputConsumer from '@ohos.multimodalInput.inputConsumer';
import {Logger} from '../../utils/Logger.ets';
import {Logger} from '../../utils/Logger';
export class MultimodalInputManager {
logger: Logger = new Logger('MultimodalInputManager');
@ -41,33 +41,33 @@ export class MultimodalInputManager {
'finalKeyDownDuration': 0
};
registerListener(callback) {
async registerListener(callback) {
this.logger.debug(`registerListener start`);
inputConsumer.on('key', this.leftKeyOptions, (err, data) => {
this.logger.debug(`notificationRegister err: ${JSON.stringify(err)} data: ${JSON.stringify(data)}`);
inputConsumer.on('key', this.leftKeyOptions, (data) => {
this.logger.debug(`notificationRegister data: ${JSON.stringify(data)}`);
callback(0);
});
inputConsumer.on('key', this.rightKeyOptions, (err, data) => {
this.logger.debug(`controlRegister err: ${JSON.stringify(err)} data: ${JSON.stringify(data)}`);
inputConsumer.on('key', this.rightKeyOptions, (data) => {
this.logger.debug(`controlRegister data: ${JSON.stringify(data)}`);
callback(1);
});
inputConsumer.on('key', this.escKeyOptions, (err, data) => {
this.logger.debug(`escRegister err: ${JSON.stringify(err)} data: ${JSON.stringify(data)}`);
inputConsumer.on('key', this.escKeyOptions, (data) => {
this.logger.debug(`escRegister data: ${JSON.stringify(data)}`);
callback(2);
});
this.logger.debug(`registerListener end`);
}
unregisterListener() {
async unregisterListener() {
this.logger.debug(`unregisterListener start`);
inputConsumer.off('key', this.leftKeyOptions, (err, data) => {
this.logger.debug(`notificationUnregister err: ${JSON.stringify(err)} data: ${JSON.stringify(data)}`);
inputConsumer.off('key', this.leftKeyOptions, (data) => {
this.logger.debug(`notificationUnregister data: ${JSON.stringify(data)}`);
});
inputConsumer.off('key', this.rightKeyOptions, (err, data) => {
this.logger.debug(`controlUnregister err: ${JSON.stringify(err)} data: ${JSON.stringify(data)}`);
inputConsumer.off('key', this.rightKeyOptions, (data) => {
this.logger.debug(`controlUnregister data: ${JSON.stringify(data)}`);
});
inputConsumer.off('key', this.escKeyOptions, (err, data) => {
this.logger.debug(`escUnregister err: ${JSON.stringify(err)} data: ${JSON.stringify(data)}`);
inputConsumer.off('key', this.escKeyOptions, (data) => {
this.logger.debug(`escUnregister data: ${JSON.stringify(data)}`);
});
this.logger.debug(`unregisterListener end`);
}

View File

@ -13,9 +13,9 @@
* limitations under the License.
*/
import {FifoCache} from '../browser/photo/FifoCache.ets'
import {Thumbnail} from '../browser/photo/Thumbnail.ets'
import {Logger} from '../../utils/Logger.ets'
import {FifoCache} from '../browser/photo/FifoCache'
import {Thumbnail} from '../browser/photo/Thumbnail'
import {Logger} from '../../utils/Logger'
import {Constants} from './Constants'
export class PixelMapManager {

View File

@ -13,10 +13,9 @@
* limitations under the License.
*/
import display from '@ohos.display'
import {Logger} from '../../utils/Logger.ets'
import {Logger} from '../../utils/Logger'
import {Constants} from './Constants'
import {UiUtil} from '../../utils/UiUtil.ets';
import {UiUtil} from '../../utils/UiUtil'
export enum ColumnSize {
COLUMN_TWO = 2,
@ -33,7 +32,7 @@ enum ScreenWidth {
enum WindowMode {
UNDEFINED = 1,
FULLSCREEN,
FULL_SCREEN,
PRIMARY,
SECONDARY,
FLOATING
@ -43,6 +42,8 @@ export class ScreenManager {
static readonly ON_WIN_SIZE_CHANGED = 'on_win_size_changed';
static readonly ON_SPLIT_MODE_CHANGED = 'on_split_mode_changed';
static readonly ON_LEFT_BLANK_CHANGED = 'on_left_blank_changed';
static readonly DEFAULT_WIDTH : number = 1920;
static readonly DEFAULT_HEIGHT : number = 1080;
private static readonly SPLIT_THRESHOLD = 1.7;
private logger: Logger = new Logger('ScreenManager');
private winWidth = 0.0;
@ -51,7 +52,7 @@ export class ScreenManager {
private naviBarHeight = 0;
private leftBlank: [number, number, number, number] = [0, 0, 0, 0];
private events = [];
private mainWindow = undefined;
private columns: number = ColumnSize.COLUMN_FOUR;
// Default orientation
@ -71,29 +72,32 @@ export class ScreenManager {
}
let manager: ScreenManager = AppStorage.Get(Constants.APP_KEY_SCREEN_MANAGER);
// TODO: use display to replace window Temporarily
if (0 == manager.winWidth || 0 == manager.winHeight) {
display.getDefaultDisplay().then(retDisplay => {
if (retDisplay.height <= retDisplay.width) {
manager.winWidth = px2vp(retDisplay.height);
manager.winHeight = px2vp(retDisplay.width);
} else {
manager.winWidth = px2vp(retDisplay.width);
manager.winHeight = px2vp(retDisplay.height);
}
});
}
if (manager.winWidth < ScreenWidth.WIDTH_MEDIUM) {
manager.columns = ColumnSize.COLUMN_FOUR;
} else if (manager.winWidth >= ScreenWidth.WIDTH_MEDIUM && manager.winWidth < ScreenWidth.WIDTH_LARGE) {
manager.columns = ColumnSize.COLUMN_EIGHT;
} else {
manager.columns = ColumnSize.COLUMN_TWELVE;
}
return manager;
}
async initializationSize(win): Promise<void> {
this.mainWindow = win;
let properties = await win.getProperties();
return new Promise<void>((resolve, reject) => {
if (!properties || !properties.windowRect) {
reject();
}
let size = properties.windowRect;
this.logger.info(`display screen windowRect: ${JSON.stringify(size)}`);
this.winWidth = px2vp(size.width);
this.winHeight = px2vp(size.height);
this.logger.info(`display screen windowRect px2vp: ${this.winWidth} ${this.winHeight}`);
if (this.winWidth < ScreenWidth.WIDTH_MEDIUM) {
this.columns = ColumnSize.COLUMN_FOUR;
} else if (this.winWidth >= ScreenWidth.WIDTH_MEDIUM && this.winWidth < ScreenWidth.WIDTH_LARGE) {
this.columns = ColumnSize.COLUMN_EIGHT;
} else {
this.columns = ColumnSize.COLUMN_TWELVE;
}
resolve();
});
}
/**
* Add Listeners
*
@ -188,6 +192,7 @@ export class ScreenManager {
initWindowMode() {
this.logger.debug(`start to initialize photos application window mode: ${this.windowMode}`);
this.checkWindowMode();
this.mainWindow && this.setMainWindow();
}
isSplitMode(): boolean {
@ -205,23 +210,23 @@ export class ScreenManager {
return;
}
this.windowMode = mode;
if (WindowMode.FULLSCREEN == this.windowMode) {
if (WindowMode.FULL_SCREEN == this.windowMode) {
this.setFullScreen();
} else {
this.setSplitScreen();
}
}
setMainWindow(win) {
setMainWindow() {
this.logger.debug('setMainWindow');
win.on('windowSizeChange', (data) => {
this.mainWindow.on('windowSizeChange', (data) => {
this.logger.debug(`windowSizeChange ${JSON.stringify(data)}`);
this.onWinSizeChanged(data);
})
}
getAvoidArea() {
let topWindow: any = AppStorage.Get('mainWindow');
let topWindow: any = AppStorage.Get(Constants.MAIN_WINDOW);
topWindow.getAvoidArea(0, (err, data) => {
this.logger.info('Succeeded in obtaining the area. Data:' + JSON.stringify(data));
this.onLeftBlankChanged(data);
@ -229,7 +234,7 @@ export class ScreenManager {
}
setFullScreen() {
let topWindow: any = AppStorage.Get('mainWindow');
let topWindow: any = AppStorage.Get(Constants.MAIN_WINDOW);
this.logger.debug('getTopWindow start');
try {
topWindow.setLayoutFullScreen(true, () => {
@ -254,7 +259,7 @@ export class ScreenManager {
hideStatusBar() {
this.logger.debug('hideStatusBar start');
let topWindow: any = AppStorage.Get('mainWindow');
let topWindow: any = AppStorage.Get(Constants.MAIN_WINDOW);
this.logger.debug('getTopWindow start');
let names = ['navigation'];
this.logger.debug(`getTopWindow names: ${names} end`);
@ -264,13 +269,13 @@ export class ScreenManager {
topWindow.getAvoidArea(0, async (err, data) => {
this.logger.info(`Succeeded in obtaining the area. Data: ${JSON.stringify(data)}`);
this.onLeftBlankChanged(data);
let barColor = await UiUtil.getResourceString($r('app.color.default_background_color'));
let barColor = await UiUtil.getResourceString($r('app.color.transparent'));
let barContentColor = await UiUtil.getResourceString($r('app.color.default_bar_content_color'));
if (!barColor) {
barColor = '#fff1f3f5';
barColor = '#00000000';
}
if (!barContentColor) {
barContentColor = '#ff000000';
barContentColor = '#FF000000';
}
topWindow.setSystemBarProperties({navigationBarColor: barColor, navigationBarContentColor: barContentColor},
() => { this.logger.info('setStatusBarColor done'); });
@ -281,9 +286,33 @@ export class ScreenManager {
}
}
async setNavigationBarColor(resource: string) {
this.logger.debug('setNavigationBarColor start');
let topWindow: any = AppStorage.Get(Constants.MAIN_WINDOW);
try {
topWindow.setSystemBarProperties({navigationBarContentColor: resource},
() => { this.logger.info('setStatusBarColor done'); });
} catch (err) {
this.logger.error(`setNavigationBarColor err: ${err}`);
}
}
async setNavigationBarProperties(barColor: String, barContentColor: string) {
this.logger.debug('setNavigationBarColor start');
let topWindow: any = AppStorage.Get(Constants.MAIN_WINDOW);
let backColor = barColor == '' ? '#00000000' : barColor;
let contentColor = barContentColor == '' ? '#ff000000' : barContentColor;
try {
topWindow.setSystemBarProperties({navigationBarColor: backColor, navigationBarContentColor: contentColor},
() => { this.logger.info('setStatusBarColor done'); });
} catch (err) {
this.logger.error(`setNavigationBarColor err: ${err}`);
}
}
setSystemUi(isShowBar: boolean): void {
this.logger.debug('setSystemUi start');
let topWindow: any = AppStorage.Get('mainWindow');
let topWindow: any = AppStorage.Get(Constants.MAIN_WINDOW);
this.logger.debug('getTopWindow start');
let names = ["navigation"];
if (!isShowBar) {
@ -335,6 +364,14 @@ export class ScreenManager {
};
this.winWidth = px2vp(size.width);
this.winHeight = px2vp(size.height);
this.logger.info(`onWinSizeChanged px2vp: ${this.winWidth} ${this.winHeight}`);
if (this.winWidth < ScreenWidth.WIDTH_MEDIUM) {
this.columns = ColumnSize.COLUMN_FOUR;
} else if (this.winWidth >= ScreenWidth.WIDTH_MEDIUM && this.winWidth < ScreenWidth.WIDTH_LARGE) {
this.columns = ColumnSize.COLUMN_EIGHT;
} else {
this.columns = ColumnSize.COLUMN_TWELVE;
}
let isSplitModeNow = this.isSplitMode();
if (isSplitModeBefore != isSplitModeNow) {
this.logger.info(`splitMode changed: ${isSplitModeBefore} -> ${isSplitModeNow}`);
@ -374,6 +411,7 @@ export class ScreenManager {
}
getColumnsWidth(count: number): number {
this.logger.info(`getColumnsWidth count is ${count} colunms is ${this.columns}`);
let columnWidth = (this.winWidth - Constants.COLUMN_MARGIN) / this.columns;
return columnWidth * count - Constants.COLUMN_GUTTER;
}

View File

@ -14,9 +14,8 @@
*/
import {UiUtil} from '../../utils/UiUtil.ets'
import {ActionBarProp} from '../browser/operation/ActionBarProp.ets';
import {Logger} from '../../utils/Logger.ets'
import {UiUtil} from '../../utils/UiUtil'
import {Logger} from '../../utils/Logger'
import {Constants} from './Constants'
export enum StatusBarColorMode {

View File

@ -63,4 +63,12 @@ export class BroadCast {
}
}
}
public release() {
this.callBackArray.forEach((array) => {
array.length = 0;
});
this.callBackArray.length = 0;
this.callBackArray = [];
}
}

View File

@ -0,0 +1,127 @@
/*
* 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 {Logger} from './Logger'
import {Constants} from '../model/common/Constants'
import data_preferences from '@ohos.data.preferences'
export class DataStoreUtil {
private logger: Logger = new Logger('DataStoreUtil');
private context:any = undefined;
private preferences: any = undefined;
private static readonly PREFERENCES_KEY_MY_FORM_STORE = 'myFormStore'
private constructor(context) {
this.logger.info('new DataStoreUtil');
this.context = context;
}
public static getInstance(context: any): DataStoreUtil {
if (AppStorage.Get(Constants.FROM_DATA_STORE_UTIL) == null) {
AppStorage.SetOrCreate(Constants.FROM_DATA_STORE_UTIL, new DataStoreUtil(context));
}
return AppStorage.Get(Constants.FROM_DATA_STORE_UTIL);
}
public async init(): Promise<void> {
this.logger.debug('init start!');
if (this.preferences) {
this.logger.debug('init already!');
return;
}
await data_preferences.getPreferences(this.context, DataStoreUtil.PREFERENCES_KEY_MY_FORM_STORE).then((preferences) => {
this.logger.info(`init preferences ${preferences}`);
this.preferences = preferences;
}).catch((err) => {
this.logger.error(`init err ${err}`);
})
this.logger.debug('init end!');
return;
}
public async getData(key:string, defValue) {
this.logger.debug('getData start!');
if (this.preferences == undefined) {
this.logger.error(`getData preferences is undefined`);
return defValue;
}
let temValue = defValue;
await this.preferences.get(key, defValue).then((value) => {
this.logger.debug("The value of startup is " + value)
temValue = value;
}).catch((err) => {
this.logger.error(`Get the value failed with err: ${err}`)
})
return temValue;
}
public async putData(key: string, value) {
this.logger.debug('putData start!');
if (this.preferences == undefined) {
this.logger.error('putData preferences is undefined');
}
await this.preferences.put(key, value).then(() => {
this.logger.debug('Put the value successfully.');
}).catch((err) => {
this.logger.error(`Put the value failed with err: ${err}`);
})
}
public async delData(key: string) {
this.logger.debug('delData start!');
if (this.preferences == undefined) {
this.logger.error(`delData preferences is undefined`);
}
await this.preferences.delete(key).then(() => {
this.logger.debug("Delete the value successfully.");
}).catch((err) => {
this.logger.error(`Delete the value failed with err: ${err}`);
})
}
public async flush() {
this.logger.debug('flush start!');
await this.preferences.flush();
}
public async hasData(key: string) {
this.logger.debug(`hasData start! preferences ${this.preferences}`);
let ret = false;
if (this.preferences == undefined) {
this.logger.error(`hasData preferences is undefined`);
return ret;
}
await this.preferences.has(key).then((value) => {
this.logger.debug("hasData the value successfully.");
ret = value;
}).catch((err) => {
this.logger.error(`hasData the value failed with err: ${err}`);
ret = false;
})
return ret;
}
public async removeCache() {
this.logger.debug('removeCache start!');
await data_preferences.removePreferencesFromCache(this.context, DataStoreUtil.PREFERENCES_KEY_MY_FORM_STORE).then(() => {
this.preferences = undefined;
console.info("removeCache successfully.")
}).catch((err) => {
console.error("removeCache failed with err: " + err)
})
}
}

View File

@ -13,8 +13,9 @@
* limitations under the License.
*/
import {Logger} from './Logger.ets'
import {Logger} from './Logger'
import i18n from '@ohos.i18n';
import Intl from '@ohos.intl';
export class DateUtil {
// logger
@ -23,18 +24,45 @@ export class DateUtil {
'zh': 'zh-CN',
'en': 'en-US'
};
private static readonly FORMAT_DECIMAL: number = 10
public static readonly MILLISECONDS_PER_SECOND: number = 1000;
public static readonly SECONDS_PER_MINUTE: number = 60;
public static readonly SECONDS_PER_HOUR: number = 3660;
public static readonly SECONDS_PER_HOUR: number = 3600;
// Get the date after localization (year-month-day)
public static getLocalizedDate(milliseconds: number): string {
let locales: string = this.getLocales();
return new Intl.DateTimeFormat(locales, {
year: 'numeric',
month: 'long',
day: 'numeric'
}).format(new Date(milliseconds));
return new Intl.DateTimeFormat(locales, this.buildDateTimeOpt('numeric', 'long', 'numeric', '', '')).format(new Date(milliseconds));
}
public static format(time: Date, format_s?: string): string {
if (!format_s) {
return time.valueOf().toString();
}
let opts = {
'MM': time.getMonth() + 1,
'dd': time.getDate(),
'HH': time.getHours(),
'mm': time.getMinutes(),
'ss': time.getSeconds()
}
if (/(y+)/.test(format_s)) {
format_s = format_s.replace('yyyy', time.getFullYear().toString().substr(0));
}
for (let f in opts) {
if (new RegExp('(' + f + ')').test(format_s)) {
format_s = format_s.replace(f, (f.length == 1) ? opts[f] : (('00' + opts[f]).substr(
opts[f].toString()
.length)))
}
}
return format_s;
}
public static getDateTimeFormat(milliseconds: number): string {
return DateUtil.format(new Date(milliseconds), 'yyyy/MM/dd HH:mm:ss');
}
// Gets the localization date of the photo page grouping data
@ -54,29 +82,28 @@ export class DateUtil {
public static getLocalizedYear(milliseconds: number): Resource {
let locales: string = this.getLocales();
let yearText = new Intl.DateTimeFormat(locales, {
year: 'numeric'
}).format(new Date(milliseconds));
let yearText = new Intl.DateTimeFormat(locales, this.buildDateTimeOpt('numeric', '', '', '', '')).format(new Date(milliseconds));
return $r('app.string.common_place_holder', yearText.toString());
}
public static getLocalizedYearAndMonth(milliseconds: number): string {
let locales: string = this.getLocales();
return new Intl.DateTimeFormat(locales, {
year: 'numeric',
month: 'long'
}).format(new Date(milliseconds));
return new Intl.DateTimeFormat(locales, this.buildDateTimeOpt('numeric', 'long', '', '', '')).format(new Date(milliseconds));
}
public static getLocalizedTime(milliseconds: number): string {
let locales: string = this.getLocales();
let is24HourClock = i18n.is24HourClock();
return new Intl.DateTimeFormat(locales, { hour12: !is24HourClock,
hour: (is24HourClock ? '2-digit' : 'numeric'), minute: '2-digit' }).format(new Date(milliseconds));
this.logger.info(`get is24HourClock ${is24HourClock}`);
return new Intl.DateTimeFormat(locales, this.buildDateTimeOpt('','','',(!is24HourClock ? '2-digit' : 'numeric'), '2-digit')).format(new Date(milliseconds));
}
private static getLocales(): string {
let language = AppStorage.Get('languageCode').toString();
static getLocales(): string {
let systemLocale = i18n.getSystemLanguage();
let language = systemLocale.split('-')[0];
let locales: string = this.LANGUAGE_LOCALES_MAP['en'];
if (this.LANGUAGE_LOCALES_MAP[language]) {
locales = this.LANGUAGE_LOCALES_MAP[language];
@ -114,7 +141,7 @@ export class DateUtil {
return '00';
}
let formatTime: string = time.toString();
if (time < 10) {
if (time < DateUtil.FORMAT_DECIMAL) {
let zeroString = '0';
formatTime = zeroString.concat(formatTime);
}
@ -138,4 +165,28 @@ export class DateUtil {
const endYear = new Date(endTime).getFullYear();
return startYear === endYear ? true : false;
}
public static buildDateTimeOpt(year: string, month: string, day: string, hour:string, minute: string){
return {
locale: '',
dateStyle: '',
timeStyle: '',
hourCycle: '',
timeZone: '',
numberingSystem: '',
hour12: false,
weekday: '',
era: '',
year: year,
month: month,
day: day,
hour: hour,
minute: minute,
second: '',
timeZoneName: '',
dayPeriod: '',
localeMatcher: '',
formatMatcher: '',
}
}
}

View File

@ -13,10 +13,17 @@
* limitations under the License.
*/
import {Logger} from './Logger.ets'
import {Logger} from './Logger'
export class ImageUtil {
static logger: Logger = new Logger('ImageUtil');
private static readonly MAX_BIT = 30;
private static readonly BIT_SIXTEEN = 16;
private static readonly BIT_EIGHT = 8;
private static readonly BIT_FOUR = 4;
private static readonly BIT_TWO = 2;
private static readonly BIT_ONE = 1;
private static readonly ROTATE_TWICE = 180; //TODO MAGIC
static computeSampleSize(width: number, height: number, minSideLength: number, maxNumOfPixels: number): number {
if (width == 0 || height == 0 || minSideLength == 0 || maxNumOfPixels == 0) {
@ -45,14 +52,14 @@ export class ImageUtil {
static nextPowerOf2(value: number): number {
let useValue = value;
if (useValue <= 0 || useValue > (1 << 30)) {
if (useValue <= 0 || useValue > (1 << ImageUtil.MAX_BIT)) {
}
useValue -= 1;
useValue |= useValue >> 16;
useValue |= useValue >> 8;
useValue |= useValue >> 4;
useValue |= useValue >> 2;
useValue |= useValue >> 1;
useValue |= useValue >> ImageUtil.BIT_SIXTEEN;
useValue |= useValue >> ImageUtil.BIT_EIGHT;
useValue |= useValue >> ImageUtil.BIT_FOUR;
useValue |= useValue >> ImageUtil.BIT_TWO;
useValue |= useValue >> ImageUtil.BIT_ONE;
this.logger.error(`nextPowerOf2:${useValue}`);
return useValue + 1;
}
@ -71,6 +78,6 @@ export class ImageUtil {
return 1;
}
let orientation = info.orientation || 0;
return orientation == 0 || orientation == 180 ? info.width / info.height : info.height / info.width;
return orientation == 0 || orientation == ImageUtil.ROTATE_TWICE ? info.width / info.height : info.height / info.width;
}
}

View File

@ -24,7 +24,7 @@ export class Logger {
static readonly WARN = 3;
static readonly ERROR = 4;
static logLevel = Logger.INFO;
static logLevel = Logger.DEBUG;
constructor(module: string) {
this.prefix = `${module}: `;

View File

@ -13,7 +13,7 @@
* limitations under the License.
*/
import {Logger} from './Logger.ets'
import {Logger} from './Logger'
export class StringUtil {
static logger: Logger = new Logger('StringUtil');
@ -60,4 +60,13 @@ export class StringUtil {
}
return result.substr(0, (result.length - connector.length));
}
static getIdFromUri(uri:string): number {
let srcIndex = uri.lastIndexOf('/');
let srcEnd = uri.length;
let srcId = uri.substring(srcIndex + 1, srcEnd);
let fileId = new Number(srcId);
this.logger.info(`getIdByUri fileId: ${fileId}`);
return fileId.valueOf();
}
}

View File

@ -14,13 +14,14 @@
*/
import i18n from '@ohos.i18n';
import {Logger} from './Logger.ets'
import {Logger} from './Logger'
export class SystemUtil {
static logger: Logger = new Logger('SystemUtil');
public static getSystemLanguage(): string {
let localInfo = AppStorage.Get('languageCode').toString();
let systemLocale = i18n.getSystemLanguage();
let localInfo = systemLocale.split('-')[0];
return localInfo;
}

View File

@ -32,7 +32,7 @@ export class TraceControllerUtils {
bytrace.startTrace(name, taskId);
}
// Used to track the end of cross tasks. The name and taskid must be the same as at start
// Used to track the end of cross tasks. The name and taskId must be the same as at start
public static finishTraceWithTaskId(name: string, taskId: number): void {
bytrace.finishTrace(name, taskId);
}

View File

@ -13,10 +13,12 @@
* limitations under the License.
*/
import {MathUtil} from './MathUtil.ets'
import {Logger} from './Logger.ets'
import {MathUtil} from './MathUtil'
import {Logger} from './Logger'
import {Constants} from '../model/common/Constants';
import resourceManager from '@ohos.resourceManager';
import prompt from '@system.prompt';
import {ScreenManager} from '../model/common/ScreenManager';
export class UiUtil {
@ -55,7 +57,7 @@ export class UiUtil {
*/
private static readonly HEX_COLOR_OPACITY_LENGTH = 2;
private static readonly TOAST_DURATION = 2000;
public static readonly TOAST_DURATION = 3000;
/**
* Hexadecimal array
@ -92,7 +94,7 @@ export class UiUtil {
*/
static setSystemUi(isShowBar: boolean): void {
this.logger.debug('setSystemUi start');
let topWindow: any = AppStorage.Get('mainWindow');
let topWindow: any = AppStorage.Get(Constants.MAIN_WINDOW);
this.logger.debug('getTopWindow start');
let names = ["status", "navigation"];
if (!isShowBar) {
@ -233,8 +235,8 @@ export class UiUtil {
static async getResourceString(resource: Resource) {
try {
this.logger.info(`getResourceString: ${JSON.stringify(resource)}`);
let mgr = await resourceManager.getResourceManager(globalThis.photosAbilityContext);
if (mgr) {
let mgr:resourceManager.ResourceManager = await resourceManager.getResourceManager(globalThis.photosAbilityContext);
if (mgr != null || mgr != undefined) {
return await mgr.getString(resource.id);
} else {
this.logger.error(`getResourceManager instance is none`);
@ -248,11 +250,12 @@ export class UiUtil {
static async showToast(resource: Resource) {
let message = await UiUtil.getResourceString(resource);
let naviBarHeight = ScreenManager.getInstance().getNaviBarHeight()
this.logger.debug(`showToast: ${message}`);
prompt.showToast({
message: message,
duration: UiUtil.TOAST_DURATION,
bottom: '200vp'
bottom: `${64 + naviBarHeight}vp`
});
}
}

View File

@ -12,7 +12,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {Constants} from '../model/common/Constants'
@Component
export struct GridScrollBar {
@ -25,18 +25,19 @@ export struct GridScrollBar {
state: this.isHideScrollBar? BarState.Off: BarState.Auto }) {
Row() {
if (this.isClickScrollBar) {
Image($r('app.media.scroll_press_light_hdpi'))
Image($r("app.media.scroll_press_light"))
.width($r('app.float.scroll_bar_big_width'))
.height($r('app.float.scroll_bar_big_height'))
} else {
Image($r('app.media.scroll_light_hdpi'))
Image($r("app.media.scroll_light"))
.width($r('app.float.scroll_bar_small_width'))
.height($r('app.float.scroll_bar_small_height'))
.borderRadius(25)
}
}
}
.height('100%')
.width(this.isClickScrollBar
? $r('app.float.scroll_bar_margin_small') : $r('app.float.scroll_bar_small_width'),)
.position({x:'100%', y:0})
.markAnchor({
x: this.isClickScrollBar ? $r('app.float.scroll_bar_big_width') : $r('app.float.scroll_bar_small_width'),

View File

@ -13,17 +13,17 @@
* limitations under the License.
*/
import {Logger} from '../utils/Logger.ets'
import {Constants} from '../model/common/Constants.ets'
import {MediaItem} from '../model/browser/photo/MediaItem.ets'
import {Logger} from '../utils/Logger'
import {Constants} from '../model/common/Constants'
import {MediaItem} from '../model/browser/photo/MediaItem'
import {DateUtil} from '../utils/DateUtil'
import {BroadCast} from '../utils/BroadCast.ets'
import {BroadCast} from '../utils/BroadCast'
import {BroadCastConstants} from '../model/common/BroadCastConstants'
import image from '@ohos.multimedia.image'
import {ImageUtil} from '../utils/ImageUtil'
import {ScreenManager} from '../model/common/ScreenManager'
import {TraceControllerUtils} from '../utils/TraceControllerUtils'
import { MediaLibraryAccess } from '../access/MediaLibraryAccess.ets';
import { MediaLibraryAccess } from '../access/MediaLibraryAccess';
// General grid picture control
@Component
@ -69,7 +69,7 @@ export struct ImageGridItemComponent {
this.isEnteringPhoto = false;
}
private aboutToAppear(): void {
aboutToAppear(): void {
this.logger.debug('aboutToAppear');
this.imageThumbnail = this.item.thumbnail;
this.logger.debug(`imageThumbnail: ${JSON.stringify(this.imageThumbnail)}`);
@ -141,8 +141,8 @@ export struct ImageGridItemComponent {
private generateSampleSize(imageWidth: number, imageHeight: number): number {
let width = ScreenManager.getInstance().getWinWidth();
let height = ScreenManager.getInstance().getWinHeight();
width = width == 0 ? 1920 : width;
height = height == 0 ? 1080 : height;
width = width == 0 ? ScreenManager.DEFAULT_WIDTH : width;
height = height == 0 ? ScreenManager.DEFAULT_HEIGHT : height;
let maxNumOfPixels = width * height;
let minSide = Math.min(width, height);
return ImageUtil.computeSampleSize(imageWidth, imageHeight, minSide, maxNumOfPixels);
@ -151,24 +151,25 @@ export struct ImageGridItemComponent {
build() {
Column() {
Stack({ alignContent: Alignment.Start }) {
Image(this.useAlt ? ((this.item.mediaType == MediaLibraryAccess.MEDIA_TYPE_VIDEO) ?
$r('app.media.alt_video_placeholder') : $r('app.media.alt_placeholder')) : this.imageThumbnail)
.alt(this.useAlt ? ((this.item.mediaType == MediaLibraryAccess.MEDIA_TYPE_VIDEO) ?
$r('app.media.alt_video_placeholder') : $r('app.media.alt_placeholder')) : '')
.aspectRatio(1)
.rotate({ x: 0, y: 0, z: 1, angle: this.useAlt ? 0 : this.item.orientation })
.objectFit(ImageFit.Cover)
.autoResize(false)
// .sharedTransition(this.transitionId, {duration:200}) TODO: delete dynamic effect
.onError(() => {
if(this.imageThumbnail) {
this.useAlt = true;
}
this.logger.error('alt Image error');
})
.onComplete(() => {
this.logger.debug(`Draw the image! ${this.imageThumbnail}`);
})
Row() {
Image(this.useAlt ? ((this.item.mediaType == MediaLibraryAccess.MEDIA_TYPE_VIDEO) ?
$r('app.media.alt_video_placeholder') : $r('app.media.alt_placeholder')) : this.imageThumbnail)
.alt(this.useAlt ? ((this.item.mediaType == MediaLibraryAccess.MEDIA_TYPE_VIDEO) ?
$r('app.media.alt_video_placeholder') : $r('app.media.alt_placeholder')) : '')
.aspectRatio(1)
.rotate({ x: 0, y: 0, z: 1, angle: this.useAlt ? 0 : this.item.orientation })
.objectFit(ImageFit.Cover)
.autoResize(false)
.onError(() => {
if(this.imageThumbnail) {
this.useAlt = true;
}
this.logger.error('alt Image error');
})
.onComplete(() => {
this.logger.debug(`Draw the image! ${this.imageThumbnail}`);
})
}.sharedTransition(this.transitionId, {duration : Constants.SHARE_TRANSITION_DURATION})
if (this.item.mediaType == MediaLibraryAccess.MEDIA_TYPE_VIDEO) {
Column()
@ -181,10 +182,10 @@ export struct ImageGridItemComponent {
.fontSize($r('sys.float.ohos_id_text_size_caption'))
.fontFamily($r('app.string.id_text_font_family_regular'))
.fontColor($r('app.color.text_color_above_picture'))
.lineHeight(12)
.lineHeight($r('app.float.grid_item_text_line_height'))
.position({ x: '0%', y: '100%' })
.markAnchor({ x: -4, y: 16 })
.margin({ right: 32 })
.markAnchor({ x: $r('app.float.grid_item_duration_markAnchor_x'), y: $r('app.float.grid_item_duration_markAnchor_y') })
.margin({ right: $r('app.float.grid_item_duration_margin_right') })
}
Image($r('app.media.ic_favorite_overlay'))
@ -192,7 +193,7 @@ export struct ImageGridItemComponent {
.width($r('app.float.icon_size'))
.objectFit(ImageFit.Contain)
.position({ x: '100%', y: '0%' })
.markAnchor({ x: 28, y: -4 })
.markAnchor({ x: $r('app.float.grid_item_favor_markAnchor_x'), y: $r('app.float.grid_item_favor_markAnchor_y') })
.visibility(this.item.isFavor ? Visibility.Visible : Visibility.None)
Column()
@ -224,7 +225,7 @@ export struct ImageGridItemComponent {
.width($r('app.float.icon_size_hot'))
.position({ x: '0%', y: '0%' })
.markAnchor({ x: 0, y: 0 })
.padding(4)
.padding($r('app.float.grid_item_preview_padding'))
.visibility(this.isSelectedMode ? Visibility.Visible : Visibility.None)
Image(this.isSelected
@ -232,7 +233,7 @@ export struct ImageGridItemComponent {
.height($r('app.float.icon_size'))
.width($r('app.float.icon_size'))
.position({ x: '100%', y: '100%' })
.markAnchor({ x: 28, y: 28 })
.markAnchor({ x: $r('app.float.grid_item_checkbox_markAnchor'), y: $r('app.float.grid_item_checkbox_markAnchor') })
.visibility(this.isSelectedMode ? Visibility.Visible : Visibility.None)
.onClick(() => {
this.selectStateChange();

View File

@ -14,8 +14,8 @@
*/
import {ScreenManager} from '../model/common/ScreenManager'
import {Constants} from '../model/common/Constants.ets'
import {Logger} from '../utils/Logger.ets'
import {Constants} from '../model/common/Constants'
import {Logger} from '../utils/Logger'
@Component
export struct NoPhotoComponent {
@ -25,19 +25,31 @@ export struct NoPhotoComponent {
// set an initial value temporarily, later change to 0.
@State offSetY: number = Constants.EMPTY_PAGE_DEFAULT_OFFSET;
@StorageLink('isHorizontal') isHorizontal: boolean = ScreenManager.getInstance().isHorizontal();
@StorageLink('isSidebar') isSidebar: boolean = ScreenManager.getInstance().isSidebar();
@StorageLink('leftBlank') leftBlank: [number, number, number, number]
= [0, ScreenManager.getInstance().getStatusBarHeight(), 0, ScreenManager.getInstance().getNaviBarHeight()];
@State bigScreen: boolean = false;
private aboutToAppear(): void {
aboutToAppear(): void {
this.logger.info(`aboutToAppear`);
this.bigScreen = Math.min(ScreenManager.getInstance().getWinHeight(), ScreenManager.getInstance().getWinWidth()) > Constants.BIG_SCREEN_WIDTH
let halfImageHeight = this.bigScreen ? Constants.BIG_EMPTY_ICON_SIZE / 2 : Constants.SMALL_EMPTY_ICON_SIZE / 2
let screenHeight = ScreenManager.getInstance().getWinHeight() - this.leftBlank[1] - this.leftBlank[3]
if (this.isHorizontal) {
// Phone landscape
this.offSetY = (ScreenManager.getInstance().getWinHeight() -
Constants.ActionBarHeight) / Constants.NUMBER_2 - Constants.EMPTY_PAGE_MARGIN;
if (this.isSidebar) {
// Pad landscape
this.offSetY = screenHeight / Constants.NUMBER_2 - halfImageHeight - Constants.ActionBarHeight;
} else {
// Phone landscape
this.offSetY = (screenHeight - Constants.ActionBarHeight) / Constants.NUMBER_2 - halfImageHeight;
}
} else {
// Phone vertical screen
this.offSetY = ScreenManager.getInstance().getWinHeight() * Constants.EMPTY_PAGE_OFFSET_RADIO -
Constants.ActionBarHeight - Constants.EMPTY_PAGE_MARGIN;
this.offSetY = screenHeight * Constants.EMPTY_PAGE_OFFSET_RADIO -
Constants.ActionBarHeight - halfImageHeight;
}
this.logger.info(`isHorizontal: ${this.isHorizontal}, offSetY: ${this.offSetY}`);
this.logger.info(`isHorizontal: ${this.isHorizontal}, offSetY: ${this.offSetY}, bigScreen: ${this.bigScreen}`);
}
build() {
@ -47,9 +59,9 @@ export struct NoPhotoComponent {
alignItems: ItemAlign.Start
}) {
Column() {
Image($rawfile('no_photos.png'))
.height($r('app.float.empty_page_picture_size'))
.width($r('app.float.empty_page_picture_size'))
Image($r("app.media.no_image_icon"))
.height(this.bigScreen ? $r('app.float.empty_page_picture_size_large') : $r('app.float.empty_page_picture_size'))
.width(this.bigScreen ? $r('app.float.empty_page_picture_size_large') : $r('app.float.empty_page_picture_size'))
.margin({
bottom: $r('sys.float.ohos_id_elements_margin_vertical_m'),
})

View File

@ -14,8 +14,8 @@
*/
import {ScreenManager} from '../model/common/ScreenManager'
import {Constants} from '../model/common/Constants.ets'
import {Logger} from '../utils/Logger.ets'
import {Constants} from '../model/common/Constants'
import {Logger} from '../utils/Logger'
const IMAGE_SCREEN_RATIO = 0.8
@ -26,9 +26,15 @@ export struct NoPhotoIndexComponent {
// set an initial value temporarily, later change to 0.
@State imageSize: number = 0;
private reSizeFunc = this.reSizeLayout.bind(this);
private aboutToAppear(): void {
aboutToAppear(): void {
this.logger.info('aboutToAppear');
ScreenManager.getInstance().on(ScreenManager.ON_WIN_SIZE_CHANGED, this.reSizeFunc);
this.updateImageSize();
}
reSizeLayout() {
this.updateImageSize();
}
@ -37,16 +43,13 @@ export struct NoPhotoIndexComponent {
let winHeightHalf = ScreenManager.getInstance().getWinHeight() / 2;
this.imageSize
= (winWidth < winHeightHalf) ? (winWidth * IMAGE_SCREEN_RATIO) : (winHeightHalf * IMAGE_SCREEN_RATIO)
this.logger.info(`window size: ${winWidth}, ${winHeightHalf} ,empty photos or album picture size = ${this.imageSize}`);
}
build() {
Flex({
direction: FlexDirection.Column,
justifyContent: FlexAlign.Start,
alignItems: ItemAlign.Start
}) {
Row() {
Column() {
Image((this.index == Constants.TIMELINE_PAGE_INDEX) ? $r('app.media.Photo') : $r('app.media.Album'))
Image((this.index == Constants.TIMELINE_PAGE_INDEX) ? $r("app.media.photo_empty") : $r("app.media.album_empty"))
.height(this.imageSize)
.width(this.imageSize)
.margin({
@ -66,7 +69,7 @@ export struct NoPhotoIndexComponent {
Text((this.index == Constants.TIMELINE_PAGE_INDEX) ? $r('app.string.no_photo_head_title_timeline')
: $r('app.string.no_photo_head_title_album'))
.fontSize($r('sys.float.ohos_id_text_size_headline8'))
.fontFamily($r('app.string.id_text_font_family_regular'))
.fontWeight(FontWeight.Medium)
.fontColor($r('sys.color.ohos_id_color_text_primary'))
.margin({
left: $r('app.float.max_padding_start'),
@ -86,7 +89,11 @@ export struct NoPhotoIndexComponent {
}
}
.width('100%')
.margin({ top: $r('app.float.appbar_max_height')})
}
.width('100%')
.height('100%')
.alignItems(VerticalAlign.Top)
.justifyContent(FlexAlign.Start)
}
}

View File

@ -0,0 +1,34 @@
/*
* 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 {ScreenManager} from '../model/common/ScreenManager';
@Component
export struct PhotoBrowserHolder {
@Consume isShowBar: boolean;
@StorageLink('leftBlank') leftBlank: [number, number, number, number]
= [0, ScreenManager.getInstance().getStatusBarHeight(), 0, ScreenManager.getInstance().getNaviBarHeight()];
build() {
Column() {
}
.backgroundColor($r('app.color.default_background_color'))
.width('100%')
.height(this.leftBlank[3])
.markAnchor({x: '0%', y: '100%'})
.position({x: '0%', y: '100%'})
.opacity($r('app.float.photo_browser_holder_opacity'))
.visibility(this.isShowBar ? Visibility.Visible : Visibility.Hidden)
}
}

View File

@ -14,14 +14,16 @@
*/
import Matrix4 from '@ohos.matrix4'
import router from '@system.router'
import {MediaItem} from '../../common/model/browser/photo/MediaItem.ets'
import {EventPipeline} from '../../common/model/browser/photo/EventPipeline.ets'
import {MediaItem} from '../../common/model/browser/photo/MediaItem'
import {EventPipeline} from '../../common/model/browser/photo/EventPipeline'
import {BroadCast} from '../../common/utils/BroadCast'
import {Logger} from '../utils/Logger'
import {Constants as PhotoConstants} from '../../common/model/browser/photo/Constants'
import {MediaLibraryAccess} from '../../common/access/MediaLibraryAccess'
import {ScreenManager} from '../model/common/ScreenManager'
import {Constants} from '../model/common/Constants.ets';
import {Constants} from '../model/common/Constants';
import {TraceControllerUtils} from '../utils/TraceControllerUtils';
import {LoadingPanel} from '../../feature/browser/view/photo/components/LoadingPanel'
@Component
export struct PhotoItem {
@ -29,8 +31,7 @@ export struct PhotoItem {
@State matrix: any = Matrix4.identity().copy();
@State direction: PanDirection = PanDirection.Vertical;
@Consume broadCast: BroadCast;
@State transitionId: string = 'null';
@State visible: Visibility = Visibility.Hidden;
@State transitionId: string = PhotoConstants.DEFAULT_TRANSITION_ID;
@State objectFit: ImageFit = ImageFit.Contain;
@State thumbnail: string = '';
@State ratio: number = 1.0;
@ -44,28 +45,40 @@ export struct PhotoItem {
private logger: Logger = new Logger('PhotoItem');
private animationOption: any = null;
private animationEndMatrix: any = null;
@State usePixmap: boolean = true;
private releasePixmap: Function;
@Provide isLoading: boolean = true;
private imgScale: number = 1;
private firstLoad: boolean = true;
private preItem = {rotate: 0, height: 0, width: 0};
onTransitionChange() {
this.logger.info(`onTransitionChange , ${this.updateTransition} ${this.position}`);
if (this.updateTransition == this.position) {
this.transitionId = this.transitionTag + this.item.uri;
this.visible = Visibility.Visible;
this.broadCast.emit(PhotoConstants.PHOTO_SHOW_STATE, [!this.showError]);
} else {
this.transitionId = 'null';
this.visible = Visibility.Hidden;
this.transitionId = PhotoConstants.DEFAULT_TRANSITION_ID;
this.isPullingDown = false;
}
// reset matrix
this.matrix = Matrix4.identity().copy();
this.eventPipeline.reset();
if (this.imgScale != 1) {
this.matrix = Matrix4.identity().scale({
x: this.imgScale,
y: this.imgScale
}).copy();
this.eventPipeline && this.eventPipeline.setDefaultScale(this.imgScale);
} else {
this.matrix = Matrix4.identity().copy();
this.eventPipeline.reset();
}
this.logger.info(`onTransitionChange end`);
}
private aboutToAppear(): void {
aboutToAppear(): void {
this.logger.info(`photoItem aboutToAppear ${this.item.uri}`);
this.eventPipeline = new EventPipeline(this.broadCast, this.item);
this.matrix = Matrix4.identity().copy();
this.firstLoad = true;
this.isLoading = this.updateTransition == this.position;
// register event handling
this.broadCast.on(PhotoConstants.TOUCH_EVENT + this.item.uri, (matrix: any) => {
this.matrix = matrix;
@ -83,38 +96,46 @@ export struct PhotoItem {
});
this.onTransitionChange();
this.onViewDataChanged();
this.logger.info(`photoItem aboutToAppear ${this.item.uri} end`);
}
private aboutToDisappear(): void {
aboutToDisappear(): void {
this.logger.info(`aboutToDisappear ${this.item.uri}`);
// clean up event registration
this.broadCast.off(PhotoConstants.TOUCH_EVENT + this.item.uri, null);
this.broadCast.off(PhotoConstants.DIRECTION_CHANGE + this.item.uri, null);
this.broadCast.off(PhotoConstants.ANIMATION_EVENT + this.item.uri, null);
this.isPullingDown = false;
this.releasePixmap(this.item.uri);
this.logger.info(`aboutToDisappear ${this.item.uri} end`);
}
onViewDataChanged(): void {
this.logger.info(`onViewDataChanged start`);
if ((this.preItem.rotate == this.item.orientation && this.preItem.height == this.item.imgHeight &&
this.preItem.width == this.item.imgWidth) && !this.firstLoad) {
this.preItem.rotate = this.item.orientation;
this.preItem.width = this.item.imgWidth;
this.preItem.height = this.item.imgHeight;
this.eventPipeline && this.eventPipeline.onDataChanged(this.item)
return;
}
if (this.item.orientation == PhotoConstants.ROTATE_ONCE || this.item.orientation == PhotoConstants.ROTATE_THRICE) {
let componentWidth = vp2px(ScreenManager.getInstance().getWinWidth());
let componentHeight = vp2px(ScreenManager.getInstance().getWinHeight());
let widthScale = componentWidth / (this.item.width == 0 ? PhotoConstants.DEFAULT_SIZE : this.item.width);
let heightScale = componentHeight / (this.item.height == 0 ? PhotoConstants.DEFAULT_SIZE : this.item.height);
let widthScale = componentWidth / (this.item.imgWidth == 0 ? PhotoConstants.DEFAULT_SIZE : this.item.imgWidth);
let heightScale = componentHeight / (this.item.imgHeight == 0 ? PhotoConstants.DEFAULT_SIZE : this.item.imgHeight);
let screenScale = widthScale > heightScale ? heightScale : widthScale;
let reWidthScale = componentWidth / (this.item.height == 0 ? PhotoConstants.DEFAULT_SIZE : this.item.height);
let reHeightScale = componentHeight / (this.item.width == 0 ? PhotoConstants.DEFAULT_SIZE : this.item.width);
let reWidthScale = componentWidth / (this.item.imgHeight == 0 ? PhotoConstants.DEFAULT_SIZE : this.item.imgHeight);
let reHeightScale = componentHeight / (this.item.imgWidth == 0 ? PhotoConstants.DEFAULT_SIZE : this.item.imgWidth);
let reScale = reWidthScale > reHeightScale ? reHeightScale : reWidthScale;
let scale = screenScale / reScale;
this.imgScale = scale;
this.matrix = Matrix4.identity().scale({
x: scale,
y: scale
}).copy();
this.logger.debug(`onViewDataChanged scale:${scale}, componentSize:${componentWidth}x${componentHeight}\
width: ${this.item.width}, height: ${this.item.height}`);
width: ${this.item.imgWidth}, height: ${this.item.imgHeight}`);
this.eventPipeline && this.eventPipeline.setDefaultScale(scale);
} else {
this.matrix = Matrix4.identity().copy();
@ -122,31 +143,20 @@ export struct PhotoItem {
this.eventPipeline && this.eventPipeline.setDefaultScale(1);
}
this.eventPipeline && this.eventPipeline.onDataChanged(this.item)
this.logger.debug(`onViewDataChanged usePixmap:${this.usePixmap}, thumbnail:${JSON.stringify(this.thumbnail)}`);
}
getVideoPlayIcon() {
if (vp2px(Constants.NUMBER_1) >= Constants.NUMBER_1 && vp2px(Constants.NUMBER_1) < Constants.NUMBER_2) {
return $r('app.media.ic_video_play_btn_hdpi')
} else if (vp2px(Constants.NUMBER_1) == Constants.NUMBER_2) {
return $r('app.media.ic_video_play_btn_xhdpi')
} else if (vp2px(Constants.NUMBER_1) == Constants.NUMBER_3) {
return $r('app.media.ic_video_play_btn_xxhdpi')
} else {
return $r('app.media.ic_video_play_btn_xxxhdpi')
}
this.firstLoad = false;
this.preItem.rotate = this.item.orientation;
this.preItem.width = this.item.imgWidth;
this.preItem.height = this.item.imgHeight;
this.logger.debug(`onViewDataChanged thumbnail:${JSON.stringify(this.thumbnail)}`);
}
build() {
Stack() {
Image('placeholder')
.visibility(Visibility.Hidden)
.onComplete(() => {
this.eventPipeline.onComponentSizeChanged();
})
.onError(() => {
this.eventPipeline.onComponentSizeChanged();
})
Column() {
LoadingPanel()
}
.width('100%')
.height('100%')
Flex({
direction: FlexDirection.Row,
alignItems: ItemAlign.Center,
@ -157,14 +167,23 @@ export struct PhotoItem {
.rotate({ x: 0, y: 0, z: 1, angle: this.item.orientation })
.transform(this.matrix)
.autoResize(false)
// .sharedTransition(this.transitionId, {duration: PhotoConstants.SHARE_TRANSITION_DURATION}) TODO: delete dynamic effect
.onComplete(() => {
TraceControllerUtils.startTrace(`PhotoItemComplete_${this.position}`);
this.logger.debug(`onComplete finish index: ${this.position}, uri: ${this.item.uri}`);
this.showError = false;
this.isLoading = false;
if (this.updateTransition == this.position) {
this.broadCast.emit(PhotoConstants.PHOTO_SHOW_STATE, [true]);
}
TraceControllerUtils.finishTrace(`PhotoItemComplete_${this.position}`);
})
.onError(() => {
this.logger.debug(`image show error`);
this.logger.error(`image show error`);
this.showError = true;
this.isLoading = true;
if (this.updateTransition == this.position) {
this.broadCast.emit(PhotoConstants.PHOTO_SHOW_STATE, [false]);
}
})
}
.width('100%')
@ -285,8 +304,6 @@ export struct PhotoItem {
)
)
.clip(true)
.width('100%')
.height('100%')
.onTouch((event) => {
this.eventPipeline.onTouch(event);
})
@ -303,7 +320,7 @@ export struct PhotoItem {
}.margin({top: (this.item.mediaType == MediaLibraryAccess.MEDIA_TYPE_VIDEO) ? $r('app.float.input_text_notify_margin') : 0})
}
Row() {
Image(this.getVideoPlayIcon()).objectFit(ImageFit.Contain).width($r('app.float.icon_video_size'))
Image($r('app.media.ic_video_play_btn_png')).objectFit(ImageFit.Contain).width($r('app.float.icon_video_size'))
.height($r('app.float.icon_video_size')).onClick(() => {
if (this.item != undefined) {
router.push({
@ -315,9 +332,11 @@ export struct PhotoItem {
}
})
}
}).visibility(this.isPullingDown ? Visibility.None : this.isVideoPlayBtnShow())
}).visibility(this.isVideoPlayBtnShow())
}
}
}.width('100%')
.height('100%')
.sharedTransition(this.transitionId, {duration: PhotoConstants.SHARE_TRANSITION_DURATION})
}
isVideoPlayBtnShow(): Visibility {

View File

@ -13,10 +13,12 @@
* limitations under the License.
*/
import {PhotoItem} from './PhotoItem.ets'
import {BroadCastConstants} from '../model/common/BroadCastConstants.ets';
import {Logger} from '../../feature/browser/utils/Logger.ets';
import {BroadCast} from '../utils/BroadCast.ets';
import {PhotoItem} from './PhotoItem'
import {BroadCastConstants} from '../model/common/BroadCastConstants';
import {Logger} from '../../feature/browser/utils/Logger';
import {BroadCast} from '../utils/BroadCast';
import {Constants} from '../model/common/Constants';
import {Constants as PhotoConstants} from '../../common/model/browser/photo/Constants'
@Component
export struct PhotoSwiper {
@ -25,14 +27,16 @@ export struct PhotoSwiper {
transition: string;
@Consume currentIndex: number;
@Consume broadCast: BroadCast;
@Consume canSwipe: boolean;
@State duration: number = 400;
onPhotoChanged: Function;
onReleasePixmap: Function;
swiperController: SwiperController;
aboutToAppear() {
this.broadCast.on(BroadCastConstants.ON_DATA_RELOADED, () => {
this.logger.debug('animate to data reloaded start');
animateTo({
duration: Constants.DELETE_ANIMATE_DURATION,
onFinish: () => {
let totalCount = this.dataSource.totalCount();
this.dataSource.onDataChanged(this.currentIndex);
@ -48,6 +52,11 @@ export struct PhotoSwiper {
this.dataSource.deleteData(this.currentIndex);
})
});
this.broadCast.on(BroadCastConstants.CHANGE_SWIPER_DURATION, (value) => {
this.logger.debug(`change duration start ${value}`);
this.duration = value;
});
}
build() {
@ -59,18 +68,23 @@ export struct PhotoSwiper {
position: item.pos,
thumbnail: item.thumbnail,
transitionId: (item.pos == this.currentIndex && this.transition != undefined)
? (this.transition + item.data.uri) : 'null',
transitionTag: this.transition ? this.transition : 'null',
releasePixmap: this.onReleasePixmap
? (this.transition + item.data.uri) : PhotoConstants.DEFAULT_TRANSITION_ID,
transitionTag: this.transition ? this.transition : PhotoConstants.DEFAULT_TRANSITION_ID,
})
}
}.zIndex(item.pos == this.currentIndex ? 2 : 1)
}, (item) => item.data.uri)
}
.gesture(PanGesture({
direction: PanDirection.Horizontal
}))
.index(this.currentIndex)
.indicator(false)
.loop(false)
.onChange((index: number) => {
this.onPhotoChanged(index);
if (this.duration != 0) {
this.onPhotoChanged(index);
}
})
.disableSwipe(this.canSwipe)
}
}

View File

@ -13,12 +13,17 @@
* limitations under the License.
*/
import {Logger} from '../utils/Logger.ets'
import {TabItem, TabItemWithText} from '../model/common/TabItem.ets'
import {Logger} from '../utils/Logger'
import {TabItem, TabItemWithText} from '../model/common/TabItem'
import {BroadCastManager} from '../model/common/BroadCastManager'
import {BroadCast} from '../utils/BroadCast'
import {BroadCastConstants} from '../model/common/BroadCastConstants'
import {Constants} from '../model/common/Constants.ets'
import {Constants} from '../model/common/Constants'
export enum DEVICE_TYPE {
DEVICE_PHONE,
DEVICE_PAD
}
@Component
export struct TabBar {
@ -30,8 +35,9 @@ export struct TabBar {
private controller: TabsController;
private logger: Logger = new Logger('TabBar');
private appBroadCast: BroadCast = BroadCastManager.getInstance().getBroadCast();
deviceType: DEVICE_TYPE = DEVICE_TYPE.DEVICE_PHONE;
private aboutToAppear(): void {
aboutToAppear(): void {
this.onTabSelected = this.onTabSelected.bind(this);
this.tabs[this.currentIndex].isSelected = true;
this.tabs.forEach((tab: TabItem) => {this.logger.info(`${JSON.stringify(tab.name)} , ${tab.iconSelected}`)});
@ -59,10 +65,17 @@ export struct TabBar {
alignItems: ItemAlign.Center,
justifyContent: FlexAlign.Center
}) {
ForEach(this.tabs, (tab: TabItem) => {
Tab({ tabItem: tab, index: this.tabs.indexOf(tab), onTabSelected: this.onTabSelected })
}, tab => tab.name.id)
Column() {
ForEach(this.tabs, (tab: TabItem) => {
Stack() {
Tab({ tabItem: tab, index: this.tabs.indexOf(tab), onTabSelected: this.onTabSelected })
}.layoutWeight(1)
}, tab => tab.name.id)
}
.height(DEVICE_TYPE.DEVICE_PAD == this.deviceType ? $r('app.float.horizontal_width') : '100%')
}
.markAnchor({x: '0%', y: '0%'})
.position({x: '0%', y: '0%'})
.width($r('app.float.tab_bar_width'))
.backgroundColor($r('app.color.default_background_color'))
} else {
@ -72,7 +85,9 @@ export struct TabBar {
justifyContent: FlexAlign.Center
}) {
ForEach(this.tabs, (tab: TabItem) => {
Tab({ tabItem: tab, index: this.tabs.indexOf(tab), onTabSelected: this.onTabSelected })
Stack() {
Tab({ tabItem: tab, index: this.tabs.indexOf(tab), onTabSelected: this.onTabSelected })
}.layoutWeight(1)
}, tab => tab.name.id)
}
.markAnchor({x: '0%', y: '100%'})
@ -102,7 +117,6 @@ struct Tab {
.height($r('app.float.icon_size'))
.width($r('app.float.icon_size'))
.objectFit(ImageFit.Fill)
.fillColor(this.tabItem.getConditionIcon(this.tabItem.isSelected))
}
Text(this.tabItem.name)
@ -115,7 +129,6 @@ struct Tab {
left: $r('app.float.tab_bar_text_padding_horizontal')
})
}
.layoutWeight(1)
.onClick(() => {
this.onTabSelected && this.onTabSelected(this.index);
this.tabItem.isSelected = true;
@ -132,7 +145,7 @@ export struct TabBarForAlbumSet {
private controller: TabsController;
private logger: Logger = new Logger('TabBarForAlbumSet');
private aboutToAppear(): void {
aboutToAppear(): void {
this.onTabSelected = this.onTabSelected.bind(this);
this.tabs[this.currentIndex].isSelected = true;
this.tabs.forEach((tab: TabItemWithText) => {
@ -179,7 +192,7 @@ struct TabWithText {
onTabSelected: Function;
private logger: Logger = new Logger('TabWithText');
private aboutToAppear(): void {
aboutToAppear(): void {
// Determine the length of the underline based on the font length
if (this.index == 0) {
this.TabWidth = px2vp(fp2px(Constants.TEXT_SIZE_SUB_TITLE2)) * 2;

View File

@ -13,12 +13,12 @@
* limitations under the License.
*/
import {Action} from '../model/browser/operation/Action.ets'
import {ActionBar} from './actionbar/ActionBar.ets'
import {ActionBarProp} from '../model/browser/operation/ActionBarProp.ets'
import {ActionBarMode, ActionBarColorMode, ActionBarSelectionMode} from '../model/browser/operation/ActionBarMode.ets'
import {Logger} from '../utils/Logger.ets'
import {ScreenManager} from '../model/common/ScreenManager.ets';
import {Action} from './browserOperation/Action'
import {ActionBar} from './actionbar/ActionBar'
import {ActionBarProp} from './browserOperation/ActionBarProp'
import {ActionBarMode, ActionBarColorMode, ActionBarSelectionMode} from './browserOperation/ActionBarMode'
import {Logger} from '../utils/Logger'
import {ScreenManager} from '../model/common/ScreenManager';
@Component
export struct ThirdSelectPhotoBrowserActionBar {
@ -37,7 +37,7 @@ export struct ThirdSelectPhotoBrowserActionBar {
.setLeftAction(Action.BACK)
.setMode(ActionBarMode.SELECTION_MODE)
.setSelectionMode(this.isMultiPick ? ActionBarSelectionMode.MULTI : ActionBarSelectionMode.SINGLE)
.setColorMode(ActionBarColorMode.NORMAL)
.setColorMode(ActionBarColorMode.TRANSPARENT)
.setAlpha(ActionBarProp.PHOTO_BROWSER_ACTIONBAR_ALPHA)
.setMenuList(menuList);
return actionBarProp;
@ -45,6 +45,8 @@ export struct ThirdSelectPhotoBrowserActionBar {
build() {
Stack({ alignContent: Alignment.TopStart }) {
Image($r('app.media.gradientBasePlate')).width('100%')
.height('100%').objectFit(ImageFit.Fill)
ActionBar({
isShowBar: true,
actionBarProp: this.createActionBar(),

View File

@ -13,19 +13,19 @@
* limitations under the License.
*/
import {Logger} from '../../utils/Logger.ets'
import {ActionBarProp} from '../../model/browser/operation/ActionBarProp.ets'
import {Action} from '../../model/browser/operation/Action.ets'
import {ActionBarMode} from '../../model/browser/operation/ActionBarMode.ets'
import {SingleTitle} from './SingleTitle.ets'
import {DetailTitle} from './DetailTitle.ets'
import {SelectionTitle} from './SelectionTitle.ets'
import {MenuPanel} from './MenuPanel.ets'
import {DetailMenuPanel} from './DetailMenuPanel.ets'
import {Constants} from '../../model/common/Constants.ets'
import {ActionBarButton} from './ActionBarButton.ets'
import {Logger} from '../../utils/Logger'
import {ActionBarProp} from '../browserOperation/ActionBarProp'
import {Action} from '../browserOperation/Action'
import {ActionBarMode} from '../browserOperation/ActionBarMode'
import {SingleTitle} from './SingleTitle'
import {DetailTitle} from './DetailTitle'
import {SelectionTitle} from './SelectionTitle'
import {MenuPanel} from './MenuPanel'
import {DetailMenuPanel} from './DetailMenuPanel'
import {Constants} from '../../model/common/Constants'
import {ActionBarButton} from './ActionBarButton'
// ActionBarIt consists of action on the left, title in the middle and menupanel on the right
// ActionBarIt consists of action on the left, title in the middle and menu panel on the right
@Component
export struct ActionBar {
@State isShowBar: boolean = true;
@ -33,6 +33,7 @@ export struct ActionBar {
onMenuClicked: Function;
logger: Logger = new Logger('ActionBar');
isVideoPage: boolean = false;
@State hasTabBar: boolean = this.actionBarProp.getHasTabBar();
private onBuildDone(): void {
this.logger.info(`onBuildDone,actionBarProp:${this.actionBarProp.getHasTabBar()}, isShowBar:${this.isShowBar}`);
@ -57,13 +58,19 @@ export struct ActionBar {
if (this.actionBarProp.getMode() === ActionBarMode.DETAIL_MODE) {
DetailMenuPanel({ actionBarProp: this.actionBarProp, onMenuClicked: this.onMenuClicked, isLeft: true })
} else if (this.actionBarProp.getMode() === ActionBarMode.SELECTION_MODE) {
SelectionTitle({ actionBarProp: this.actionBarProp })
Stack({alignContent: Alignment.Start}) {
SelectionTitle({ actionBarProp: this.actionBarProp })
}.flexGrow(1)
MenuPanel({ actionBarProp: this.actionBarProp, onMenuClicked: this.onMenuClicked })
} else if (this.actionBarProp.getMode() === ActionBarMode.TOP_MODE) {
DetailTitle({isVideoPage: this.isVideoPage})
Stack({alignContent: Alignment.Start}) {
DetailTitle({isVideoPage: this.isVideoPage})
}.flexGrow(1)
DetailMenuPanel({ actionBarProp: this.actionBarProp, onMenuClicked: this.onMenuClicked, isLeft: false })
} else {
SingleTitle({ actionBarProp: this.actionBarProp })
Stack({ alignContent: Alignment.Start }) {
SingleTitle({ actionBarProp: this.actionBarProp })
}.flexGrow(1)
MenuPanel({ actionBarProp: this.actionBarProp, onMenuClicked: this.onMenuClicked })
}
}
@ -73,7 +80,7 @@ export struct ActionBar {
.backgroundColor(this.actionBarProp.getBackgroundColor())
.opacity(this.actionBarProp.getAlpha())
.padding({ right: $r('app.float.default_actionbar_padding_right'),
left: (this.actionBarProp.getHasTabBar() ?
left: (this.hasTabBar ?
$r('app.float.default_padding_start_with_tab_bar') :
$r('app.float.default_actionbar_padding_start_without_tab_bar'))
})

View File

@ -13,10 +13,10 @@
* limitations under the License.
*/
import {Action} from '../../model/browser/operation/Action.ets'
import {ActionBarColorMode} from '../../model/browser/operation/ActionBarMode.ets'
import {ScreenManager, ColumnSize} from '../../model/common/ScreenManager.ets';
import {Constants} from '../../model/common/Constants.ets';
import {Action} from '../browserOperation/Action'
import {ActionBarColorMode} from '../browserOperation/ActionBarMode'
import {ScreenManager, ColumnSize} from '../../model/common/ScreenManager';
import {Constants} from '../../model/common/Constants';
@Component
export struct ActionBarButton {
@ -31,40 +31,36 @@ export struct ActionBarButton {
@State showPopup: boolean = false
@Consume moreMenuList: Action[];
private aboutToAppear(): void {}
aboutToAppear(): void {}
@Builder PopupBuilder() {
Column() {
ForEach(this.moreMenuList, (menu: Action) => {
Text(menu.textRes)
.width(ScreenManager.getInstance().getColumnsWidth(ColumnSize.COLUMN_TWO))
.width('100%')
.height($r('app.float.menu_height'))
.fontColor(menu.fillColor)
.fontSize($r('sys.float.ohos_id_text_size_body1'))
.onClick(() => {
this.showPopup = false;
this.onMenuClicked && this.onMenuClicked(menu);
})
if (this.moreMenuList.indexOf(menu) != this.moreMenuList.length - 1) {
Divider()
.width(ScreenManager.getInstance().getColumnsWidth(ColumnSize.COLUMN_TWO))
.width('100%')
.strokeWidth(Constants.MENU_DIVIDER_STROKE_WIDTH)
.color($r('sys.color.ohos_id_color_list_separator'))
}
}, menu => (menu.actionType != null ? menu.actionType.id : menu.actionID))
}
}.width(ScreenManager.getInstance().getColumnsWidth(ColumnSize.COLUMN_TWO))
.borderRadius($r('sys.float.ohos_id_corner_radius_default_l'))
.padding({
top: $r('app.float.menu_padding_vertical'),
bottom: $r('app.float.menu_padding_vertical'),
left: $r('app.float.menu_padding_horizontal'),
right: $r('app.float.menu_padding_horizontal')
})
.backgroundColor(Color.White)
.margin({
right: this.isHorizontal ? $r('app.float.menu_horizontal_margin_right') : $r('app.float.menu_margin_right'),
bottom: this.isHorizontal ? 0 : $r('app.float.menu_margin_bottom'),
top: this.isHorizontal ? $r('app.float.menu_horizontal_margin_top') : 0
.padding({
top: $r('app.float.menu_padding_vertical'),
bottom: $r('app.float.menu_padding_vertical'),
left: $r('app.float.menu_padding_horizontal'),
right: $r('app.float.menu_padding_horizontal')
})
.backgroundColor(Color.White)
}
@Builder ActionBarButtonBuilder() {
@ -75,12 +71,14 @@ export struct ActionBarButton {
}) {
if (this.isAutoTint) {
Image(this.res)
.commonButtonStyle()
.height($r('app.float.icon_size'))
.width($r('app.float.icon_size'))
.fillColor(this.colorMode == ActionBarColorMode.TRANSPARENT ?
Action.ICON_DEFAULT_COLOR_CONTRARY : this.action.fillColor)
} else {
Image(this.res)
.commonButtonStyle()
.height($r('app.float.icon_size'))
.width($r('app.float.icon_size'))
}
}
.height($r('app.float.default_button_size'))
@ -117,9 +115,4 @@ export struct ActionBarButton {
})
}
}
}
@Extend(Image) function commonButtonStyle () {
.height($r('app.float.icon_size'))
.width($r('app.float.icon_size'))
}

View File

@ -13,10 +13,10 @@
* limitations under the License.
*/
import {Logger} from '../../utils/Logger.ets'
import {ActionBarProp} from '../../model/browser/operation/ActionBarProp.ets'
import {Action} from '../../model/browser/operation/Action.ets'
import {ActionBarButton} from './ActionBarButton.ets'
import {Logger} from '../../utils/Logger'
import {ActionBarProp} from '../browserOperation/ActionBarProp'
import {Action} from '../browserOperation/Action'
import {ActionBarButton} from './ActionBarButton'
// Large picture button for dynamic refresh
@Component
@ -46,6 +46,6 @@ export struct DetailMenuPanel {
colorMode: this.actionBarProp.getColorMode()
})
}, menu => (menu.actionType ? menu.actionType.id : menu.actionID))
}.padding({ right: $r('app.float.default_actionbar_padding_right') })
}.alignItems(VerticalAlign.Center)
}
}

View File

@ -13,8 +13,8 @@
* limitations under the License.
*/
import {Logger} from '../../utils/Logger.ets'
import {ActionBarProp} from '../../model/browser/operation/ActionBarProp.ets'
import {Logger} from '../../utils/Logger'
import {ActionBarProp} from '../browserOperation/ActionBarProp'
// Large picture title, including primary date title and secondary time and place title
@Component
@ -42,15 +42,14 @@ export struct DetailTitle {
.fontFamily(ActionBarProp.REGULAR_FONT)
.fontColor(this.isVideoPage ? $r('app.color.white') : ActionBarProp.NORMAL_SUBTITLE_TEXT_COLOR)
.maxLines(1)
.lineHeight(18)
.lineHeight('app.float.detail_sub_title_max_lines')
.margin({ top: $r('sys.float.ohos_id_text_margin_vertical') })
.textOverflow({ overflow: TextOverflow.Ellipsis })
}
.constraintSize({ minHeight: 48 })
.constraintSize({ minHeight: ('app.float.detail_title_constraint_size_min_height') })
.alignItems(HorizontalAlign.Start)
}.margin({ left: $r('app.float.actionbar_title_margin'),
right: $r('app.float.actionbar_title_margin') })
.flexGrow(1)
.alignItems(VerticalAlign.Center)
}
}

View File

@ -13,10 +13,10 @@
* limitations under the License.
*/
import {Logger} from '../../utils/Logger.ets'
import {ActionBarProp} from '../../model/browser/operation/ActionBarProp.ets'
import {Action} from '../../model/browser/operation/Action.ets'
import {ActionBarButton} from './ActionBarButton.ets'
import {Logger} from '../../utils/Logger'
import {ActionBarProp} from '../browserOperation/ActionBarProp'
import {Action} from '../browserOperation/Action'
import {ActionBarButton} from './ActionBarButton'
// MenuPanelRight menu button panel
@Component
@ -26,7 +26,7 @@ export struct MenuPanel {
onMenuClicked: Function;
logger: Logger = new Logger('MenuPanel');
private aboutToAppear(): void {
aboutToAppear(): void {
this.logger.info('aboutToAppear.');
this.onActionBarPropChanged();
}
@ -57,9 +57,5 @@ export struct MenuPanel {
}, menu => (menu.actionType ? menu.actionType.id : menu.actionID))
}
.alignItems(VerticalAlign.Center)
.margin(
{
right: $r('app.float.default_actionbar_padding_right')
})
}
}

View File

@ -13,9 +13,9 @@
* limitations under the License.
*/
import {ActionBarColorMode, ActionBarSelectionMode} from '../../model/browser/operation/ActionBarMode'
import {Logger} from '../../utils/Logger.ets'
import {ActionBarProp} from '../../model/browser/operation/ActionBarProp.ets'
import {ActionBarColorMode, ActionBarSelectionMode} from '../browserOperation/ActionBarMode'
import {Logger} from '../../utils/Logger'
import {ActionBarProp} from '../browserOperation/ActionBarProp'
// Select the mode title, the content changes with the number of selections
@Component
@ -47,6 +47,5 @@ export struct SelectionTitle {
.margin({ left: $r('app.float.actionbar_title_margin'),
right: $r('app.float.actionbar_title_margin') })
.alignItems(VerticalAlign.Center)
.flexGrow(1)
}
}

View File

@ -13,8 +13,9 @@
* limitations under the License.
*/
import {Logger} from '../../utils/Logger.ets'
import {ActionBarProp} from '../../model/browser/operation/ActionBarProp.ets'
import {Logger} from '../../utils/Logger'
import {ActionBarProp} from '../browserOperation/ActionBarProp'
import {Action} from '../browserOperation/Action';
// Single line title, fixed content
@Component
@ -30,16 +31,18 @@ export struct SingleTitle {
Row() {
Text(this.actionBarProp.getTitle())
.fontSize(this.actionBarProp.getIsHeadTitle()
? ActionBarProp.HEAD_TITLE_TEXT_SIZE : ActionBarProp.TITLE_TEXT_SIZE)
? ActionBarProp.HEAD_TITLE_ONE_LINE_TEXT_SIZE : ActionBarProp.TITLE_TEXT_SIZE)
.fontWeight(FontWeight.Bold)
.fontColor(ActionBarProp.NORMAL_TEXT_COLOR)
.maxLines(2)
.textOverflow({ overflow: TextOverflow.Ellipsis })
}
.width('80%')
.alignItems(VerticalAlign.Center)
.flexGrow(1)
.padding({
left: $r('app.float.default_actionbar_padding_start_without_tab_bar')
left: this.actionBarProp.getLeftAction().equals(Action.NONE) ?
$r('app.float.default_actionbar_padding_start_without_tab_bar') :
$r('app.float.actionbar_title_margin')
})
}
}

View File

@ -13,12 +13,12 @@
* limitations under the License.
*/
import {ScreenManager,ColumnSize} from '../../model/common/ScreenManager.ets'
import {ScreenManager,ColumnSize} from '../../model/common/ScreenManager'
import {ToolBarButton} from './ToolBarButton'
import {Constants} from '../../model/common/Constants.ets'
import {ActionBarProp} from '../../model/browser/operation/ActionBarProp.ets'
import {Action} from '../../model/browser/operation/Action.ets'
import {ActionBarMode} from '../../model/browser/operation/ActionBarMode.ets'
import {Constants} from '../../model/common/Constants'
import {ActionBarProp} from '../browserOperation/ActionBarProp'
import {Action} from '../browserOperation/Action'
import {ActionBarMode} from '../browserOperation/ActionBarMode'
export class MenuItem {
value: string;
@ -48,7 +48,7 @@ export struct ToolBar {
return actionBarProp;
}
private aboutToAppear(): void {
aboutToAppear(): void {
this.actionBarProp = this.createActionBar();
}
@ -56,22 +56,23 @@ export struct ToolBar {
Column() {
ForEach(this.moreMenuList, (menu: Action) => {
Text(menu.textRes)
.width(ScreenManager.getInstance().getColumnsWidth(ColumnSize.COLUMN_TWO))
.width('100%')
.height($r('app.float.menu_height'))
.fontColor(menu.fillColor)
.fontSize($r('sys.float.ohos_id_text_size_body1'))
.onClick(() => {
this.showPopup = false;
this.onMenuClicked && this.onMenuClicked(menu);
})
if (this.moreMenuList.indexOf(menu) != this.moreMenuList.length - 1) {
Divider()
.width(ScreenManager.getInstance().getColumnsWidth(ColumnSize.COLUMN_TWO))
.width('100%')
.strokeWidth(Constants.MENU_DIVIDER_STROKE_WIDTH)
.color($r('sys.color.ohos_id_color_list_separator'))
}
}, menu => (menu.actionType != null ? menu.actionType.id : menu.actionID))
}
}.width(ScreenManager.getInstance().getColumnsWidth(ColumnSize.COLUMN_TWO))
.borderRadius($r('sys.float.ohos_id_corner_radius_default_l'))
.padding({
top: $r('app.float.menu_padding_vertical'),
@ -80,93 +81,90 @@ export struct ToolBar {
right: $r('app.float.menu_padding_horizontal')
})
.backgroundColor(Color.White)
.offset({x : $r('app.float.bind_popup_margin_x'), y: $r('app.float.bind_popup_margin_y')})
}
build() {
if (this.isShowBar) {
Row() {
Row() {
Row() {
ForEach(this.toolMenuList, (menu: Action) => {
if (menu == Action.MORE) {
Column() {
Row() {
ToolBarButton({
res: menu.iconRes,
action: menu,
isLeft: true,
isAutoTint: menu.isAutoTint,
colorMode: this.actionBarProp.getColorMode()
})
}.margin({ top: $r('app.float.id_icon_margin_vertical') })
Row() {
Text(menu.textRes)
.fontSize($r('sys.float.ohos_id_text_size_caption'))
.fontFamily($r('app.string.id_text_font_family_regular'))
.fontColor(menu.fillColor)
}.margin({ top: $r('sys.float.ohos_id_text_margin_vertical') })
}
.width(`${100/this.toolMenuList.length}%`)
.height('100%')
.onClick(() => {
this.showPopup = !this.showPopup
})
.bindPopup(this.showPopup, {
builder: this.PopupBuilder,
placement: Placement.Top,
maskColor: 0x33000000,
popupColor: '#00FFFFFF',
enableArrow: false,
onStateChange: (e) => {
if (!e.isVisible) {
this.showPopup = false
}
}
ForEach(this.toolMenuList, (menu: Action) => {
if (menu == Action.MORE) {
Column() {
Row() {
ToolBarButton({
res: menu.iconRes,
action: menu,
isLeft: true,
isAutoTint: menu.isAutoTint,
colorMode: this.actionBarProp.getColorMode()
})
}.margin({ top: $r('app.float.id_icon_margin_vertical') })
} else {
Column() {
Row() {
ToolBarButton({
res: menu.iconRes,
action: menu,
isLeft: true,
isAutoTint: menu.isAutoTint,
colorMode: this.actionBarProp.getColorMode()
})
}.margin({ top: $r('app.float.id_icon_margin_vertical') })
Row() {
Text(menu.textRes)
.fontSize($r('sys.float.ohos_id_text_size_caption'))
.fontFamily($r('app.string.id_text_font_family_regular'))
.fontColor(menu.fillColor)
}
.margin({ top: $r('sys.float.ohos_id_text_margin_vertical') })
}
.onClick(() => {
this.onMenuClicked && this.onMenuClicked(menu)
})
.width(`${100/this.toolMenuList.length}%`)
.height('100%')
Row() {
Text(menu.textRes)
.fontSize($r('sys.float.ohos_id_text_size_caption'))
.fontFamily($r('app.string.id_text_font_family_regular'))
.fontColor(menu.fillColor)
}.margin({ top: $r('sys.float.ohos_id_text_margin_vertical') })
}
}, menu => (menu.actionType != null ? menu.actionType.id : menu.actionID))
}
.width('100%')
.height(Constants.ActionBarHeight)
.padding(this.toolMenuList.length > 4 ? {} : {left: $r('app.float.actionbar_margin_horizontal'),
right: $r('app.float.actionbar_margin_horizontal')})
.width(`${Constants.PERCENT_HUNDRED / this.toolMenuList.length}%`)
.height('100%')
.onClick(() => {
this.showPopup = !this.showPopup
})
.bindPopup(this.showPopup, {
builder: this.PopupBuilder,
placement: Placement.Top,
maskColor: 0x33000000,
popupColor: '#00FFFFFF',
enableArrow: false,
onStateChange: (e) => {
if (!e.isVisible) {
this.showPopup = false
}
}
})
} else {
Column() {
Row() {
ToolBarButton({
res: menu.iconRes,
action: menu,
isLeft: true,
isAutoTint: menu.isAutoTint,
colorMode: this.actionBarProp.getColorMode()
})
}.margin({ top: $r('app.float.id_icon_margin_vertical') })
Row() {
Text(menu.textRes)
.fontSize($r('sys.float.ohos_id_text_size_caption'))
.fontFamily($r('app.string.id_text_font_family_regular'))
.fontColor(menu.fillColor)
}
.margin({ top: $r('sys.float.ohos_id_text_margin_vertical') })
}
.onClick(() => {
this.onMenuClicked && this.onMenuClicked(menu)
})
.width(`${Constants.PERCENT_HUNDRED / this.toolMenuList.length}%`)
.height('100%')
}
}, menu => (menu.actionType != null ? menu.actionType.id : menu.actionID))
}
.margin({
bottom: this.isFromPhotoBrowser ? this.leftBlank[3] : 0
})
.width('100%')
.backgroundColor(this.actionBarProp.getBackgroundColor())
.opacity(this.actionBarProp.getAlpha())
.visibility(this.isShowBar && !this.isHorizontal ? Visibility.Visible : Visibility.Hidden)
.markAnchor({x: '0%', y: '100%'})
.position({x: '0%', y: '100%'})
.height(Constants.ActionBarHeight)
.padding(this.toolMenuList.length > 4 ? {} : {left: $r('app.float.actionbar_margin_horizontal'),
right: $r('app.float.actionbar_margin_horizontal')})
}
.margin({
bottom: this.isFromPhotoBrowser ? this.leftBlank[3] : 0
})
.width('100%')
.backgroundColor(this.actionBarProp.getBackgroundColor())
.opacity(this.actionBarProp.getAlpha())
.visibility(this.isShowBar && !this.isHorizontal ? Visibility.Visible : Visibility.Hidden)
.markAnchor({x: '0%', y: '100%'})
.position({x: '0%', y: '100%'})
}
}

View File

@ -13,8 +13,8 @@
* limitations under the License.
*/
import {Action} from '../../model/browser/operation/Action.ets'
import {ActionBarColorMode} from '../../model/browser/operation/ActionBarMode.ets'
import {Action} from '../browserOperation/Action'
import {ActionBarColorMode} from '../browserOperation/ActionBarMode'
@Component
export struct ToolBarButton {

View File

@ -39,6 +39,7 @@ enum ActionID {
SHARE,
SHARE_INVALID,
EDIT,
EDIT_INVALID,
MORE,
NEW,
RENAME,
@ -51,7 +52,8 @@ enum ActionID {
COPY_INVALID,
NAVIGATION_ALBUMS,
DOWNLOAD,
DOWNLOAD_INVALID
DOWNLOAD_INVALID,
CLEAR_RECYCLE_INVALID
}
interface ActionOptions {
@ -122,6 +124,14 @@ export class Action {
actionType: $r('app.string.action_delete')
});
public static CLEAR_RECYCLE_INVALID = new Action({
id: ActionID.CLEAR_RECYCLE_INVALID,
iconRes: $r('app.media.ic_gallery_public_delete_line'),
textRes: $r('app.string.action_clear_recycle'),
fillColor: $r('app.color.icon_disabled_color'),
actionType: $r('app.string.action_delete')
});
public static DELETE_INVALID = new Action({
id: ActionID.DELETE_INVALID,
iconRes: $r('app.media.ic_gallery_public_delete_line'),
@ -234,6 +244,13 @@ export class Action {
textRes: $r('app.string.action_edit')
});
public static EDIT_INVALID = new Action({
id: ActionID.EDIT_INVALID,
iconRes: $r('app.media.ic_gallery_public_edit'),
textRes: $r('app.string.action_edit'),
fillColor: $r('app.color.icon_disabled_color')
});
public static MORE = new Action({
id: ActionID.MORE,
iconRes: $r('app.media.ic_gallery_public_more'),
@ -276,23 +293,23 @@ export class Action {
public static MOVE = new Action({
id: ActionID.MOVE,
textRes: $r('app.string.move_to_album')
textRes: $r('app.string.action_move_to_album')
});
public static MOVE_INVALID = new Action({
id: ActionID.MOVE_INVALID,
textRes: $r('app.string.move_to_album'),
textRes: $r('app.string.action_move_to_album'),
fillColor: $r('app.color.icon_disabled_color')
});
public static COPY = new Action({
id: ActionID.COPY,
textRes: $r('app.string.copy_to_album')
textRes: $r('app.string.action_copy_to_album')
});
public static COPY_INVALID = new Action({
id: ActionID.COPY_INVALID,
textRes: $r('app.string.copy_to_album'),
textRes: $r('app.string.action_copy_to_album'),
fillColor: $r('app.color.icon_disabled_color')
});

View File

@ -13,8 +13,8 @@
* limitations under the License.
*/
import {Action} from './Action.ets'
import {ActionBarMode, ActionBarColorMode, ActionBarSelectionMode} from './ActionBarMode.ets'
import {Action} from './Action'
import {ActionBarMode, ActionBarColorMode, ActionBarSelectionMode} from './ActionBarMode'
// ActionBarProp
export class ActionBarProp {
@ -26,12 +26,14 @@ export class ActionBarProp {
public static TRANSPARENT_TEXT_COLOR: Resource = $r('app.color.title_text_color_on_transparent_bg');
public static TRANSPARENT_SUBTITLE_TEXT_COLOR: Resource = $r('app.color.subtitle_text_color_on_transparent_bg');
public static HEAD_TITLE_TEXT_SIZE: Resource = $r('sys.float.ohos_id_text_size_headline6');
public static HEAD_TITLE_ONE_LINE_TEXT_SIZE: Resource = $r('sys.float.ohos_id_text_size_headline7');
public static TITLE_TEXT_SIZE: Resource = $r('sys.float.ohos_id_text_size_headline8');
public static TITLE_FONT_WEIGHT = 500;
public static SUBTITLE_TEXT_SIZE: Resource = $r('sys.float.ohos_id_text_size_body2');
public static MEDIUM_FONT: Resource = $r('app.string.id_text_font_family_medium');
public static REGULAR_FONT: Resource = $r('app.string.id_text_font_family_regular');
public static SINGLE_UNSELECT_TITLE: Resource = $r('app.string.title_select_photos');
public static SINGLE_SELECT_ALBUM_TITLE: Resource = $r('app.string.title_select_album');
public static MULTI_UNSELECT_TITLE: Resource = $r('app.string.title_none_selected');
public static PHOTO_BROWSER_ACTIONBAR_ALPHA = 0.95;
private hasTabBar = false;

View File

@ -13,41 +13,66 @@
* limitations under the License.
*/
import {BroadCast} from '../../utils/BroadCast.ets'
import {Logger} from '../../../feature/browser/utils/Logger.ets';
import {BroadCastConstants} from '../../model/common/BroadCastConstants.ets';
import {AlbumInfo} from '../../model/browser/album/AlbumInfo.ets';
import {BroadCast} from '../../utils/BroadCast'
import {Logger} from '../../../feature/browser/utils/Logger';
import {BroadCastConstants} from '../../model/common/BroadCastConstants';
import {AlbumInfo} from '../../model/browser/album/AlbumInfo';
@Component
export struct AlbumListCard {
@State useAlt: boolean = false
@Consume broadCast: BroadCast;
item: AlbumInfo;
logger: Logger = new Logger('MediaOperationPage');
private aboutToAppear(): void {
aboutToAppear(): void {
this.logger.info(`album mediaSet ${JSON.stringify(this.item)}`);
}
mediaOperation() {
this.broadCast.emit(BroadCastConstants.MEDIA_OPERATION, [this.item.name]);
this.broadCast.emit(BroadCastConstants.MEDIA_OPERATION, [this.item]);
}
showMediaRes(): Resource {
if (this.item.videoCount == 0) {
return $r('app.string.show_photo_num', this.item.count);
return $r('app.plural.show_photo_num', this.item.count, this.item.count);
} else if (this.item.videoCount == this.item.count) {
return $r('app.string.show_video_num', this.item.count);
return $r('app.plural.show_video_num', this.item.count, this.item.count);
} else if (this.item.videoCount == 1) {
return $r('app.plural.show_one_video_with_photo_num', this.item.count - this.item.videoCount,
this.item.count - this.item.videoCount, this.item.videoCount);
} else {
return $r('app.string.show_photo_video_num', this.item.count - this.item.videoCount, this.item.videoCount);
return $r('app.plural.show_multi_video_with_photo_num', this.item.count - this.item.videoCount,
this.item.count - this.item.videoCount, this.item.videoCount)
}
}
build() {
Row() {
Image(this.item.coverUri)
if(this.useAlt) {
Row(){
Image($r('app.media.ic_goto_photos'))
.height($r('app.float.icon_size'))
.width($r('app.float.icon_size'))
.objectFit(ImageFit.Cover)
}
.justifyContent(FlexAlign.Center)
.backgroundColor($r('app.color.default_background_color'))
.borderRadius($r('sys.float.ohos_id_corner_radius_default_s'))
.height($r('app.float.list_card_image_size'))
.width($r('app.float.list_card_image_size'))
.borderRadius($r('sys.float.ohos_id_corner_radius_default_s'))
} else {
Image(this.item.coverUri)
.height($r('app.float.list_card_image_size'))
.width($r('app.float.list_card_image_size'))
.borderRadius($r('sys.float.ohos_id_corner_radius_default_s'))
.onError(() => {
if(this.item.coverUri) {
this.useAlt = true;
}
this.logger.error('alt Image error');
})
}
Column() {
Text(this.item.displayName)
.fontSize($r('sys.float.ohos_id_text_size_body1'))
@ -65,15 +90,10 @@ export struct AlbumListCard {
.padding({
left: $r('app.float.crop_vertical_padding'),
})
Divider().vertical(false).strokeWidth(0.5)
.color($r('sys.color.ohos_id_color_list_separator'))
.position({x: '0%', y: '100%'})
.margin({left: $r('app.float.album_list_card_divider_margin_left')})
}
.alignItems(VerticalAlign.Center)
.width('100%')
.height($r('app.float.list_card_height'))
.backgroundColor($r('sys.color.ohos_id_color_card_bg'))
.onClick(() => {
this.mediaOperation();
})

View File

@ -13,21 +13,23 @@
* limitations under the License.
*/
import {Logger} from '../../../utils/Logger.ets'
import {BroadCastConstants} from '../../common/BroadCastConstants.ets';
import {Logger} from '../../utils/Logger'
import {BroadCastConstants} from '../../model/common/BroadCastConstants';
import {MenuOperationCallback} from './MenuOperationCallback'
import {MenuOperation} from './MenuOperation'
import {MenuContext} from './MenuContext'
import {JumpSourceToMain} from '../../browser/photo/JumpSourceToMain.ets'
import {JumpSourceToMain} from '../../model/browser/photo/JumpSourceToMain'
import {AlbumInfo} from '../../model/browser/album/AlbumInfo';
import router from '@system.router';
import resmgr from '@ohos.resourceManager';
import {UiUtil} from '../../../utils/UiUtil.ets'
import {UiUtil} from '../../utils/UiUtil'
import { AlbumDefine } from '../../model/browser/AlbumDefine'
import {BrowserDataFactory} from '../../interface/BrowserDataFactory'
export class AlbumSetNewMenuOperation implements MenuOperation, MenuOperationCallback {
private menuContext: MenuContext;
private logger: Logger = new Logger('AlbumSetNewMenuOperation');
private defaultAlbumName: string;
private newAlbumDisplayName: string;
private onOperationEnd: Function;
constructor(menuContext: MenuContext) {
@ -45,32 +47,35 @@ export class AlbumSetNewMenuOperation implements MenuOperation, MenuOperationCal
this.defaultAlbumName = '';
try {
let context = globalThis.photosAbilityContext;
let resourceManager = await resmgr.getResourceManager(context);
let resourceManager: resmgr.ResourceManager = await resmgr.getResourceManager(context);
let result = await resourceManager.getString(a.id);
this.defaultAlbumName = result;
this.logger.info(`The display name is ${this.defaultAlbumName}`);
this.newAlbumDisplayName
= this.menuContext.albumSetDataSource.getNewAlbumDefaultName(this.defaultAlbumName);
this.logger.info(`The display name of new album is ${this.newAlbumDisplayName}`);
let newAlbumDisplayName
= this.getNewAlbumDefaultName(this.defaultAlbumName);
this.logger.info(`The display name of new album is ${newAlbumDisplayName}`);
this.confirmCallback = this.confirmCallback.bind(this);
this.cancelCallback = this.cancelCallback.bind(this);
this.menuContext.broadCast.emit(BroadCastConstants.SHOW_NEW_ALBUM_PHOTO_DIALOG,
[this.newAlbumDisplayName, this.confirmCallback, this.cancelCallback]);
[newAlbumDisplayName, this.confirmCallback, this.cancelCallback]);
} catch(e) {
this.logger.info(`The display name e ${e}`);
this.logger.error(`The display name e ${e}`);
}
}
private confirmCallback(displayName: string): void {
private async confirmCallback(displayName: string) {
this.logger.info(`AlbumSet new album confirm and the new name is: ${displayName}`);
let newAlbumInfo = new AlbumInfo('', '', displayName, displayName, 0, '', AlbumDefine.genAlbumRelativePath(displayName))
if (null != displayName && undefined != displayName) {
if (this.menuContext.albumSetDataSource.isRepeatedName(displayName)) {
let dataImpl = BrowserDataFactory.getFeature(BrowserDataFactory.TYPE_ALBUM);
let targetAlbum = await dataImpl.getDataByName(displayName, {relativePath: AlbumDefine.genAlbumRelativePath('', true)})
if (targetAlbum) {
UiUtil.showToast($r('app.string.name_already_use'));
return;
}
this.newAlbumDisplayName = displayName;
}
this.onOperationEnd = this.menuContext.onOperationEnd;
let onOperationStart: Function = this.menuContext.onOperationStart;
@ -79,12 +84,12 @@ export class AlbumSetNewMenuOperation implements MenuOperation, MenuOperationCal
if (this.menuContext.jumpSourceToMain == JumpSourceToMain.ALBUM) {
this.logger.info('go back to photo grid');
this.menuContext.broadCast.emit(BroadCastConstants.MEDIA_OPERATION,
[this.newAlbumDisplayName, this.onCompleted.bind(this)]);
[newAlbumInfo, this.onCompleted.bind(this)]);
} else {
router.push({
uri: 'feature/browser/view/album/AlbumSelect',
params: {
albumName: this.newAlbumDisplayName,
albumInfo: JSON.stringify(newAlbumInfo),
isNewAlbum: true
}
});
@ -105,4 +110,41 @@ export class AlbumSetNewMenuOperation implements MenuOperation, MenuOperationCal
this.logger.error('new album data failed!');
this.onOperationEnd && this.onOperationEnd();
}
private getNewAlbumDefaultName(prefixName : string) : string {
let numbers = [];
for (let i = 0; i < this.menuContext.albumSetDataSource.totalCount(); i++) {
let res = this.menuContext.albumSetDataSource.getData(i).name.match(new RegExp(`^${prefixName}[1-9][0-9]*$`));
if (res != null) {
let number = res[0].match(new RegExp(`[1-9][0-9]*`));
numbers.push(parseInt(number[0]));
}
}
this.logger.debug(`${JSON.stringify(numbers)}`);
if (numbers.length <= 0) {
return `${prefixName}1`;
} else if (numbers.length == 1) {
if (numbers[0] - 1 > 0) {
return `${prefixName}1`;
} else {
return `${prefixName}${numbers[0] + 1}`;
}
}
numbers.sort(function(a, b) { return a - b; });
if (numbers[0] - 1 > 0) {
return `${prefixName}1`;
}
for (let i = 1; i < numbers.length; i++) {
let res = numbers[i - 1] + 1;
if (res < numbers[i]) {
return `${prefixName}${res}`;
}
}
return `${prefixName}${numbers[numbers.length - 1] + 1}`;
}
}

View File

@ -13,14 +13,14 @@
* limitations under the License.
*/
import {Logger} from '../../../utils/Logger.ets'
import {SelectManager} from '../SelectManager'
import {Logger} from '../../utils/Logger'
import {SelectManager} from '../../model/browser/SelectManager'
import {MenuContext} from './MenuContext'
import {BrowserOperationFactory} from '../interface/BrowserOperationFactory.ets'
import { BroadCastConstants } from '../../common/BroadCastConstants.ets';
import {AlbumDefine} from '../../../../common/model/browser/AlbumDefine.ets'
import {ProcessMenuOperation} from './ProcessMenuOperation.ets';
import {MediaOperationType} from '../../common/MediaOperationType'
import {BrowserOperationFactory} from '../../interface/BrowserOperationFactory'
import {BroadCastConstants} from '../../model/common/BroadCastConstants';
import { AlbumDefine } from '../../model/browser/AlbumDefine'
import {ProcessMenuOperation} from './ProcessMenuOperation';
import { TraceControllerUtils } from '../../utils/TraceControllerUtils';
export class BatchDeleteMenuOperation extends ProcessMenuOperation {
@ -49,9 +49,9 @@ export class BatchDeleteMenuOperation extends ProcessMenuOperation {
this.confirmCallback = this.confirmCallback.bind(this);
this.cancelCallback = this.cancelCallback.bind(this);
if (this.menuContext.albumName == AlbumDefine.ALBUM_NAME_RECYCLE) {
if (this.menuContext.albumId == AlbumDefine.ALBUM_ID_RECYCLE) {
this.menuContext.broadCast.emit(BroadCastConstants.SHOW_DELETE_DIALOG,
[$r('app.string.recycleAlbum_delete_message'), this.confirmCallback, this.cancelCallback]);
[$r('app.plural.recycleAlbum_delete_message', this.count), this.confirmCallback, this.cancelCallback]);
} else {
this.menuContext.broadCast.emit(BroadCastConstants.SHOW_DELETE_DIALOG,
[selectManager.isAllSelected ? $r('app.string.recycle_all_files_tips') :
@ -66,6 +66,7 @@ export class BatchDeleteMenuOperation extends ProcessMenuOperation {
return;
}
this.uris = uris;
TraceControllerUtils.finishTrace('Batch delete confirm')
this.processOperation();
}
@ -79,20 +80,38 @@ export class BatchDeleteMenuOperation extends ProcessMenuOperation {
let startIndex = (this.currentBatch - 1) * this.BATCH_SIZE;
let endIndex = this.currentBatch * this.BATCH_SIZE;
let batchUris: string[] = this.uris.slice(startIndex, Math.min(endIndex, this.uris.length));
let operationImpl = BrowserOperationFactory.getFeature(BrowserOperationFactory.TYPE_PHOTO);
if (this.menuContext.albumName == AlbumDefine.ALBUM_NAME_RECYCLE) {
operationImpl.delete(batchUris[0], this);
if (this.menuContext.albumId == AlbumDefine.ALBUM_ID_RECYCLE) {
TraceControllerUtils.startTraceWithTaskId('delete', this.currentBatch)
operationImpl.delete(batchUris[0]).then(() => {
TraceControllerUtils.finishTraceWithTaskId('delete', this.currentBatch)
this.onCompleted()
}).catch((error) => {
this.logger.error(`delete error: ${error}`);
TraceControllerUtils.finishTraceWithTaskId('delete', this.currentBatch)
this.onError();
})
} else {
operationImpl.trash(batchUris[0], this);
TraceControllerUtils.startTraceWithTaskId('trash', this.currentBatch)
operationImpl.trash(batchUris[0], true).then(() => {
TraceControllerUtils.finishTraceWithTaskId('trash', this.currentBatch)
this.onCompleted()
}).catch((error) => {
this.logger.error(`delete error: ${error}`);
TraceControllerUtils.finishTraceWithTaskId('trash', this.currentBatch)
this.onError();
})
}
}
confirmCallback(): void {
this.logger.info('Batch delete confirm');
TraceControllerUtils.startTrace('Batch delete confirm')
// 1. Variable initialization
this.onOperationEnd = this.menuContext.onOperationEnd;
// 2. selectManager gets the URI of the data and starts processing deletion in the callback
if (this.menuContext.albumName == AlbumDefine.ALBUM_NAME_RECYCLE) {
if (this.menuContext.albumId == AlbumDefine.ALBUM_ID_RECYCLE) {
this.menuContext.selectManager.getDeleteSelection(this);
} else {
this.menuContext.selectManager.getSelection(this);

View File

@ -13,22 +13,28 @@
* limitations under the License.
*/
import {Logger} from '../../../utils/Logger.ets'
import {Logger} from '../../utils/Logger'
import {MenuContext} from './MenuContext'
import {ProcessMenuOperation, FindSameOperation} from './ProcessMenuOperation'
import {BroadCastConstants} from '../../common/BroadCastConstants.ets';
import {SelectManager} from '../SelectManager.ets';
import {BrowserOperationFactory} from '../../browser/interface/BrowserOperationFactory.ets'
import {MediaOperationType} from '../../common/MediaOperationType'
import {BroadCastConstants} from '../../model/common/BroadCastConstants';
import {SelectManager} from '../../model/browser/SelectManager'
import {BrowserOperationFactory} from '../../interface/BrowserOperationFactory'
import {MediaOperationType} from '../../model/common/MediaOperationType'
import {AlbumInfo} from '../../model/browser/album/AlbumInfo';
import { AlbumDefine } from '../../model/browser/AlbumDefine'
import { TraceControllerUtils } from '../../utils/TraceControllerUtils';
export class CopyMenuOperation extends ProcessMenuOperation {
logger: Logger = new Logger('CopyMenuOperation');
albumName: string;
displayName: string;
albumInfo: AlbumInfo;
operationImpl = BrowserOperationFactory.getFeature(BrowserOperationFactory.TYPE_PHOTO);
constructor(menuContext: MenuContext) {
super(menuContext);
this.albumName = menuContext.albumName;
this.albumInfo = menuContext.albumInfo;
if (this.menuContext.deviceId){
this.albumInfo = new AlbumInfo('', '', '', '', 0, '', AlbumDefine.genAlbumRelativePath(AlbumDefine.REMOTE_ALBUM_PATH))
}
}
doAction(): void {
@ -68,25 +74,19 @@ export class CopyMenuOperation extends ProcessMenuOperation {
this.callback([mediaItem.uri]);
}
this.logger.info(`this.albumName.displayName, ${this.albumName}`);
this.getAlbumDisplayName(this.albumName).then((displayName) =>{
this.displayName = displayName
if (this.menuContext.deviceId) {
this.menuContext.broadCast.emit(BroadCastConstants.SHOW_PROGRESS_DIALOG,
[$r('app.string.download_progress_message', this.displayName),
MediaOperationType.Copy, this.cancelFunc.bind(this)]);
} else {
this.menuContext.broadCast.emit(BroadCastConstants.SHOW_PROGRESS_DIALOG,
[$r('app.string.copy_progress_message', this.displayName),
MediaOperationType.Copy, this.cancelFunc.bind(this)]);
}
});
if (this.menuContext.deviceId) {
this.menuContext.broadCast.emit(BroadCastConstants.SHOW_PROGRESS_DIALOG,
[$r('app.string.download_progress_message'),
MediaOperationType.Copy, this.cancelFunc.bind(this)]);
} else {
this.menuContext.broadCast.emit(BroadCastConstants.SHOW_PROGRESS_DIALOG,
[$r('app.string.copy_progress_message', this.albumInfo.displayName),
MediaOperationType.Copy, this.cancelFunc.bind(this)]);
}
}
callback(uris: string[]): void {
this.uris = uris;
this.albumName = this.menuContext.albumName;
this.processOperation();
}
@ -99,18 +99,25 @@ export class CopyMenuOperation extends ProcessMenuOperation {
let startIndex = (this.currentBatch - 1) * this.BATCH_SIZE;
let endIndex = this.currentBatch * this.BATCH_SIZE;
let batchUris: string[] = this.uris.slice(startIndex, Math.min(endIndex, this.uris.length));
let operationImpl = BrowserOperationFactory.getFeature(BrowserOperationFactory.TYPE_PHOTO);
if (batchUris[0] == undefined) {
this.onOperateContinue();
return;
}
operationImpl.getExistTargetInTargetAlbum(batchUris[0], this.albumName, this.menuContext.deviceId).then((assets) => {
if (assets) {
if (this.menuContext.deviceId) {
operationImpl.copy(batchUris[0], this.albumName, this, false, this.menuContext.deviceId, true);
return;
}
if (assets.targetAsset.uri == assets.fileAsset.uri) {
this.logger.info(`requestOneBatchOperation ${JSON.stringify(this.albumInfo)}`);
TraceControllerUtils.startTraceWithTaskId('getFileCopyOrMoveInfo', this.currentBatch);
this.getFileCopyOrMoveInfo(batchUris[0], this.albumInfo, this.menuContext.deviceId).then((assets) => {
TraceControllerUtils.finishTraceWithTaskId('getFileCopyOrMoveInfo', this.currentBatch);
if (this.menuContext.deviceId) {
let displayName = assets.sourceAsset.displayName;
let index = displayName.lastIndexOf('.');
displayName = `${displayName.slice(0, index)}${new Date().getTime()}${displayName.slice(index)}`;
this.copy(assets.sourceAsset, null, {mediaType: assets.sourceAsset.mediaType, name: displayName, path: this.albumInfo.relativePath});
return;
}
if (assets.targetAsset) {
if (assets.targetAsset.uri == assets.sourceAsset.uri) {
this.logger.info('copy same fileAsset');
this.onOperateContinue();
return ;
@ -120,12 +127,12 @@ export class CopyMenuOperation extends ProcessMenuOperation {
case FindSameOperation.NONE:
this.menuContext.broadCast.emit(BroadCastConstants.FIND_SAME_FILE_DIALOG,
[assets, this.count, () => {
operationImpl.copy(batchUris[0], this.albumName, this, true, this.menuContext.deviceId);
this.copy(assets.sourceAsset, assets.targetAsset);
}, this.onOperateContinue.bind(this), this.onOperateCancelled.bind(this),
this.setFindSameOperation.bind(this)]);
break;
case FindSameOperation.REPLACE:
operationImpl.copy(batchUris[0], this.albumName, this, true, this.menuContext.deviceId);
this.copy(assets.sourceAsset, assets.targetAsset);
break;
case FindSameOperation.SKIP:
this.onOperateContinue();
@ -135,17 +142,39 @@ export class CopyMenuOperation extends ProcessMenuOperation {
break;
}
} else {
operationImpl.copy(batchUris[0], this.albumName, this, false, this.menuContext.deviceId);
this.copy(assets.sourceAsset, null, {mediaType: assets.sourceAsset.mediaType, name: assets.sourceAsset.displayName, path: this.albumInfo.relativePath});
}
});
}
async copy(source, target, param?){
try{
if(!target){
TraceControllerUtils.startTraceWithTaskId('create', this.currentBatch)
target = await this.operationImpl.create(param);
if(target == null){
this.logger.error(`Target file creat failed when copyFile!`);
this.onError();
return;
}
TraceControllerUtils.finishTraceWithTaskId('create', this.currentBatch);
}
TraceControllerUtils.startTraceWithTaskId('openWriteClose', this.currentBatch)
await this.operationImpl.copy(source, target);
TraceControllerUtils.finishTraceWithTaskId('openWriteClose', this.currentBatch)
this.onCompleted();
}catch(error){
this.logger.error(`copyFile is error ${error}`);
this.onError();
}
}
cancelFunc(): void {
this.logger.info(`progress cancel`);
this.onOperatePause();
let cancelMessage = $r('app.string.copy_cancel_message', this.getExpectProgress().toString());
if (this.menuContext.deviceId) {
if (this.albumInfo.deviceId) {
this.menuContext.broadCast && this.menuContext.broadCast.emit(BroadCastConstants.DOWNLOAD_CANCEL_OPERATE,
[cancelMessage, this.onOperateContinue.bind(this), this.onOperateCancelled.bind(this)]);
} else {
@ -158,15 +187,6 @@ export class CopyMenuOperation extends ProcessMenuOperation {
onOperateContinue(): void {
this.logger.info('Operate Continue');
this.isPause = false;
if (this.menuContext.deviceId) {
this.menuContext.broadCast.emit(BroadCastConstants.SHOW_PROGRESS_DIALOG,
[$r('app.string.download_progress_message', this.displayName),
MediaOperationType.Copy, this.cancelFunc.bind(this)]);
} else {
this.menuContext.broadCast.emit(BroadCastConstants.SHOW_PROGRESS_DIALOG,
[$r('app.string.copy_progress_message', this.displayName),
MediaOperationType.Copy, this.cancelFunc.bind(this)]);
}
this.cyclicOperation();
}
}

View File

@ -14,17 +14,17 @@
*/
import {Logger} from '../../utils/Logger'
import {Action} from '../../model/browser/operation/Action.ets'
import {Action} from './Action'
import {ActionBar} from '../../../common/view/actionbar/ActionBar'
import {ActionBarProp} from '../../model/browser/operation/ActionBarProp'
import {ActionBarMode} from '../../model/browser/operation/ActionBarMode'
import {ScreenManager} from '../../model/common/ScreenManager.ets'
import {ActionBarProp} from './ActionBarProp'
import {ActionBarMode} from './ActionBarMode'
import {ScreenManager} from '../../model/common/ScreenManager'
import {MediaOperationType} from '../../model/common/MediaOperationType'
@Component
export struct MediaOperationActionBar {
@Consume pageType:string;
@Consume loadingFinish: boolean;
onMenuClicked : Function;
logger: Logger = new Logger('MediaOperationActionBar');
@ -33,7 +33,9 @@ export struct MediaOperationActionBar {
private createActionBar(): ActionBarProp {
let menuList: Array<Action> = new Array<Action>();
let actionBarProp: ActionBarProp = new ActionBarProp();
menuList.push(Action.NEW);
if(this.loadingFinish){
menuList.push(Action.NEW);
}
actionBarProp
.setHasTabBar(false)
.setTitle((this.pageType == MediaOperationType.Move) ? $r('app.string.move_to') : $r('app.string.copy_to'))

View File

@ -15,20 +15,22 @@
import {MediaOperationType} from '../../model/common/MediaOperationType'
import {MediaOperationActionBar} from './MediaOperationActionBar'
import {Logger} from '../../utils/Logger'
import {BroadCast} from '../../utils/BroadCast.ets'
import {AlbumSetNewMenuOperation} from '../../model/browser/operation/AlbumSetNewMenuOperation.ets';
import {MenuOperationFactory} from '../../model/browser/interface/MenuOperationFactory.ets';
import {AlbumSetDataSource} from '../../model/browser/album/AlbumSetDataSource.ets';
import {AlbumInfo} from '../../model/browser/album/AlbumInfo.ets';
import {BroadCastConstants} from '../../model/common/BroadCastConstants.ets';
import {AlbumListCard} from './AlbumListCard.ets';
import {BroadCast} from '../../utils/BroadCast'
import {AlbumSetNewMenuOperation} from './AlbumSetNewMenuOperation';
import {MenuOperationFactory} from '../../interface/MenuOperationFactory';
import {AlbumSetDataSource} from '../../model/browser/album/AlbumSetDataSource';
import {AlbumInfo} from '../../model/browser/album/AlbumInfo';
import {BroadCastConstants} from '../../model/common/BroadCastConstants';
import {AlbumListCard} from './AlbumListCard';
import router from '@system.router';
import {MenuContext} from '../../model/browser/operation/MenuContext.ets';
import {Action} from '../../model/browser/operation/Action.ets';
import {JumpSourceToMain} from '../../../common/model/browser/photo/JumpSourceToMain.ets'
import {CustomDialogView} from '../dialog/CustomDialogView.ets';
import {AlbumDefine} from '../../model/browser/AlbumDefine.ets';
import {ScreenManager, ColumnSize} from '../../model/common/ScreenManager.ets';
import {MenuContext} from './MenuContext';
import {Action} from './Action';
import {JumpSourceToMain} from '../../../common/model/browser/photo/JumpSourceToMain'
import {CustomDialogView} from '../dialog/CustomDialogView';
import {AlbumDefine} from '../../model/browser/AlbumDefine';
import {ScreenManager, ColumnSize} from '../../model/common/ScreenManager';
import {BroadCastManager} from '../../model/common/BroadCastManager';
import {Constants} from '../../model/common/Constants';
@Entry
@Component
@ -39,31 +41,38 @@ struct MediaOperationPage {
@Provide pageType: string = MediaOperationType.Move;
@Provide broadCast: BroadCast = new BroadCast();
@Provide moreMenuList: Action[] = new Array<Action>();
@State listCardWidth: number = 200;
@Provide loadingFinish: boolean = false;
@State listCardWidth: number = 0;
scroller: Scroller = new Scroller();
albums: AlbumSetDataSource;
isActive: boolean = false; // Whether the page is in the foreground
logger: Logger = new Logger('MediaOperationPage');
sourceAlbumName: string;
sourceAlbumId: string;
private appBroadCast: BroadCast = BroadCastManager.getInstance().getBroadCast();
private aboutToAppear(): void {
aboutToAppear(): void {
let self = this;
this.albums = new AlbumSetDataSource(this.broadCast);
this.albums = new AlbumSetDataSource(this.broadCast, {moreInfo: true});
this.onActive();
let param = router.getParams();
if (param) {
this.logger.info(`router getParams ${JSON.stringify(param)}`);
this.pageType = param.pageType;
this.sourceAlbumName = param.albumName;
param.pageType && (this.pageType = param.pageType.toString());
param.albumId && (this.sourceAlbumId = param.albumId.toString());
}
this.onMenuClicked = this.onMenuClicked.bind(this);
this.broadCast.on(BroadCastConstants.MEDIA_OPERATION, (albumName: string, completedFunc?: Function) => {
this.broadCast.on(Constants.ON_LOADING_FINISHED, (totalCount) => {
this.loadingFinish = true;
});
this.broadCast.on(BroadCastConstants.MEDIA_OPERATION, (albumInfo: AlbumInfo, completedFunc?: Function) => {
router.back({
uri: '',
params:{
pageType: self.pageType,
albumName: albumName
albumInfo: JSON.stringify(albumInfo)
}
});
completedFunc && completedFunc();
@ -136,7 +145,7 @@ struct MediaOperationPage {
}
}
private onBackPress() {
onBackPress() {
this.logger.info('onBackPress');
router.back({
uri: '',
@ -145,18 +154,40 @@ struct MediaOperationPage {
return true;
}
private isLast(info: AlbumInfo) {
let list = [];
for (let i = 0; i < this.albums.totalCount(); i++) {
let item = this.albums.getData(i);
if (!AlbumDefine.ALBUM_DISABLE_COPY_LIST.has(item.innerId) && item.innerId != this.sourceAlbumId) {
list.push(item);
}
}
return list[list.length - 1].innerId == info.innerId;
}
onPageShow(){
this.appBroadCast.emit(BroadCastConstants.THIRD_ROUTE_PAGE, []);
}
build() {
Column() {
MediaOperationActionBar({onMenuClicked: this.onMenuClicked})
List({scroller: this.scroller}) {
LazyForEach(this.albums, (item:AlbumInfo) => {
LazyForEach(this.albums, (item: AlbumInfo, index) => {
ListItem() {
if (!AlbumDefine.ALBUM_DISABLE_COPY_LIST.has(item.name) && item.name != this.sourceAlbumName) {
AlbumListCard({item: item})
if (!AlbumDefine.ALBUM_DISABLE_COPY_LIST.has(item.id) && item.id != this.sourceAlbumId) {
Column() {
AlbumListCard({item: item})
if (!this.isLast(item)) {
Divider().vertical(false).strokeWidth(1)
.color($r('sys.color.ohos_id_color_list_separator'))
.margin({left: $r('app.float.album_list_card_divider_margin_left')})
}
}
}
}
}, item => item.name)
}, item => item.id)
}
.borderRadius($r('sys.float.ohos_id_corner_radius_default_l'))
.margin({
@ -181,4 +212,10 @@ struct MediaOperationPage {
bottom: this.leftBlank[3]
})
}
pageTransition() {
PageTransitionEnter({ type: RouteType.None, duration: 1 })
.opacity(0)
PageTransitionExit({ type: RouteType.None, duration: 1 })
.opacity(0)
}
}

View File

@ -13,30 +13,31 @@
* limitations under the License.
*/
import {MediaItem} from '../photo/MediaItem.ets'
import {SelectManager} from '../SelectManager.ets'
import {BroadCast} from '../../../utils/BroadCast.ets'
import {AlbumSetDataSource} from '../../../../common/model/browser/album/AlbumSetDataSource.ets'
import {MediaItem} from '../../model/browser/photo/MediaItem'
import {SelectManager} from '../../model/browser/SelectManager'
import {BroadCast} from '../../utils/BroadCast'
import {AlbumSetDataSource} from '../../model/browser/album/AlbumSetDataSource'
import {AlbumInfo} from '../../model/browser/album/AlbumInfo';
export class MenuContext {
mediaItem: MediaItem;
albumName: string;
albumId: string;
selectManager: SelectManager;
onOperationStart: Function;
onOperationEnd: Function;
broadCast: BroadCast
latlng: number[];
jumpSourceToMain: number;
albumSetDataSource: AlbumSetDataSource;
deviceId;
deviceId: string;
albumInfo: AlbumInfo
withMediaItem(mediaItem: MediaItem): MenuContext {
this.mediaItem = mediaItem;
return this;
}
withAlbumName(albumName: string): MenuContext {
this.albumName = albumName;
withAlbumId(albumId: string): MenuContext {
this.albumId = albumId;
return this;
}
@ -60,11 +61,6 @@ export class MenuContext {
return this;
}
withLatlng(latlng: number[]): MenuContext {
this.latlng = latlng;
return this;
}
withJumpSourceToMain(jumpSourceToMain: number): MenuContext {
this.jumpSourceToMain = jumpSourceToMain;
return this;
@ -79,4 +75,9 @@ export class MenuContext {
this.deviceId = deviceId;
return this;
}
withAlbumInfo(albumInfo) {
this.albumInfo = albumInfo;
return this;
}
}

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