mirror of
https://gitee.com/openharmony/applications_photos
synced 2024-11-23 07:00:09 +00:00
Signed-off-by: Fanny <liujuan76@h-partners.com>
Changes to be committed:
This commit is contained in:
parent
d463ea09ca
commit
bc35c9b6b8
23
.gitignore
vendored
23
.gitignore
vendored
@ -1,15 +1,8 @@
|
||||
/node_modules
|
||||
/local.properties
|
||||
/.hvigor
|
||||
/.idea
|
||||
/.deveco
|
||||
**/build
|
||||
*.iml
|
||||
.DS_Store
|
||||
/build
|
||||
/captures
|
||||
.externalNativeBuild
|
||||
/entry/.preview
|
||||
.cxx
|
||||
/package-lock.json
|
||||
/tsconfig.json
|
||||
.idea/*
|
||||
.hvigor/*
|
||||
local.properties
|
||||
.preview/*
|
||||
build/*
|
||||
oh_modules/*
|
||||
signature/hap-sign-tool.jar
|
||||
signature/hapsign-online-plugin.jar
|
||||
|
@ -1,10 +1,24 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2023 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",
|
||||
"vendor": "ohos",
|
||||
"versionCode": 1000000,
|
||||
"versionName": "1.0.0",
|
||||
"icon": "$media:app_icon",
|
||||
"icon": "$media:ohos_gallery",
|
||||
"label": "$string:app_name",
|
||||
"distributedNotificationEnabled": true,
|
||||
"minAPIVersion": 9,
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 6.6 KiB |
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB |
Binary file not shown.
Before Width: | Height: | Size: 16 KiB |
35
OAT.xml
35
OAT.xml
@ -47,36 +47,23 @@
|
||||
|
||||
<configuration>
|
||||
<oatconfig>
|
||||
<policylist>
|
||||
<policy name="projectPolicy" desc="">
|
||||
<policyitem type="copyright" name="Copyright 2015 the original author or authors." path="gradlew" rule="may" group="defaultGroup" filefilter="copyrightPolicyFilter" desc="file generated by development tool"/>
|
||||
<policyitem type="copyright" name="Copyright 2015 the original author or authors." path="gradlew.bat" rule="may" group="defaultGroup" filefilter="copyrightPolicyFilter" desc="file generated by development tool"/>
|
||||
</policy>
|
||||
</policylist>
|
||||
<filefilterlist>
|
||||
<filefilter name="binaryFileTypePolicyFilter" desc="Filters for binary file policies">
|
||||
<filteritem type="filepath" name="demos/.*.png" desc="self developed image"/>
|
||||
<filteritem type="filepath" name="demos/.*.jpg" desc="self developed image"/>
|
||||
<filteritem type="filepath" name="common/.*/src/main/resources/base/media/.*.png" desc="self developed image"/>
|
||||
<filteritem type="filepath" name="common/.*/src/main/js/default/common/image/icon/.*.png" desc="self developed image"/>
|
||||
<filteritem type="filepath" name="common/.*/src/main/js/default/common/image/icon/.*.jpg" desc="self developed image"/>
|
||||
<filteritem type="filepath" name="common/.*/src/main/js/default/common/image/svg/.*.svg" desc="self developed image"/>
|
||||
<filteritem type="filepath" name="entry/src/main/resources/base/media/.*.png" desc="self developed image"/>
|
||||
<filteritem type="filepath" name="entry/src/main/js/default/common/image/icon/.*.png" desc="self developed image"/>
|
||||
<filteritem type="filepath" name="entry/src/main/js/default/common/image/icon/.*.jpg" desc="self developed image"/>
|
||||
<filteritem type="filepath" name="entry/src/main/js/default/common/image/svg/.*.svg" desc="self developed image"/>
|
||||
<filteritem type="filepath" name="features/.*/src/main/resources/base/media/.*.png" desc="self developed image"/>
|
||||
<filteritem type="filepath" name="features/.*/src/main/js/default/common/image/icon/.*.png" desc="self developed image"/>
|
||||
<filteritem type="filepath" name="features/.*/src/main/js/default/common/image/icon/.*.jpg" desc="self developed image"/>
|
||||
<filteritem type="filepath" name="features/.*/src/main/js/default/common/image/svg/.*.svg" desc="self developed image"/>
|
||||
<filteritem type="filepath" name="figures/.*.png" desc="self developed image"/>
|
||||
<filteritem type="filepath" name="AppScope/resources/base/media/.*.png" desc="self developed image"/>
|
||||
<filteritem type="filepath" name="common/src/main/resources/.*.png" desc="self developed image"/>
|
||||
<filteritem type="filepath" name="common/src/main/resources/.*.svg" desc="self developed image"/>
|
||||
<filteritem type="filepath" name="feature/browser/src/resources/base/media/.*.svg" desc="self developed image"/>
|
||||
<filteritem type="filepath" name="product/pad/src/.*.png" desc="self developed image"/>
|
||||
<filteritem type="filepath" name="product/phone/src/.*.png" desc="self developed image"/>
|
||||
<filteritem type="filepath" name="gradle/wrapper/.*.jar" desc="Build Files"/>
|
||||
</filefilter>
|
||||
|
||||
<filefilter name="copyrightPolicyFilter" desc="Filters for copyright header policies">
|
||||
<filteritem type="filename" name="README|README_zh|.*.log|.*.json5|.*.json" desc=""/>
|
||||
<filteritem type="filename" name="*.json5" desc="json file"/>
|
||||
<filteritem type="filename" name="publicity.xml" desc="Build Files"/>
|
||||
</filefilter>
|
||||
<filefilter name="defaultPolicyFilter" desc="Filters for LICENSE file policies">
|
||||
<filteritem type="filename" name="README|README_zh|*.log|*.json5|*.json" desc="json file"/>
|
||||
<filteritem type="filename" name="*.json5" desc="json file"/>
|
||||
<filteritem type="filename" name="publicity.xml" desc="Build Files"/>
|
||||
</filefilter>
|
||||
</filefilterlist>
|
||||
</oatconfig>
|
||||
|
@ -2,15 +2,23 @@
|
||||
"app": {
|
||||
"signingConfigs": [
|
||||
{
|
||||
"name": "default",
|
||||
"name": "debug",
|
||||
"material": {
|
||||
"certpath": "./signature/OpenHarmonyApplication.cer",
|
||||
"storePassword": "00000016139B93BBCA1641496EA2EDC04012D36AAF788805480483B92ED8CC7F2367472558F1",
|
||||
//该方案的签名材料
|
||||
"certpath": "signature/OpenHarmonyApplication.cer",
|
||||
//调试或发布证书文件,格式为.cer,
|
||||
"storePassword": "000000166348AFD6C93C5F2D2233C88FB2C5643A9D9DC9B4AFA4E9015CB42D471D34812358D7",
|
||||
//密钥库密码,以密文形式呈现,
|
||||
"keyAlias": "OpenHarmony Application Release",
|
||||
"keyPassword": "000000165E797840E4487C9186CD743D2640A6732F892B14D2B6517D2FBFA7D1C705E55EAB6D",
|
||||
"profile": "./signature/photos.p7b",
|
||||
//密钥别名信息,
|
||||
"keyPassword": "000000166146A16C62C98E5BB0A445915F2A4B6FEF2F3A16B46CA44799D2120224FF6696BD94",
|
||||
//密钥密码,以密文形式呈现,
|
||||
"profile": "signature/Photos.p7b",
|
||||
//调试或发布证书Profile文件,格式为.p7b,
|
||||
"signAlg": "SHA256withECDSA",
|
||||
"storeFile": "./signature/OpenHarmony.p12"
|
||||
//密钥库signAlg参数
|
||||
"storeFile": "signature/OpenHarmony.p12"
|
||||
//密钥库文件,格式为.p12
|
||||
}
|
||||
}
|
||||
],
|
||||
@ -19,62 +27,96 @@
|
||||
"products": [
|
||||
{
|
||||
"name": "default",
|
||||
"signingConfig": "default"
|
||||
"signingConfig": "debug"
|
||||
},
|
||||
],
|
||||
},
|
||||
"modules": [
|
||||
{
|
||||
"name": "entry",
|
||||
"srcPath": "./entry",
|
||||
"name": "photos_common",
|
||||
"srcPath": "./common",
|
||||
"targets": [
|
||||
{
|
||||
"name": "default",
|
||||
"applyToProducts": [
|
||||
"default",
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
"name": "base",
|
||||
"srcPath": "./common/base"
|
||||
},
|
||||
{
|
||||
"name": "timeline",
|
||||
"srcPath": "./features/timeline"
|
||||
},
|
||||
{
|
||||
"name": "browser",
|
||||
"srcPath": "./features/browser"
|
||||
},
|
||||
{
|
||||
"name": "grid",
|
||||
"srcPath": "./features/grid"
|
||||
},
|
||||
{
|
||||
"name": "album",
|
||||
"srcPath": "./features/album"
|
||||
},
|
||||
{
|
||||
"name": "selectAlbum",
|
||||
"srcPath": "./features/selectAlbum"
|
||||
},
|
||||
{
|
||||
"name": "third",
|
||||
"srcPath": "./features/third"
|
||||
},
|
||||
{
|
||||
"name": "mediaOperation",
|
||||
"srcPath": "./features/mediaOperation"
|
||||
},
|
||||
{
|
||||
"name": "distributed",
|
||||
"srcPath": "./features/distributed"
|
||||
},
|
||||
{
|
||||
"name": "formEditor",
|
||||
"srcPath": "./features/formEditor"
|
||||
"tablet"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "photos_browser",
|
||||
"srcPath": "./feature/browser",
|
||||
"targets": [
|
||||
{
|
||||
"name": "default",
|
||||
"applyToProducts": [
|
||||
"default",
|
||||
"tablet"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "photos_editor",
|
||||
"srcPath": "./feature/editor",
|
||||
"targets": [
|
||||
{
|
||||
"name": "default",
|
||||
"applyToProducts": [
|
||||
"default"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "photos_formAbility",
|
||||
"srcPath": "./feature/formAbility",
|
||||
"targets": [
|
||||
{
|
||||
"name": "default",
|
||||
"applyToProducts": [
|
||||
"default"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "photos_thirdselect",
|
||||
"srcPath": "./feature/thirdselect",
|
||||
"targets": [
|
||||
{
|
||||
"name": "default",
|
||||
"applyToProducts": [
|
||||
"default"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "photos_timeline",
|
||||
"srcPath": "./feature/timeline",
|
||||
"targets": [
|
||||
{
|
||||
"name": "default",
|
||||
"applyToProducts": [
|
||||
"default"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "phone_photos",
|
||||
"srcPath": "./product/phone",
|
||||
"targets": [
|
||||
{
|
||||
"name": "default",
|
||||
"applyToProducts": [
|
||||
"default"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
],
|
||||
}
|
@ -1,3 +1,4 @@
|
||||
/node_modules
|
||||
/.preview
|
||||
/build
|
||||
/oh_modules
|
@ -1,3 +0,0 @@
|
||||
// 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').harTasks
|
||||
|
@ -1,15 +0,0 @@
|
||||
{
|
||||
"license": "ISC",
|
||||
"types": "",
|
||||
"devDependencies": {},
|
||||
"name": "@ohos/base",
|
||||
"description": "a npm package which contains arkUI2.0 page",
|
||||
"ohos": {
|
||||
"org": ""
|
||||
},
|
||||
"main": "src/main/ets/components/MainPage/MainPage.ets",
|
||||
"repository": {},
|
||||
"version": "1.0.0",
|
||||
"dependencies": {},
|
||||
"type": "module"
|
||||
}
|
@ -1,87 +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 { WindowConstants } from '../constants/WindowConstants';
|
||||
|
||||
// New style
|
||||
@Component
|
||||
export struct EmptyAlbumComponent {
|
||||
@Consume gridHeight: number;
|
||||
@Consume isBigCard: boolean;
|
||||
@State icHeight: number = 0;
|
||||
gridAspectRatio = WindowConstants.CARD_ASPECT_RATIO;
|
||||
|
||||
aboutToAppear(): void {
|
||||
let numberHeight = px2vp(fp2px(WindowConstants.TEXT_SIZE_BODY2));
|
||||
let nameHeight = px2vp(fp2px(WindowConstants.TEXT_SIZE_SUB_TITLE1));
|
||||
this.icHeight = this.gridHeight - WindowConstants.ALBUM_SET_NEW_ICON_MARGIN - numberHeight - nameHeight;
|
||||
}
|
||||
|
||||
build() {
|
||||
if (this.isBigCard) {
|
||||
Flex({
|
||||
direction: FlexDirection.Column,
|
||||
justifyContent: FlexAlign.Center,
|
||||
alignItems: ItemAlign.Center
|
||||
}) {
|
||||
Image($r('app.media.ic_goto_photos'))
|
||||
.width($r('app.float.recycle_album_cover_icon_size'))
|
||||
.height($r('app.float.recycle_album_cover_icon_size'))
|
||||
.fillColor($r('app.color.empty_or_recycle_album_icon'))
|
||||
}
|
||||
.width('100%')
|
||||
.height(this.gridHeight)
|
||||
.backgroundColor($r('app.color.empty_or_recycle_album_back'))
|
||||
.border({ radius: $r('sys.float.ohos_id_corner_radius_default_l') })
|
||||
} else {
|
||||
Flex({
|
||||
direction: FlexDirection.Column,
|
||||
justifyContent: FlexAlign.Start,
|
||||
alignItems: ItemAlign.Start
|
||||
}) {
|
||||
Stack({ alignContent: Alignment.Center }) {
|
||||
Image($r('app.media.ic_goto_photos'))
|
||||
.width($r('app.float.recycle_album_cover_icon_size'))
|
||||
.height($r('app.float.recycle_album_cover_icon_size'))
|
||||
.fillColor($r('app.color.empty_or_recycle_album_icon'))
|
||||
}
|
||||
.height(this.icHeight)
|
||||
.width('100%')
|
||||
}
|
||||
.aspectRatio(this.gridAspectRatio)
|
||||
.backgroundColor($r('app.color.empty_or_recycle_album_back'))
|
||||
.border({ radius: $r('sys.float.ohos_id_corner_radius_default_l') })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Traditional style
|
||||
@Component
|
||||
export struct EmptyAlbumComponentForTraditionalStyle {
|
||||
build() {
|
||||
Flex({
|
||||
direction: FlexDirection.Column,
|
||||
justifyContent: FlexAlign.Center,
|
||||
alignItems: ItemAlign.Center
|
||||
}) {
|
||||
Image($r('app.media.ic_goto_photos'))
|
||||
.width($r('app.float.album_set_icon_size'))
|
||||
.aspectRatio(1)
|
||||
.fillColor($r('sys.color.ohos_id_color_secondary'))
|
||||
}
|
||||
.aspectRatio(1)
|
||||
.backgroundColor($r('app.color.album_set_empty_album_bright')) // bright and dark mode
|
||||
.border({ radius: $r('sys.float.ohos_id_corner_radius_default_s') })
|
||||
}
|
||||
}
|
@ -1,293 +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 MediaLib from '@ohos.multimedia.mediaLibrary';
|
||||
import { Log } from '../utils/Log';
|
||||
import { AnimationConstants } from '../constants/AnimationConstants';
|
||||
import { MediaDataItem } from '../data/MediaDataItem';
|
||||
import { DateUtil } from '../utils/DateUtil';
|
||||
import { Broadcast } from '../utils/Broadcast';
|
||||
import { BroadcastConstants } from '../constants/BroadcastConstants';
|
||||
import { startTrace } from '../utils/TraceControllerUtils';
|
||||
import { MediaConstants } from '../constants/MediaConstants';
|
||||
import { startTraceWithTaskId, finishTraceWithTaskId } from '../utils/TraceControllerUtils';
|
||||
import { LazyItem} from '../vm/ItemDataSource';
|
||||
|
||||
const TAG = "ImageGridItemComponent"
|
||||
// General grid picture control
|
||||
@Component
|
||||
export struct ImageGridItemComponent {
|
||||
@Consume broadCast: Broadcast;
|
||||
@Consume @Watch('restPress') isSelectedMode: boolean;
|
||||
@Consume @Watch('onShow') isShow: boolean;
|
||||
@State thumbnail: string = "";
|
||||
@State isFavourite: boolean = false;
|
||||
@State pressAnimScale: number = 1.0;
|
||||
@State isError: boolean = false;
|
||||
pageName = '';
|
||||
lazyItem: LazyItem<MediaDataItem>
|
||||
mediaItem: MediaDataItem;
|
||||
isThird = false;
|
||||
private isEnteringPhoto = false;
|
||||
private isPush = false;
|
||||
private isPreview = false;
|
||||
@Link isSelectUpperLimited : boolean;
|
||||
|
||||
private resetPressAnim(): void {
|
||||
this.pressAnimScale = 1;
|
||||
this.isEnteringPhoto = false;
|
||||
}
|
||||
|
||||
private restPress(): void {
|
||||
this.pressAnimScale = 1;
|
||||
}
|
||||
|
||||
aboutToAppear(): void {
|
||||
Log.debug(TAG, 'aboutToAppear');
|
||||
this.resetShow();
|
||||
}
|
||||
|
||||
private resetShow(): void {
|
||||
Log.info(TAG, "getThumbnail1 " + this.thumbnail);
|
||||
if (this.mediaItem.isLoad()) {
|
||||
this.thumbnail = this.mediaItem.getThumbnail(MediaConstants.DEFAULT_SIZE, MediaConstants.DEFAULT_SIZE);
|
||||
this.mediaItem.isFavor().then<void, void>((status: boolean): void => {
|
||||
this.isFavourite = status;
|
||||
})
|
||||
} else {
|
||||
startTraceWithTaskId("load MediaItem", this.mediaItem.index);
|
||||
this.mediaItem.load(false).then<void, void>((): void => {
|
||||
finishTraceWithTaskId("load MediaItem", this.mediaItem.index);
|
||||
this.thumbnail = this.mediaItem.getThumbnail(MediaConstants.DEFAULT_SIZE, MediaConstants.DEFAULT_SIZE);
|
||||
this.isError = false;
|
||||
Log.info(TAG, "getThumbnail2 " + this.thumbnail);
|
||||
this.mediaItem.isFavor().then<void, void>((status: boolean): void => {
|
||||
this.isFavourite = status;
|
||||
})
|
||||
})
|
||||
}
|
||||
this.resetPressAnim();
|
||||
this.isPush = false;
|
||||
}
|
||||
|
||||
aboutToDisappear(): void {
|
||||
Log.debug(TAG, "aboutToDisappear");
|
||||
this.resetPressAnim();
|
||||
}
|
||||
|
||||
private onShow(): void {
|
||||
if(!this.isShow){
|
||||
return;
|
||||
}
|
||||
if (this.isEnteringPhoto) {
|
||||
this.resetShow();
|
||||
} else {
|
||||
this.resetPressAnim();
|
||||
}
|
||||
}
|
||||
|
||||
async routePage(isError: boolean): Promise<void> {
|
||||
Log.info(TAG, "routePage " + isError);
|
||||
try {
|
||||
startTrace('enterPhotoBrowser');
|
||||
if (this.isThird || this.isPreview) {
|
||||
this.broadCast.emit(BroadcastConstants.JUMP_THIRD_PHOTO_BROWSER, [this.pageName, this.mediaItem]);
|
||||
} else {
|
||||
this.broadCast.emit(BroadcastConstants.JUMP_PHOTO_BROWSER, [this.pageName, this.mediaItem]);
|
||||
}
|
||||
} catch (err) {
|
||||
Log.error(TAG, "fail callback, code: " + err.code + ", msg: " + err.msg);
|
||||
}
|
||||
}
|
||||
|
||||
async routeToPreviewPage(): Promise<void> {
|
||||
try {
|
||||
Log.info(TAG, 'routeToPreviewPage');
|
||||
this.broadCast.emit(BroadcastConstants.JUMP_THIRD_PHOTO_BROWSER, [this.pageName, this.mediaItem]);
|
||||
} catch (err) {
|
||||
Log.error(TAG, "fail callback, code: " + err.code + ", msg: " + err.msg);
|
||||
}
|
||||
}
|
||||
|
||||
private onSelected(): void {
|
||||
Log.info(TAG, 'onSelected');
|
||||
if ((this.isSelectUpperLimited != undefined && !this.isSelectUpperLimited) || this.mediaItem.isSelect) {
|
||||
this.mediaItem.setSelect(!this.mediaItem.isSelect);
|
||||
if (this.lazyItem != null) {
|
||||
this.lazyItem.update(this.mediaItem)
|
||||
}
|
||||
}
|
||||
this.broadCast.emit(BroadcastConstants.SELECT, [this.mediaItem.index]);
|
||||
}
|
||||
|
||||
private selectStateChange(): void {
|
||||
Log.info(TAG, "change selected " + this.isSelectedMode);
|
||||
if (!this.isSelectedMode) {
|
||||
this.isSelectedMode = true;
|
||||
this.pressAnimScale = 1;
|
||||
}
|
||||
this.onSelected();
|
||||
}
|
||||
|
||||
jumpToPhotoBrowser(): void {
|
||||
if(this.isEnteringPhoto){
|
||||
return;
|
||||
}
|
||||
this.isEnteringPhoto = true;
|
||||
this.thumbnail = this.mediaItem.getThumbnail(this.mediaItem.imgWidth, this.mediaItem.imgHeight);
|
||||
console.info("column click, first change source:"+this.thumbnail)
|
||||
this.isPush = true;
|
||||
}
|
||||
|
||||
build() {
|
||||
Stack({ alignContent: Alignment.Start }) {
|
||||
Image(this.isError ? this.mediaItem.getAlt() : this.thumbnail)
|
||||
.aspectRatio(1)
|
||||
.rotate({ x: 0, y: 0, z: 1, angle: 0 })
|
||||
.objectFit(ImageFit.Cover)
|
||||
.autoResize(false)
|
||||
.onComplete((): void => {
|
||||
Log.debug(TAG, "Draw the image! " + this.thumbnail);
|
||||
if (this.isEnteringPhoto && this.isPush) {
|
||||
Log.info(TAG, "image onComplete, broadCast, thumbnail:"+this.thumbnail);
|
||||
this.isPush = false;
|
||||
if (this.isThird || this.isPreview) {
|
||||
this.broadCast.emit(BroadcastConstants.JUMP_THIRD_PHOTO_BROWSER, [this.pageName, this.mediaItem]);
|
||||
} else {
|
||||
this.broadCast.emit(BroadcastConstants.JUMP_PHOTO_BROWSER, [this.pageName, this.mediaItem]);
|
||||
}
|
||||
}
|
||||
|
||||
})
|
||||
.onError((): void => {
|
||||
Log.error(TAG, "alt Image " + this.mediaItem.index + " error :" + this.thumbnail);
|
||||
if (this.thumbnail.length == 0 || this.mediaItem.width == 0 || this.mediaItem.height == 0) {
|
||||
this.resetShow()
|
||||
} else {
|
||||
this.isError = true
|
||||
}
|
||||
})
|
||||
.sharedTransition(this.pageName + this.mediaItem.getHashCode(), {
|
||||
duration: AnimationConstants.SHARE_TRANSITION_DURATION,
|
||||
zIndex: 0,
|
||||
})
|
||||
|
||||
if (this.mediaItem.mediaType == MediaLib.MediaType.VIDEO) {
|
||||
Column()
|
||||
.position({ x: '0%', y: '50%' })
|
||||
.height('50%')
|
||||
.width('100%')
|
||||
.linearGradient({
|
||||
angle: 0,
|
||||
colors: [
|
||||
[$r('app.color.album_cover_gradient_start_color'), 0] as object[],
|
||||
[$r('app.color.transparent'), 1.0] as object[]
|
||||
] as object[]
|
||||
})
|
||||
Text(DateUtil.getFormattedDuration(this.mediaItem.duration))
|
||||
.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($r('app.float.grid_item_text_line_height'))
|
||||
.position({ x: '0%', y: '100%' })
|
||||
.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') })
|
||||
}
|
||||
if (this.isFavourite) {
|
||||
Image($r('app.media.ic_favorite_overlay'))
|
||||
.height($r('app.float.icon_size'))
|
||||
.width($r('app.float.icon_size'))
|
||||
.objectFit(ImageFit.Contain)
|
||||
.position({ x: '100%', y: '0%' })
|
||||
.markAnchor({
|
||||
x: $r('app.float.grid_item_favor_markAnchor_x'),
|
||||
y: $r('app.float.grid_item_favor_markAnchor_y')
|
||||
})
|
||||
}
|
||||
|
||||
Column()
|
||||
.height('100%')
|
||||
.width('100%')
|
||||
.backgroundColor(this.isSelectedMode && this.mediaItem.isSelect ?
|
||||
$r('app.color.item_selection_bg_color') : $r('app.color.transparent'))
|
||||
.onClick((): void => {
|
||||
if (this.isSelectedMode) {
|
||||
this.onSelected();
|
||||
} else {
|
||||
this.isPreview = false;
|
||||
this.jumpToPhotoBrowser();
|
||||
}
|
||||
})
|
||||
if (this.isSelectedMode) {
|
||||
Image($r('app.media.ic_photo_preview'))
|
||||
.onClick((): void => {
|
||||
this.isPreview = true;
|
||||
this.jumpToPhotoBrowser();
|
||||
Log.info(TAG, 'expand.');
|
||||
})
|
||||
.height($r('app.float.icon_size_hot'))
|
||||
.width($r('app.float.icon_size_hot'))
|
||||
.position({ x: '0%', y: '0%' })
|
||||
.markAnchor({ x: 0, y: 0 })
|
||||
.padding($r('app.float.grid_item_preview_padding'))
|
||||
Image(this.mediaItem.isSelect
|
||||
? $r('app.media.ic_gallery_public_checkbox_filled') : $r('app.media.ic_checkbox_off_overlay'))
|
||||
.height($r('app.float.icon_size'))
|
||||
.width($r('app.float.icon_size'))
|
||||
.position({ x: '100%', y: '100%' })
|
||||
.markAnchor({
|
||||
x: $r('app.float.grid_item_checkbox_markAnchor'),
|
||||
y: $r('app.float.grid_item_checkbox_markAnchor')
|
||||
})
|
||||
.onClick((): void => {
|
||||
this.onSelected();
|
||||
})
|
||||
}
|
||||
}
|
||||
.aspectRatio(1)
|
||||
.scale({
|
||||
x: this.pressAnimScale,
|
||||
y: this.pressAnimScale
|
||||
})
|
||||
.animation({
|
||||
duration: AnimationConstants.PRESS_ANIM_DURATION,
|
||||
curve: Curve.Ease
|
||||
})
|
||||
.onTouch((event: TouchEvent): void => {
|
||||
Log.info(TAG, "onTouch trigger: isSelectedMode: " + this.isSelectedMode +
|
||||
", isEnteringPhoto: " + this.isEnteringPhoto + ", " + JSON.stringify(event));
|
||||
if (this.isSelectedMode) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Press animation
|
||||
if (event.type == TouchType.Down) {
|
||||
this.pressAnimScale = AnimationConstants.PRESS_ANIM_SCALE;
|
||||
}
|
||||
|
||||
if (event.type == TouchType.Up && !this.isEnteringPhoto && this.pressAnimScale != 1) {
|
||||
this.pressAnimScale = 1;
|
||||
}
|
||||
})
|
||||
.gesture(LongPressGesture().onAction((event: GestureEvent): void => {
|
||||
if (!this.isThird) {
|
||||
Log.info(TAG, "LongPressGesture " + this.isSelectedMode);
|
||||
this.selectStateChange();
|
||||
}
|
||||
}))
|
||||
}
|
||||
}
|
@ -1,31 +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.
|
||||
*/
|
||||
@Entry
|
||||
@Component
|
||||
export struct MainPage {
|
||||
@State message: string = 'Hello World'
|
||||
|
||||
build() {
|
||||
Row() {
|
||||
Column() {
|
||||
Text(this.message)
|
||||
.fontSize(50)
|
||||
.fontWeight(FontWeight.Bold)
|
||||
}
|
||||
.width('100%')
|
||||
}
|
||||
.height('100%')
|
||||
}
|
||||
}
|
@ -1,55 +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.
|
||||
*/
|
||||
|
||||
@Component
|
||||
export struct AlbumScrollBar {
|
||||
scroller: Scroller;
|
||||
@State isClickScrollBar: boolean = false;
|
||||
@Consume isHideScrollBar: boolean;
|
||||
hasSideBar: boolean = true;
|
||||
@Consume('tabBarShow') hasTabBarShow: boolean;
|
||||
|
||||
build() {
|
||||
ScrollBar({ scroller: this.scroller, direction: ScrollBarDirection.Vertical,
|
||||
state: this.isHideScrollBar ? BarState.Off : BarState.Auto }) {
|
||||
Row() {
|
||||
}
|
||||
.width(this.isClickScrollBar ?
|
||||
$r('app.float.album_scrollbar_select_size') : $r('app.float.album_scrollbar_normal_size'))
|
||||
.height($r('app.float.album_scrollbar_height_size'))
|
||||
.border({ radius: $r('app.float.album_scrollbar_radius') })
|
||||
.backgroundColor($r('app.color.album_scrollbar_color'))
|
||||
}
|
||||
.height('100%')
|
||||
.position({ x: '100%', y: 0 })
|
||||
.markAnchor({
|
||||
x: this.isClickScrollBar
|
||||
? $r('app.float.album_scrollbar_select_size') : $r('app.float.album_scrollbar_normal_size'),
|
||||
y: 0
|
||||
})
|
||||
.onTouch((event: TouchEvent): void => {
|
||||
if (event.type == TouchType.Down) {
|
||||
this.isClickScrollBar = true;
|
||||
} else if (event.type == TouchType.Up) {
|
||||
this.isClickScrollBar = false;
|
||||
}
|
||||
})
|
||||
.padding({
|
||||
bottom: this.hasTabBarShow
|
||||
? (this.hasSideBar ? $r('app.float.album_set_page_padding_end_112') : $r('app.float.album_set_page_padding_end_168'))
|
||||
: (this.hasSideBar ? $r('app.float.album_set_tab_bar_height') : $r('app.float.album_set_page_padding_end_112'))
|
||||
})
|
||||
}
|
||||
}
|
@ -1,54 +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.
|
||||
*/
|
||||
|
||||
@Component
|
||||
export struct GridScrollBar {
|
||||
scroller: Scroller;
|
||||
@State isClickScrollBar: boolean = false;
|
||||
@Link isHideScrollBar: boolean;
|
||||
|
||||
build() {
|
||||
ScrollBar({ scroller: this.scroller, direction: ScrollBarDirection.Vertical,
|
||||
state: this.isHideScrollBar ? BarState.Off : BarState.Auto }) {
|
||||
Row() {
|
||||
if (this.isClickScrollBar) {
|
||||
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"))
|
||||
.width($r('app.float.scroll_bar_small_width'))
|
||||
.height($r('app.float.scroll_bar_small_height'))
|
||||
}
|
||||
}
|
||||
}
|
||||
.hitTestBehavior(HitTestMode.Transparent)
|
||||
.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'),
|
||||
y: 0
|
||||
})
|
||||
.onTouch((event: TouchEvent): void => {
|
||||
if (event.type == TouchType.Down) {
|
||||
this.isClickScrollBar = true;
|
||||
} else if (event.type == TouchType.Up) {
|
||||
this.isClickScrollBar = false;
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
@ -1,22 +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.
|
||||
*/
|
||||
export class AnimationConstants {
|
||||
static readonly SHARE_TRANSITION_DURATION = 200;
|
||||
static readonly DELETE_ANIMATE_DURATION: number = 150;
|
||||
// Press animation duration
|
||||
static readonly PRESS_ANIM_DURATION = 100;
|
||||
// Press to scale the value at the end of the animation
|
||||
static readonly PRESS_ANIM_SCALE = 0.9;
|
||||
}
|
@ -1,62 +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.
|
||||
*/
|
||||
|
||||
export class BroadcastConstants {
|
||||
static readonly DELETE_FROM_BROWSER: number = 0;
|
||||
static readonly DELETE_FROM_GRID: number = 1;
|
||||
static readonly SELECT = 'select';
|
||||
static readonly GROUP_SELECT = 'groupSelect';
|
||||
static readonly JUMP_PHOTO_BROWSER = 'JumpPhotoPage';
|
||||
static readonly SHOW_DELETE_DIALOG = 'showDeleteDialog';
|
||||
static readonly UPDATE_PROGRESS = 'updateProgress';
|
||||
static readonly CANCEL_DELETE = 'cancelDelete';
|
||||
static readonly JUMP_THIRD_PHOTO_BROWSER = 'jumpThirdPhotoPage';
|
||||
static readonly BACK_PRESS_EVENT = 'back';
|
||||
static readonly RESET_STATE_EVENT = 'resetState';
|
||||
static readonly ON_TAB_CHANGED = 'onTabChanged';
|
||||
static readonly RESET_ZERO = 'resetZero';
|
||||
static readonly SHOW_DETAIL_DIALOG = 'showDetailDialog';
|
||||
static readonly SHOW_THIRD_DELETE_DIALOG = 'showThirdDeleteDialog';
|
||||
static readonly SHOW_MULTI_SELECT_DIALOG = 'showMultiSelectDialog';
|
||||
static readonly UPDATE_DATA_SOURCE = 'updateDataSource';
|
||||
static readonly SHOW_PROGRESS_DIALOG = 'showProgressDialog';
|
||||
static readonly DELETE_PROGRESS_DIALOG = 'deleteProgressDialog';
|
||||
static readonly CANCEL_OPERATE = 'cancelOperate';
|
||||
static readonly MEDIA_OPERATION = 'mediaOperation';
|
||||
static readonly OPERATE_CONTINUE = 'operateContinue';
|
||||
static readonly OPERATE_PAUSE = 'operatePause';
|
||||
static readonly SHOW_RENAME_PHOTO_DIALOG = 'showRenamePhotoDialog';
|
||||
static readonly SHOW_SAVE_PHOTO_DIALOG = 'showSavePhotoDialog';
|
||||
static readonly SHOW_EDIT_EXIT_PHOTO_DIALOG = 'showEditExitPhotoDialog';
|
||||
static readonly SHOW_ADD_NOTES_PHOTO_DIALOG = 'showAddNotesPhotoDialog';
|
||||
static readonly SHOW_NEW_ALBUM_PHOTO_DIALOG = 'showNewAlbumPhotoDialog';
|
||||
static readonly SHOW_COPY_OR_MOVE_DIALOG = 'showCopyOrMoveDialog';
|
||||
static readonly FIND_SAME_FILE_DIALOG = 'findSameFileDialog';
|
||||
static readonly ON_REMOTE_CHANGED = 'on_remote_changed';
|
||||
static readonly EXIT_SAVE_PROGRESS_CLOSE = 'save_progress_close';
|
||||
static readonly SHOW_EDIT_SAVE_PROGRESS_DIALOG = 'show_exit_save_progress_dialog';
|
||||
static readonly DOWNLOAD_CANCEL_OPERATE = 'download_cancel_operate';
|
||||
static readonly ON_DATA_RELOADED = 'on_data_reloaded';
|
||||
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_COMPLETE: string = 'photo_edit_save_complete';
|
||||
static readonly CHANGE_SWIPER_DURATION = 'change_swiper_duration';
|
||||
// USED for AppStorage
|
||||
static readonly LEFT_BLANK: string = 'leftBlank';
|
||||
static readonly RESET_TAB_SELECTED_STATUE: string = 'reset_tab_selected_statue';
|
||||
static readonly RESET_TAB_SELECTED_TEXT: string = 'reset_tab_selected_text';
|
||||
}
|
@ -1,95 +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.
|
||||
*/
|
||||
|
||||
export class MediaConstants {
|
||||
// Media item status
|
||||
static readonly UNDEFINED = 0;
|
||||
static readonly PART_LOADED = 1
|
||||
static readonly LOADED = 2;
|
||||
static readonly TRASHED = 3;
|
||||
// Media type
|
||||
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 ROTATE_NONE = 0;
|
||||
static readonly ROTATE_ONCE = 90;
|
||||
static readonly ROTATE_TWICE = 180;
|
||||
static readonly ROTATE_THIRD = 270;
|
||||
static readonly ROTATE_AROUND = 360;
|
||||
static readonly DEFAULT_SIZE = 256;
|
||||
static readonly DEFAULT_THUMBNAIL_SIZE = 1920;
|
||||
// select type
|
||||
static readonly SELECT_TYPE_ALL = 0;
|
||||
static readonly SELECT_TYPE_VIDEO = 1;
|
||||
static readonly SELECT_TYPE_IMAGE = 2;
|
||||
// album id
|
||||
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: Set<string> = new Set<string>([
|
||||
MediaConstants.ALBUM_ID_ALL,
|
||||
MediaConstants.ALBUM_ID_VIDEO,
|
||||
MediaConstants.ALBUM_ID_RECYCLE,
|
||||
MediaConstants.ALBUM_ID_FAVOR
|
||||
] as string[]);
|
||||
static readonly ALBUM_DISABLE_DELETE_LIST: Set<string> = new Set<string>([
|
||||
MediaConstants.ALBUM_ID_ALL,
|
||||
MediaConstants.ALBUM_ID_CAMERA,
|
||||
MediaConstants.ALBUM_ID_VIDEO,
|
||||
MediaConstants.ALBUM_ID_RECYCLE,
|
||||
MediaConstants.ALBUM_ID_FAVOR
|
||||
] as string[]);
|
||||
static readonly ALBUM_DISABLE_NEW_LIST: Set<string> = new Set<string>([
|
||||
MediaConstants.ALBUM_ID_ALL,
|
||||
MediaConstants.ALBUM_ID_CAMERA,
|
||||
MediaConstants.ALBUM_ID_VIDEO,
|
||||
MediaConstants.ALBUM_ID_RECYCLE,
|
||||
MediaConstants.ALBUM_ID_FAVOR,
|
||||
MediaConstants.ALBUM_ID_SNAPSHOT
|
||||
] as string[]);
|
||||
static readonly ALBUM_DISABLE_RENAME_LIST: Set<string> = new Set<string>([
|
||||
MediaConstants.ALBUM_ID_ALL,
|
||||
MediaConstants.ALBUM_ID_CAMERA,
|
||||
MediaConstants.ALBUM_ID_VIDEO,
|
||||
MediaConstants.ALBUM_ID_RECYCLE,
|
||||
MediaConstants.ALBUM_ID_FAVOR,
|
||||
MediaConstants.ALBUM_ID_SNAPSHOT
|
||||
] as string[]);
|
||||
static readonly ALBUM_DEFAULT_SORT_LIST: string[] = [
|
||||
MediaConstants.ALBUM_ID_CAMERA,
|
||||
MediaConstants.ALBUM_ID_ALL,
|
||||
MediaConstants.ALBUM_ID_VIDEO,
|
||||
MediaConstants.ALBUM_ID_SNAPSHOT,
|
||||
MediaConstants.ALBUM_ID_FAVOR
|
||||
];
|
||||
static readonly CAMERA_ALBUM_PATH = 'Camera'
|
||||
static readonly REMOTE_ALBUM_PATH = 'FromOtherDevices'
|
||||
static readonly SNAPSHOT_ALBUM_PATH = 'Screenshots'
|
||||
|
||||
// 需要过滤的媒体文件类型
|
||||
static readonly FILTER_MEDIA_TYPE_ALL: string = 'FILTER_MEDIA_TYPE_ALL';
|
||||
static readonly FILTER_MEDIA_TYPE_IMAGE: string = 'FILTER_MEDIA_TYPE_IMAGE';
|
||||
static readonly FILTER_MEDIA_TYPE_VIDEO: string = 'FILTER_MEDIA_TYPE_VIDEO';
|
||||
}
|
@ -1,40 +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.
|
||||
*/
|
||||
|
||||
enum EntryForm {
|
||||
NORMAL = 0,
|
||||
CAMERA = 1,
|
||||
SINGLE_SELECT = 2,
|
||||
MULTIPLE_SELECT = 3,
|
||||
RECYCLE = 4,
|
||||
DISTRIBUTED = 5,
|
||||
CARD = 6,
|
||||
VIEW_DATA = 7
|
||||
}
|
||||
|
||||
export class RouterConstants {
|
||||
static readonly ENTRY_FROM_NONE = 0;
|
||||
static readonly ENTRY_FROM_CAMERA = 1;
|
||||
static readonly ENTRY_FROM_SINGLE_SELECT = 2;
|
||||
static readonly ENTRY_FROM_MULTIPLE_SELECT = 3;
|
||||
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 = EntryForm;
|
||||
}
|
@ -1,42 +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.
|
||||
*/
|
||||
|
||||
export class WindowConstants {
|
||||
static readonly MAIN_WINDOW: string = 'mainWindow';
|
||||
static readonly TOP_BAR_SIZE: number = 56;
|
||||
static readonly TOOL_BAR_SIZE: number = 72;
|
||||
static readonly BOTTOM_TOOL_BAR_SIZE: number = 196;
|
||||
static readonly FILTER_BOTTOM_TOOL_BAR_SIZE: number = 232;
|
||||
// Grid Constants
|
||||
static readonly ACTION_BAR_HEIGHT: number = 56;
|
||||
static readonly TAB_BAR_WIDTH: number = 96;
|
||||
static readonly GRID_GUTTER: number = 2;
|
||||
static readonly GRID_IMAGE_SIZE: number = 256;
|
||||
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;
|
||||
static readonly CARD_ASPECT_RATIO: number = 0.75;
|
||||
static readonly TEXT_SIZE_SUB_TITLE1: number = 18; // ohos_id_text_size_sub_title1
|
||||
static readonly TEXT_SIZE_BODY2: number = 14; // ohos_id_text_size_body2
|
||||
static readonly TEXT_SIZE_SUB_TITLE2: number = 16; // ohos_id_text_size_sub_title2
|
||||
|
||||
static readonly ALBUM_SET_NEW_ICON_SIZE: number = 22;
|
||||
static readonly ALBUM_SET_NEW_ICON_MARGIN: number = 8;
|
||||
static readonly ALBUM_SET_MARGIN: number = 24;
|
||||
static readonly ALBUM_SET_GUTTER: number = 12;
|
||||
static readonly ALBUM_SET_COVER_SIZE: number = 150;
|
||||
}
|
@ -1,116 +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 MediaLib from '@ohos.multimedia.mediaLibrary';
|
||||
import { mediaModel } from '../model/MediaModel';
|
||||
|
||||
import { selectManager } from '../manager/SelectManager';
|
||||
import { Log } from '../utils/Log';
|
||||
import { MediaConstants } from '../constants/MediaConstants';
|
||||
import { getFetchOptions } from '../helper/MediaDataHelper';
|
||||
|
||||
const TAG = "AlbumDataItem"
|
||||
|
||||
let objectIndex = 0
|
||||
|
||||
export class AlbumDataItem {
|
||||
index: number;
|
||||
id: string;
|
||||
uri: string;
|
||||
orientation: number;
|
||||
displayName: string;
|
||||
count: number;
|
||||
isDisableRename: boolean;
|
||||
isDisableDelete: boolean;
|
||||
relativePath: string;
|
||||
innerId: number;
|
||||
selectType: number = MediaConstants.SELECT_TYPE_ALL;
|
||||
deviceId: string = "";
|
||||
isSelect: boolean = false;
|
||||
status: number = MediaConstants.UNDEFINED;
|
||||
objectIndex: number
|
||||
|
||||
constructor(id: string, count: number, displayName: string, selectType: number, deviceId: string) {
|
||||
this.id = id;
|
||||
this.displayName = displayName;
|
||||
this.count = count;
|
||||
this.isDisableRename = MediaConstants.ALBUM_DISABLE_RENAME_LIST.has(id);
|
||||
this.isDisableDelete = MediaConstants.ALBUM_DISABLE_DELETE_LIST.has(id);
|
||||
this.selectType = selectType;
|
||||
this.deviceId = deviceId;
|
||||
this.objectIndex = objectIndex++;
|
||||
this.load();
|
||||
}
|
||||
|
||||
getHashCode(): string {
|
||||
return this.objectIndex + "" + this.id + " " + this.orientation + " " + this.isSelect
|
||||
}
|
||||
|
||||
async load(): Promise<void> {
|
||||
if (this.status >= MediaConstants.LOADED) {
|
||||
return;
|
||||
}
|
||||
let fetchOption: MediaLib.MediaFetchOptions = await getFetchOptions(this.selectType, this.id, this.deviceId);
|
||||
let fileAsset = (await mediaModel.getAllMediaItem(this.id, fetchOption, false)).fileAsset;
|
||||
this.update(fileAsset);
|
||||
}
|
||||
|
||||
update(fileAsset: MediaLib.FileAsset): void {
|
||||
this.uri = fileAsset.uri;
|
||||
this.relativePath = fileAsset.relativePath;
|
||||
|
||||
this.status = MediaConstants.LOADED;
|
||||
this.isSelect = selectManager.isSelect(this.id, this.isSelect);
|
||||
}
|
||||
|
||||
async getRelativePath(): Promise<string> {
|
||||
await this.load();
|
||||
return this.relativePath;
|
||||
}
|
||||
|
||||
getThumbnail(): string {
|
||||
Log.debug(TAG, "this.uri " + this.uri);
|
||||
return this.uri + "/thumbnail/256/256";
|
||||
}
|
||||
|
||||
async getVideoCount(): Promise<number> {
|
||||
if (this.selectType == MediaConstants.SELECT_TYPE_IMAGE) {
|
||||
return 0;
|
||||
}
|
||||
let videoFetchOption: MediaLib.MediaFetchOptions = await getFetchOptions(MediaConstants.SELECT_TYPE_VIDEO, this.id, this.deviceId);
|
||||
return (await mediaModel.getAllMediaItem(this.id, videoFetchOption, true)).counts;
|
||||
}
|
||||
|
||||
setSelect(isSelect: boolean): void {
|
||||
this.isSelect = isSelect;
|
||||
selectManager.setSelect(this.id, this.isSelect);
|
||||
}
|
||||
|
||||
async onDelete(): Promise<boolean> {
|
||||
try {
|
||||
let fetchOption: MediaLib.MediaFetchOptions = await getFetchOptions(this.selectType, this.id, "");
|
||||
await mediaModel.deleteAll(fetchOption);
|
||||
selectManager.deleteSelect(this.uri);
|
||||
this.status = MediaConstants.TRASHED;
|
||||
return true;
|
||||
} catch (err) {
|
||||
Log.error(TAG, "onDelete error: " + JSON.stringify(err));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
isDeleted(): boolean {
|
||||
return this.status == MediaConstants.TRASHED;
|
||||
}
|
||||
}
|
@ -1,51 +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 MediaLib from '@ohos.multimedia.mediaLibrary';
|
||||
import { mediaModel } from '../model/MediaModel';
|
||||
import { MediaConstants } from '../constants/MediaConstants';
|
||||
import { MediaDataItem } from './MediaDataItem';
|
||||
|
||||
export class FavorMediaDataItem extends MediaDataItem {
|
||||
constructor(selections: string, selectionArgs: string[], index: number) {
|
||||
super(selections, selectionArgs, "", index)
|
||||
}
|
||||
|
||||
async loadFileAsset(): Promise<MediaLib.FileAsset> {
|
||||
let fetchOption: MediaLib.MediaFetchOptions;
|
||||
if (this.status == MediaConstants.UNDEFINED) {
|
||||
fetchOption = {
|
||||
selections: this.selections,
|
||||
selectionArgs: this.selectionArgs,
|
||||
order: "date_added DESC LIMIT " + this.index + ",1"
|
||||
};
|
||||
} else {
|
||||
let selectionArgs: string[] = [this.id.toString()];
|
||||
fetchOption = {
|
||||
selections: MediaLib.FileKey.ID + " = ?",
|
||||
selectionArgs: selectionArgs,
|
||||
order: "date_added DESC"
|
||||
}
|
||||
}
|
||||
return (await mediaModel.getAllFavorMediaItem(fetchOption, false)).fileAsset;
|
||||
}
|
||||
|
||||
async setFavor(): Promise<boolean> {
|
||||
let isSuccess: boolean = await super.setFavor();
|
||||
let isFavor: boolean = await super.isFavor();
|
||||
this.status = isFavor ? this.status : MediaConstants.TRASHED;
|
||||
return isSuccess;
|
||||
}
|
||||
}
|
@ -1,234 +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 { Log } from '../utils/Log';
|
||||
import MediaLib from '@ohos.multimedia.mediaLibrary';
|
||||
import { ViewType } from '../data/ViewType';
|
||||
import { mediaModel } from '../model/MediaModel';
|
||||
import { MediaConstants } from '../constants/MediaConstants';
|
||||
import { setOrientation } from '../helper/MediaDataHelper';
|
||||
import { selectManager } from '../manager/SelectManager';
|
||||
import { ItemDataSource } from '../vm/ItemDataSource'
|
||||
const TAG = "MediaDataItem"
|
||||
|
||||
const STATUS_UNDEFINED = -1
|
||||
const STATUS_FALSE = 0
|
||||
const STATUS_TRUE = 1
|
||||
|
||||
export interface DateAdded {
|
||||
dateAdded: number;
|
||||
viewType: ViewType;
|
||||
}
|
||||
|
||||
export class MediaDataItem implements DateAdded {
|
||||
viewType: ViewType = ViewType.ITEM
|
||||
readonly hashIndex: number
|
||||
index: number
|
||||
dateAdded: number | null = null
|
||||
dateModified: number
|
||||
dateTaken: number
|
||||
status: number = MediaConstants.UNDEFINED
|
||||
isSelect: boolean = false
|
||||
id: number
|
||||
uri: string
|
||||
orientation: number
|
||||
duration: number
|
||||
size: number
|
||||
width: number; // width changed by orientation
|
||||
height: number; // height changed by orientation
|
||||
imgWidth: number; // may be smaller than width, as width is too large
|
||||
imgHeight: number; // may be smaller than height, as height is too large
|
||||
path: string
|
||||
title: string
|
||||
displayName: string
|
||||
mediaType: MediaLib.MediaType
|
||||
favouriteStatus: number = STATUS_UNDEFINED
|
||||
canRotate: number = STATUS_UNDEFINED
|
||||
selections: string = ""
|
||||
selectionArgs: string[] = [];
|
||||
deviceId: string = ''
|
||||
|
||||
constructor(selections: string, selectionArgs: string[], deviceId: string, index: number) {
|
||||
this.selections = selections
|
||||
this.selectionArgs = selectionArgs
|
||||
this.deviceId = deviceId
|
||||
this.hashIndex = index
|
||||
this.index = index
|
||||
}
|
||||
|
||||
getHashCode(): string {
|
||||
//时间线界面角度,收藏状态变更,都需要刷新界面;大图浏览界面角度变更,需要刷新界面
|
||||
return this.status == MediaConstants.UNDEFINED ?
|
||||
"" + this.hashIndex :
|
||||
this.uri + this.favouriteStatus + " " + this.orientation + " " + this.isSelect
|
||||
}
|
||||
|
||||
async loadFileAsset(): Promise<MediaLib.FileAsset> {
|
||||
let fetchOption: MediaLib.MediaFetchOptions
|
||||
if (this.status == MediaConstants.UNDEFINED) {
|
||||
fetchOption = {
|
||||
selections: this.selections,
|
||||
selectionArgs: this.selectionArgs,
|
||||
order: "date_added DESC LIMIT " + this.index + ",1"
|
||||
} as MediaLib.MediaFetchOptions;
|
||||
} else {
|
||||
let selectionArgs: string [] = [this.id.toString()];
|
||||
fetchOption = {
|
||||
selections: MediaLib.FileKey.ID + " = ?",
|
||||
selectionArgs: selectionArgs,
|
||||
order: "date_added DESC"
|
||||
} as MediaLib.MediaFetchOptions;
|
||||
}
|
||||
if (this.deviceId.length > 0) {
|
||||
fetchOption.networkId = this.deviceId
|
||||
}
|
||||
return (await mediaModel.getAllCommonMediaItem(fetchOption, false)).fileAsset
|
||||
}
|
||||
|
||||
isLoad():boolean {
|
||||
if (this.status > MediaConstants.UNDEFINED) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
async load(isForce: boolean): Promise<void> {
|
||||
Log.info(TAG, "load " + this.status)
|
||||
if (this.status > (isForce ? MediaConstants.PART_LOADED : MediaConstants.UNDEFINED)) {
|
||||
return
|
||||
}
|
||||
let fileAsset = await this.loadFileAsset()
|
||||
if (fileAsset != null) {
|
||||
this.update(fileAsset)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
update(fileAsset: MediaLib.FileAsset): void {
|
||||
this.id = fileAsset.id;
|
||||
this.uri = fileAsset.uri;
|
||||
this.orientation = fileAsset.orientation;
|
||||
this.mediaType = fileAsset.mediaType;
|
||||
this.duration = fileAsset.duration;
|
||||
this.size = fileAsset.size;
|
||||
if (this.orientation == MediaConstants.ROTATE_ONCE || this.orientation == MediaConstants.ROTATE_THIRD) {
|
||||
this.width = fileAsset.height;
|
||||
this.height = fileAsset.width;
|
||||
} else {
|
||||
this.width = fileAsset.width;
|
||||
this.height = fileAsset.height;
|
||||
}
|
||||
this.imgWidth = this.width;
|
||||
this.imgHeight = this.height;
|
||||
this.path = fileAsset.relativePath;
|
||||
this.title = fileAsset.title;
|
||||
this.displayName = fileAsset.displayName;
|
||||
this.dateAdded = fileAsset.dateAdded * 1000;
|
||||
this.dateModified = fileAsset.dateModified * 1000;
|
||||
this.dateTaken = fileAsset.dateTaken * 1000;
|
||||
this.isSelect = selectManager.isSelect(this.uri, this.isSelect);
|
||||
|
||||
// may change
|
||||
fileAsset.isFavorite().then<void, void>((isFavor: boolean): void => {this.favouriteStatus = (isFavor) ? STATUS_TRUE : STATUS_FALSE});
|
||||
if (this.width > 0 && this.height > 0) {
|
||||
this.status = MediaConstants.LOADED;
|
||||
} else {
|
||||
this.status = MediaConstants.PART_LOADED;
|
||||
}
|
||||
}
|
||||
|
||||
getThumbnail(width: number, height: number): string {
|
||||
Log.debug(TAG, "getThumbnail " + this.status);
|
||||
if (this.status != MediaConstants.LOADED && this.status != MediaConstants.PART_LOADED) {
|
||||
Log.warn(TAG, "getThumbnail fail as status: " + this.status);
|
||||
return "";
|
||||
}
|
||||
Log.debug(TAG, "this.uri " + this.uri);
|
||||
return this.uri + "/thumbnail/" + width + "/" + height;
|
||||
}
|
||||
|
||||
getAlt(): Resource {
|
||||
if (this.mediaType == MediaLib.MediaType.VIDEO) {
|
||||
return $r('app.media.alt_video_placeholder');
|
||||
} else {
|
||||
return $r('app.media.alt_placeholder');
|
||||
}
|
||||
}
|
||||
|
||||
setSelect(isSelect: boolean): void {
|
||||
this.isSelect = isSelect;
|
||||
selectManager.setSelect(this.uri, this.isSelect);
|
||||
}
|
||||
|
||||
async onDelete(): Promise<boolean> {
|
||||
try {
|
||||
let fileAsset = await this.loadFileAsset();
|
||||
await fileAsset.trash(true);
|
||||
selectManager.deleteSelect(this.uri);
|
||||
this.status = MediaConstants.TRASHED;
|
||||
return true;
|
||||
} catch (err) {
|
||||
Log.error(TAG, "onDelete " + this.index + " error: " + JSON.stringify(err));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
isDeleted(): boolean {
|
||||
return this.status == MediaConstants.TRASHED;
|
||||
}
|
||||
|
||||
async isFavor(): Promise<boolean> {
|
||||
if (this.favouriteStatus == STATUS_UNDEFINED) {
|
||||
let fileAsset = await this.loadFileAsset();
|
||||
this.favouriteStatus = (await fileAsset.isFavorite()) ? STATUS_TRUE : STATUS_FALSE;
|
||||
}
|
||||
return this.favouriteStatus == STATUS_TRUE;
|
||||
}
|
||||
|
||||
async setFavor(): Promise<boolean> {
|
||||
let status = !(await this.isFavor());
|
||||
try {
|
||||
let fileAsset = await this.loadFileAsset();
|
||||
await fileAsset.favorite(status);
|
||||
await fileAsset.commitModify();
|
||||
this.favouriteStatus = status ? STATUS_TRUE : STATUS_FALSE;
|
||||
return true;
|
||||
} catch (err) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async setOrientation(): Promise<void> {
|
||||
let fileAsset = await this.loadFileAsset();
|
||||
this.orientation = (this.orientation + MediaConstants.ROTATE_ONCE) % MediaConstants.ROTATE_AROUND;
|
||||
await setOrientation(fileAsset, this.orientation);
|
||||
let tmp = this.width;
|
||||
this.width = this.height;
|
||||
this.height = tmp;
|
||||
}
|
||||
|
||||
async setName(name: string): Promise<void> {
|
||||
let fileAsset = await this.loadFileAsset();
|
||||
let displayName = fileAsset.displayName;
|
||||
let index = displayName.lastIndexOf('.');
|
||||
displayName = name + displayName.slice(index);
|
||||
|
||||
this.displayName = displayName;
|
||||
fileAsset.displayName = displayName;
|
||||
|
||||
this.title = name;
|
||||
fileAsset.title = name;
|
||||
await fileAsset.commitModify();
|
||||
}
|
||||
}
|
@ -1,44 +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 { MediaDataItem } from './MediaDataItem';
|
||||
import { stashOrGetObject } from '../utils/SingleInstanceUtils';
|
||||
|
||||
const TAG = "MediaDataItemCache"
|
||||
|
||||
class MediaDataItemCache {
|
||||
private mediaDataItemMap = new Map<string, MediaDataItem>();
|
||||
|
||||
hasKey(key: string): boolean {
|
||||
return this.mediaDataItemMap.has(key);
|
||||
}
|
||||
|
||||
deleteKey(key: string): boolean {
|
||||
return this.mediaDataItemMap.delete(key);
|
||||
}
|
||||
|
||||
set(key: string, value: MediaDataItem): void {
|
||||
this.mediaDataItemMap.set(key, value);
|
||||
}
|
||||
|
||||
get(key: string): MediaDataItem {
|
||||
return this.mediaDataItemMap.get(key);
|
||||
}
|
||||
|
||||
clearAll(): void {
|
||||
this.mediaDataItemMap.clear();
|
||||
}
|
||||
}
|
||||
|
||||
export let mediaDataItemCache: MediaDataItemCache = stashOrGetObject<MediaDataItemCache>(new MediaDataItemCache(), TAG);
|
@ -1,51 +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 MediaLib from '@ohos.multimedia.mediaLibrary';
|
||||
import { Log } from '../utils/Log';
|
||||
import { selectManager } from '../manager/SelectManager';
|
||||
|
||||
const TAG = "PeerDataItem"
|
||||
|
||||
export class PeerDataItem {
|
||||
index: number;
|
||||
uri: string;
|
||||
orientation: number;
|
||||
deviceName: string;
|
||||
count: number;
|
||||
networkId: string;
|
||||
isSelect: boolean;
|
||||
|
||||
constructor(count: number, peer: MediaLib.PeerInfo, fileAsset: MediaLib.FileAsset) {
|
||||
this.uri = fileAsset.uri;
|
||||
this.orientation = fileAsset.orientation;
|
||||
this.deviceName = peer.deviceName;
|
||||
this.count = count;
|
||||
this.networkId = peer.networkId;
|
||||
}
|
||||
|
||||
getHashCode(): string {
|
||||
return this.networkId + " " + this.orientation + " " + this.isSelect;
|
||||
}
|
||||
|
||||
getThumbnail(): string {
|
||||
Log.debug(TAG, "this.uri " + this.uri);
|
||||
return this.uri + "/thumbnail/256/256";
|
||||
}
|
||||
|
||||
setSelect(isSelect: boolean): void {
|
||||
this.isSelect = isSelect;
|
||||
selectManager.setSelect(this.uri, this.isSelect);
|
||||
}
|
||||
}
|
@ -1,30 +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.
|
||||
*/
|
||||
|
||||
export class SimpleAlbumDataItem {
|
||||
readonly id: string
|
||||
readonly displayName: string
|
||||
readonly relativePath: string
|
||||
readonly deviceId: string
|
||||
readonly deviceName: string
|
||||
|
||||
constructor(id: string, displayName: string, relativePath: string, deviceId: string, deviceName: string) {
|
||||
this.id = id
|
||||
this.displayName = displayName
|
||||
this.relativePath = relativePath
|
||||
this.deviceId = deviceId
|
||||
this.deviceName = deviceName
|
||||
}
|
||||
}
|
@ -1,74 +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 MediaLib from '@ohos.multimedia.mediaLibrary';
|
||||
import { selectManager } from '../manager/SelectManager';
|
||||
import { mediaModel } from '../model/MediaModel';
|
||||
import { Log } from '../utils/Log';
|
||||
import { MediaConstants } from '../constants/MediaConstants';
|
||||
import { MediaDataItem } from './MediaDataItem';
|
||||
|
||||
const TAG = "TrashMediaDataItem"
|
||||
|
||||
export class TrashMediaDataItem extends MediaDataItem {
|
||||
constructor(selections: string, selectionArgs: string[], index: number) {
|
||||
super(selections, selectionArgs, "", index);
|
||||
this.setSelect(false);
|
||||
}
|
||||
|
||||
async loadFileAsset(): Promise<MediaLib.FileAsset> {
|
||||
let fetchOption: MediaLib.MediaFetchOptions;
|
||||
if (this.status == MediaConstants.UNDEFINED) {
|
||||
fetchOption = {
|
||||
selections: this.selections,
|
||||
selectionArgs: this.selectionArgs,
|
||||
order: "date_added DESC LIMIT " + this.index + ",1"
|
||||
}
|
||||
} else {
|
||||
let selectionArgs: string [] = [this.id.toString()];
|
||||
fetchOption = {
|
||||
selections: MediaLib.FileKey.ID + " = ?",
|
||||
selectionArgs: selectionArgs,
|
||||
order: "date_added DESC"
|
||||
}
|
||||
}
|
||||
return (await mediaModel.getAllTrashMediaItem(fetchOption, false)).fileAsset;
|
||||
}
|
||||
|
||||
async onRecover(): Promise<boolean> {
|
||||
try {
|
||||
let fileAsset = await this.loadFileAsset();
|
||||
|
||||
await fileAsset.trash(false);
|
||||
selectManager.deleteSelect(this.uri);
|
||||
this.status = MediaConstants.TRASHED;
|
||||
return true;
|
||||
} catch (err) {
|
||||
Log.error(TAG, "onRecover error: " + JSON.stringify(err));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async onDelete(): Promise<boolean> {
|
||||
try {
|
||||
await mediaModel.deleteOne(this.uri);
|
||||
selectManager.deleteSelect(this.uri);
|
||||
this.status = MediaConstants.TRASHED;
|
||||
return true;
|
||||
} catch (err) {
|
||||
Log.error(TAG, "onDelete error: " + JSON.stringify(err));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,44 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2023 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 { TrashMediaDataItem } from './TrashMediaDataItem';
|
||||
import { stashOrGetObject } from '../utils/SingleInstanceUtils';
|
||||
|
||||
const TAG = "TrashMediaDataItemCache"
|
||||
|
||||
class TrashMediaDataItemCache {
|
||||
private trashMediaDataItemMap = new Map<string, TrashMediaDataItem>();
|
||||
|
||||
hasKey(key: string): boolean {
|
||||
return this.trashMediaDataItemMap.has(key);
|
||||
}
|
||||
|
||||
deleteKey(key: string): boolean {
|
||||
return this.trashMediaDataItemMap.delete(key);
|
||||
}
|
||||
|
||||
set(key: string, value: TrashMediaDataItem): void {
|
||||
this.trashMediaDataItemMap.set(key, value);
|
||||
}
|
||||
|
||||
get(key: string): TrashMediaDataItem {
|
||||
return this.trashMediaDataItemMap.get(key);
|
||||
}
|
||||
|
||||
clearAll(): void {
|
||||
this.trashMediaDataItemMap.clear();
|
||||
}
|
||||
}
|
||||
|
||||
export let trashMediaDataItemCache: TrashMediaDataItemCache = stashOrGetObject<TrashMediaDataItemCache>(new TrashMediaDataItemCache(), TAG);
|
@ -1,156 +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 image from '@ohos.multimedia.image';
|
||||
import MediaLib from '@ohos.multimedia.mediaLibrary';
|
||||
import { mediaModel } from '../model/MediaModel';
|
||||
import { Log } from '../utils/Log';
|
||||
import { MediaConstants } from '../constants/MediaConstants';
|
||||
import { getResourceString } from '../utils/ResourceUtils';
|
||||
import { SimpleAlbumDataItem } from '../data/SimpleAlbumDataItem';
|
||||
|
||||
const TAG = "MediaDataHelper"
|
||||
|
||||
export class Rotatable {
|
||||
rotatable: boolean
|
||||
orientation: number
|
||||
}
|
||||
|
||||
export async function setOrientation(fileAsset: MediaLib.FileAsset, orientation: number): Promise<void> {
|
||||
Log.info(TAG, "setOrientation")
|
||||
try {
|
||||
let fd: number = await mediaModel.openAsset('RW', fileAsset);
|
||||
let imageSourceApi: image.ImageSource = image.createImageSource(fd);
|
||||
await imageSourceApi.modifyImageProperty("Orientation", getPropertyValidOrientation(orientation));
|
||||
imageSourceApi.release();
|
||||
mediaModel.closeAsset(fd, fileAsset);
|
||||
} catch (err) {
|
||||
Log.error(TAG, "setOrientation err " + JSON.stringify(err));
|
||||
fileAsset.orientation = orientation;
|
||||
await fileAsset.commitModify();
|
||||
}
|
||||
}
|
||||
|
||||
function getPropertyValidOrientation(orientation: number): string {
|
||||
Log.info(TAG, "getPropertyValidOrientation " + orientation);
|
||||
if (orientation === MediaConstants.ROTATE_NONE) {
|
||||
return "1";
|
||||
} else if (orientation === MediaConstants.ROTATE_THIRD) {
|
||||
return "8";
|
||||
} else if (orientation === MediaConstants.ROTATE_TWICE) {
|
||||
return "3";
|
||||
} else if (orientation === MediaConstants.ROTATE_ONCE) {
|
||||
return "6";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
export async function getAlbumDisplayName(name: string): Promise<string> {
|
||||
if (name === MediaConstants.ALBUM_ID_ALL) {
|
||||
return await getResourceString($r('app.string.album_all'));
|
||||
} else if (name === MediaConstants.ALBUM_ID_VIDEO) {
|
||||
return await getResourceString($r('app.string.album_video'));
|
||||
} else if (name === MediaConstants.ALBUM_ID_RECYCLE) {
|
||||
return await getResourceString($r('app.string.album_recycle'));
|
||||
} else if (name === MediaConstants.ALBUM_ID_CAMERA) {
|
||||
return await getResourceString($r('app.string.album_camera'));
|
||||
} else if (name === MediaConstants.ALBUM_ID_FAVOR) {
|
||||
return await getResourceString($r('app.string.album_favor'));
|
||||
} else if (name === MediaConstants.ALBUM_ID_REMOTE) {
|
||||
return await getResourceString($r('app.string.album_remote_device'));
|
||||
} else if (name === MediaConstants.ALBUM_ID_SNAPSHOT) {
|
||||
return await getResourceString($r('app.string.album_screen_shot'));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export async function getFetchOptions(selectType: number, albumId: string, deviceId: string): Promise<MediaLib.MediaFetchOptions> {
|
||||
let selections: string = "";
|
||||
let selectionArgs: string[] = [];
|
||||
let order: string = "date_added DESC";
|
||||
if (selectType == MediaConstants.SELECT_TYPE_VIDEO || albumId == MediaConstants.ALBUM_ID_VIDEO) {
|
||||
selections = MediaLib.FileKey.MEDIA_TYPE + ' = ?';
|
||||
selectionArgs = [MediaLib.MediaType.VIDEO.toString()];
|
||||
} else if (selectType == MediaConstants.SELECT_TYPE_IMAGE && albumId != MediaConstants.ALBUM_ID_VIDEO) {
|
||||
selections = MediaLib.FileKey.MEDIA_TYPE + ' = ?';
|
||||
selectionArgs = [MediaLib.MediaType.IMAGE.toString()];
|
||||
} else if (selectType == MediaConstants.SELECT_TYPE_IMAGE && albumId == MediaConstants.ALBUM_ID_VIDEO) {
|
||||
return undefined;
|
||||
} else {
|
||||
selections = MediaLib.FileKey.MEDIA_TYPE + ' = ? or ' + MediaLib.FileKey.MEDIA_TYPE + ' = ?';
|
||||
selectionArgs = [MediaLib.MediaType.IMAGE.toString(), MediaLib.MediaType.VIDEO.toString()];
|
||||
}
|
||||
if (albumId == MediaConstants.ALBUM_ID_CAMERA) {
|
||||
let path = await mediaModel.getPublicDirectory(MediaLib.DirectoryType.DIR_CAMERA);
|
||||
selections = "(" + selections + ") and " + MediaLib.FileKey.ALBUM_NAME + " = ?";
|
||||
selectionArgs.push(path.substr(0, path.length - 1));
|
||||
} else if (albumId == MediaConstants.ALBUM_ID_SNAPSHOT) {
|
||||
let path = await mediaModel.getPublicDirectory(MediaLib.DirectoryType.DIR_IMAGE) + "Screenshots/";
|
||||
selections = "(" + selections + ") and " + MediaLib.FileKey.RELATIVE_PATH + " = ?";
|
||||
selectionArgs.push(path);
|
||||
} else if (!Number.isNaN(new Number(albumId).valueOf()) && (new Number(albumId).valueOf() > 0)) {
|
||||
selections = "(" + selections + ") and " + MediaLib.FileKey.ALBUM_ID + " = ?";
|
||||
selectionArgs.push(albumId);
|
||||
}
|
||||
|
||||
let fetchOption: MediaLib.MediaFetchOptions = {
|
||||
selections: selections,
|
||||
selectionArgs: selectionArgs,
|
||||
order: order
|
||||
} as MediaLib.MediaFetchOptions;
|
||||
|
||||
if (deviceId.length > 0) {
|
||||
fetchOption.networkId = deviceId;
|
||||
}
|
||||
return fetchOption;
|
||||
}
|
||||
|
||||
export async function getFetchOptionsByAlbumItem(item: SimpleAlbumDataItem): Promise<MediaLib.MediaFetchOptions> {
|
||||
let selections: string = "";
|
||||
let selectionArgs: string[] = [];
|
||||
|
||||
if (item.displayName.length > 0) {
|
||||
selections = MediaLib.FileKey.ALBUM_NAME + '= ?';
|
||||
selectionArgs.push(item.displayName);
|
||||
}
|
||||
|
||||
let fetchOption: MediaLib.MediaFetchOptions = {
|
||||
selections: selections,
|
||||
selectionArgs: selectionArgs,
|
||||
order: "date_added DESC"
|
||||
};
|
||||
return fetchOption;
|
||||
}
|
||||
|
||||
export async function getFetchOptionsByItem(item: SimpleAlbumDataItem): Promise<MediaLib.MediaFetchOptions> {
|
||||
let selections: string = MediaLib.FileKey.MEDIA_TYPE + " = ? or " + MediaLib.FileKey.MEDIA_TYPE + " = ?";
|
||||
let selectionArgs: string[] = [MediaLib.MediaType.IMAGE.toString(), MediaLib.MediaType.VIDEO.toString()];
|
||||
|
||||
if (item.displayName.length > 0) {
|
||||
selections = "(" + selections + ") and " + MediaLib.FileKey.DISPLAY_NAME + " = ?";
|
||||
selectionArgs.push(item.displayName);
|
||||
}
|
||||
|
||||
if (item.relativePath.length > 0) {
|
||||
selections = "(" + selections + ") and " + MediaLib.FileKey.RELATIVE_PATH + " = ?";
|
||||
selectionArgs.push(item.relativePath);
|
||||
}
|
||||
|
||||
let fetchOption: MediaLib.MediaFetchOptions = {
|
||||
selections: selections,
|
||||
selectionArgs: selectionArgs,
|
||||
order: "date_added DESC"
|
||||
};
|
||||
return fetchOption;
|
||||
}
|
@ -1,36 +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 { Log } from '../utils/Log';
|
||||
import { Broadcast } from '../utils/Broadcast';
|
||||
import { stashOrGetObject } from '../utils/SingleInstanceUtils';
|
||||
|
||||
const TAG = "BroadcastManager"
|
||||
|
||||
export class BroadcastManager {
|
||||
// The global Broadcast of the application process. Event registration and destruction should be paired
|
||||
private appBroadcast: Broadcast;
|
||||
|
||||
constructor() {
|
||||
Log.info(TAG, 'constructor');
|
||||
this.appBroadcast = new Broadcast();
|
||||
}
|
||||
|
||||
public getBroadcast(): Broadcast {
|
||||
return this.appBroadcast;
|
||||
}
|
||||
}
|
||||
|
||||
export let broadcastManager: BroadcastManager = stashOrGetObject<BroadcastManager>(new BroadcastManager(), TAG);
|
@ -1,77 +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 inputConsumer from '@ohos.multimodalInput.inputConsumer';
|
||||
import { Log } from '../utils/Log';
|
||||
|
||||
|
||||
const TAG = "MultimodalInputManager"
|
||||
|
||||
export class MultimodalInputManager {
|
||||
|
||||
//win + N
|
||||
leftKeyOptions: inputConsumer.KeyOptions = {
|
||||
preKeys: Array<number>(),
|
||||
finalKey: 2014,
|
||||
isFinalKeyDown: true,
|
||||
finalKeyDownDuration: 0
|
||||
};
|
||||
|
||||
//win + I
|
||||
rightKeyOptions: inputConsumer.KeyOptions = {
|
||||
preKeys: Array<number>(),
|
||||
finalKey: 2015,
|
||||
isFinalKeyDown: true,
|
||||
finalKeyDownDuration: 0
|
||||
};
|
||||
escKeyOptions: inputConsumer.KeyOptions = {
|
||||
preKeys: Array<number>(),
|
||||
finalKey: 2070,
|
||||
isFinalKeyDown: true,
|
||||
finalKeyDownDuration: 0
|
||||
};
|
||||
|
||||
async registerListener(callback): Promise<void> {
|
||||
Log.debug(TAG, "registerListener start");
|
||||
inputConsumer.on('key', this.leftKeyOptions, (data: inputConsumer.KeyOptions): void => {
|
||||
Log.debug(TAG, "notificationRegister data: " + JSON.stringify(data));
|
||||
callback(0);
|
||||
});
|
||||
inputConsumer.on('key', this.rightKeyOptions, (data: inputConsumer.KeyOptions): void => {
|
||||
Log.debug(TAG, "controlRegister data: " + JSON.stringify(data));
|
||||
callback(1);
|
||||
});
|
||||
inputConsumer.on('key', this.escKeyOptions, (data: inputConsumer.KeyOptions): void => {
|
||||
Log.debug(TAG, "escRegister data: " + JSON.stringify(data));
|
||||
callback(2);
|
||||
});
|
||||
Log.debug(TAG, "registerListener end");
|
||||
}
|
||||
|
||||
async unregisterListener(): Promise<void> {
|
||||
Log.debug(TAG, "unregisterListener start");
|
||||
inputConsumer.off('key', this.leftKeyOptions, (data: inputConsumer.KeyOptions): void => {
|
||||
Log.debug(TAG, "notificationUnregister data: " + JSON.stringify(data));
|
||||
});
|
||||
inputConsumer.off('key', this.rightKeyOptions, (data: inputConsumer.KeyOptions): void => {
|
||||
Log.debug(TAG, "controlUnregister data: " + JSON.stringify(data));
|
||||
});
|
||||
inputConsumer.off('key', this.escKeyOptions, (data: inputConsumer.KeyOptions): void => {
|
||||
Log.debug(TAG, "escUnregister data: " + JSON.stringify(data));
|
||||
});
|
||||
Log.debug(TAG, "unregisterListener end");
|
||||
}
|
||||
}
|
||||
|
||||
export let mMultimodalInputManager = new MultimodalInputManager();
|
@ -1,452 +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 deviceInfo from '@ohos.deviceInfo';
|
||||
import window from '@ohos.window';
|
||||
import { stashOrGetObject } from '../utils/SingleInstanceUtils';
|
||||
import { Log } from '../utils/Log';
|
||||
import { BroadcastConstants } from '../constants/BroadcastConstants';
|
||||
import { WindowConstants } from '../constants/WindowConstants';
|
||||
import { getResourceString } from '../utils/ResourceUtils';
|
||||
import { GlobalContext } from '../utils/GlobalContext';
|
||||
|
||||
export enum ColumnSize {
|
||||
COLUMN_TWO = 2,
|
||||
COLUMN_FOUR = 4,
|
||||
COLUMN_SIX = 6,
|
||||
COLUMN_EIGHT = 8,
|
||||
COLUMN_TWELVE = 12
|
||||
}
|
||||
|
||||
enum ScreenWidth {
|
||||
WIDTH_MEDIUM = 520,
|
||||
WIDTH_LARGE = 840
|
||||
}
|
||||
|
||||
enum WindowMode {
|
||||
UNDEFINED = 1,
|
||||
FULL_SCREEN,
|
||||
PRIMARY,
|
||||
SECONDARY,
|
||||
FLOATING
|
||||
}
|
||||
|
||||
interface Size {
|
||||
width: number;
|
||||
height: number;
|
||||
}
|
||||
|
||||
interface StatusNaviHeight {
|
||||
status: number;
|
||||
navi: number;
|
||||
}
|
||||
|
||||
interface GetWindowMode {
|
||||
getWindowMode(): Promise<WindowMode>
|
||||
}
|
||||
|
||||
const TAG = "ScreenManager"
|
||||
|
||||
const APP_KEY_SCREEN_MANAGER = 'app_key_screen_manager';
|
||||
|
||||
const SCREEN_ORIENTATION_HORIZONTAL: string = 'isHorizontal';
|
||||
const SCREEN_SIDEBAR: string = 'isSidebar';
|
||||
|
||||
const COLUMN_MARGIN: number = 12;
|
||||
const COLUMN_GUTTER: number = 12;
|
||||
|
||||
type CallbackType = Function
|
||||
|
||||
class ScreenManager {
|
||||
readonly ON_WIN_SIZE_CHANGED = 'on_win_size_changed';
|
||||
readonly ON_LEFT_BLANK_CHANGED = 'on_left_blank_changed';
|
||||
readonly DEFAULT_WIDTH: number = 1920;
|
||||
readonly DEFAULT_HEIGHT: number = 1080;
|
||||
readonly SPLIT_THRESHOLD = 1.7;
|
||||
private winWidth = 0.0;
|
||||
private winHeight = 0.0;
|
||||
private statusBarHeight = 0;
|
||||
private naviBarHeight = 0;
|
||||
private leftBlank: number[] = [0, 0, 0, 0];
|
||||
private events: Map<string, CallbackType[]> = new Map<string, CallbackType[]>();
|
||||
private mainWindow: window.Window = undefined;
|
||||
private globalThis = GlobalContext.getContext();
|
||||
|
||||
// Default orientation
|
||||
private horizontal = deviceInfo.deviceType == 'phone' || deviceInfo.deviceType == 'default' ? false : true;
|
||||
|
||||
// Default sidebar
|
||||
private sidebar = deviceInfo.deviceType == 'phone' || deviceInfo.deviceType == 'default' ? false : true;
|
||||
private windowMode = WindowMode.UNDEFINED;
|
||||
|
||||
constructor() {
|
||||
Log.info(TAG, 'constructor');
|
||||
}
|
||||
|
||||
async initializationSize(win): Promise<void> {
|
||||
this.mainWindow = win;
|
||||
this.setMainWindow(win)
|
||||
await this.checkWindowMode();
|
||||
this.getWindowProperties(win);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add Listeners
|
||||
*
|
||||
* @param event
|
||||
* @param fn
|
||||
*/
|
||||
on(event, fn): void {
|
||||
if (Array.isArray(event)) {
|
||||
for (let i = 0, l = event.length; i < l; i++) {
|
||||
this.on(event[i], fn);
|
||||
}
|
||||
} else {
|
||||
if(this.events.get(event) === null || this.events.get(event) === undefined){
|
||||
this.events.set(event, [])
|
||||
}
|
||||
this.events.get(event).push(fn)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete Listeners
|
||||
*
|
||||
* @param event
|
||||
* @param fn
|
||||
*/
|
||||
off(event, fn): void {
|
||||
if (event == null || event == undefined) {
|
||||
return;
|
||||
}
|
||||
if (Array.isArray(event)) {
|
||||
for (let i = 0, l = event.length; i < l; i++) {
|
||||
this.off(event[i], fn);
|
||||
}
|
||||
}
|
||||
const cbs: CallbackType[] = this.events.get(event);
|
||||
if (!new Boolean(cbs).valueOf()) {
|
||||
return;
|
||||
}
|
||||
if (fn == null || fn == undefined) {
|
||||
return;
|
||||
}
|
||||
let cb;
|
||||
let i = cbs.length;
|
||||
while (i-- > 0) {
|
||||
cb = cbs[i];
|
||||
if (cb === fn || cb.fn === fn) {
|
||||
cbs.splice(i, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private emit(event, argument: Object[]): void {
|
||||
let _self = this;
|
||||
if (!new Boolean(this.events.get(event)).valueOf()) {
|
||||
return;
|
||||
}
|
||||
|
||||
let cbs: CallbackType[] = [];
|
||||
for (let i = 0; i < this.events.get(event).length; i++) {
|
||||
cbs.push(this.events.get(event)[i])
|
||||
}
|
||||
|
||||
if (cbs.length > 0) {
|
||||
for (let i = 0, l = cbs.length; i < l; i++) {
|
||||
let ref = cbs[i];
|
||||
if (ref != null) {
|
||||
try {
|
||||
ref.apply(_self, argument);
|
||||
} catch (e) {
|
||||
new Error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private isLeftBlankInitialized(): boolean {
|
||||
return this.leftBlank[0] != 0 || this.leftBlank[1] != 0 || this.leftBlank[2] != 0 || this.leftBlank[3] != 0;
|
||||
}
|
||||
|
||||
// Unit:vp
|
||||
getWinWidth(): number {
|
||||
return px2vp(this.winWidth);
|
||||
}
|
||||
|
||||
setWinWidth(width: number): void {
|
||||
this.winWidth = width;
|
||||
}
|
||||
|
||||
// Unit:vp
|
||||
getWinHeight(): number {
|
||||
return px2vp(this.winHeight);
|
||||
}
|
||||
|
||||
getStatusBarHeight(): number {
|
||||
return px2vp(this.statusBarHeight);
|
||||
}
|
||||
|
||||
getNaviBarHeight(): number {
|
||||
return px2vp(this.naviBarHeight);
|
||||
}
|
||||
|
||||
async initWindowMode(): Promise<void> {
|
||||
Log.debug(TAG, "start to initialize photos application window mode: " + this.windowMode);
|
||||
}
|
||||
|
||||
isSplitMode(): boolean {
|
||||
return (WindowMode.PRIMARY == this.windowMode || WindowMode.SECONDARY == this.windowMode)
|
||||
}
|
||||
|
||||
async checkWindowMode(): Promise<void> {
|
||||
let before = this.windowMode;
|
||||
let photosWindowStage = this.globalThis.getObject("photosWindowStage") as GetWindowMode;
|
||||
let mode = await photosWindowStage.getWindowMode();
|
||||
Log.info(TAG, "photos application before/current window mode: " + before + "/" + mode);
|
||||
|
||||
if (before == mode) {
|
||||
return;
|
||||
}
|
||||
this.windowMode = mode;
|
||||
if (WindowMode.FULL_SCREEN == this.windowMode) {
|
||||
await this.setFullScreen();
|
||||
} else {
|
||||
this.setSplitScreen();
|
||||
}
|
||||
}
|
||||
|
||||
private setMainWindow(win: window.Window): void {
|
||||
Log.debug(TAG, 'setMainWindow');
|
||||
win.on('windowSizeChange', (data: window.Size): void => {
|
||||
Log.debug(TAG, "windowSizeChange " + JSON.stringify(data));
|
||||
this.checkWindowMode()
|
||||
this.onWinSizeChanged(data);
|
||||
})
|
||||
}
|
||||
|
||||
private getWindowProperties(win: window.Window): void {
|
||||
Log.debug(TAG, 'getWindowProperties');
|
||||
try {
|
||||
let properties = win.getWindowProperties();
|
||||
if(properties.windowRect.width !== 0 && properties.windowRect.height !== 0){
|
||||
this.winWidth = properties.windowRect.width;
|
||||
this.winHeight = properties.windowRect.height;
|
||||
}
|
||||
Log.debug(TAG, "this.winWidth = " + this.winWidth + " this.winHeight = " + this.winHeight);
|
||||
} catch (exception) {
|
||||
console.error("Failed to obtain the window properties. Cause: " + JSON.stringify(exception));
|
||||
}
|
||||
}
|
||||
|
||||
private async setFullScreen(): Promise<void> {
|
||||
let topWindow: window.Window = AppStorage.Get<window.Window>(WindowConstants.MAIN_WINDOW);
|
||||
Log.debug(TAG, 'getTopWindow start');
|
||||
try {
|
||||
await topWindow.setLayoutFullScreen(true)
|
||||
Log.debug(TAG, 'setFullScreen true Succeeded');
|
||||
await this.hideStatusBar(topWindow);
|
||||
} catch (err) {
|
||||
Log.error(TAG, "setFullScreen err: " + err);
|
||||
}
|
||||
}
|
||||
|
||||
setSplitScreen(): void {
|
||||
try {
|
||||
this.statusBarHeight = 0;
|
||||
this.naviBarHeight = 0;
|
||||
this.leftBlank = [0, 0, 0, 0];
|
||||
AppStorage.SetOrCreate<number[]>(BroadcastConstants.LEFT_BLANK, this.leftBlank);
|
||||
} catch (err) {
|
||||
Log.error(TAG, "setSplitScreen err: " + err);
|
||||
}
|
||||
}
|
||||
|
||||
private async hideStatusBar(topWindow: window.Window): Promise<void> {
|
||||
Log.debug(TAG, 'hideStatusBar start');
|
||||
let names: string[] = ['navigation'];
|
||||
Log.debug(TAG, "getTopWindow names: " + names + " end");
|
||||
try {
|
||||
// @ts-ignore
|
||||
await topWindow.setSystemBarEnable(names)
|
||||
Log.debug(TAG, 'hideStatusBar Succeeded');
|
||||
let data = await topWindow.getAvoidArea(0)
|
||||
Log.debug(TAG, "Succeeded in obtaining the area. Data: " + JSON.stringify(data));
|
||||
this.onLeftBlankChanged(data);
|
||||
let barColor = await getResourceString($r('app.color.default_background_color'));
|
||||
let barContentColor = await getResourceString($r('app.color.default_bar_content_color'));
|
||||
if (!new Boolean(barColor).valueOf()) {
|
||||
barColor = '#00FFFFFF';
|
||||
}
|
||||
if (!new Boolean(barContentColor).valueOf()) {
|
||||
barContentColor = '#FF000000';
|
||||
}
|
||||
let systemBarProperties: window.SystemBarProperties = {
|
||||
navigationBarColor: barColor,
|
||||
navigationBarContentColor: barContentColor
|
||||
};
|
||||
await topWindow.setSystemBarProperties(systemBarProperties);
|
||||
Log.info(TAG, 'setStatusBarColor done');
|
||||
} catch (err) {
|
||||
Log.error(TAG, "hideStatusBar err: " + err);
|
||||
}
|
||||
}
|
||||
|
||||
async setNavigationBarColor(barColor: string, barContentColor: string): Promise<void> {
|
||||
Log.debug(TAG, 'setNavigationBarColor start');
|
||||
let topWindow: window.Window = AppStorage.Get<window.Window>(WindowConstants.MAIN_WINDOW);
|
||||
try {
|
||||
let systemBarProperties: window.SystemBarProperties = {
|
||||
navigationBarColor: barColor,
|
||||
navigationBarContentColor: barContentColor
|
||||
};
|
||||
topWindow.setSystemBarProperties(
|
||||
systemBarProperties,
|
||||
(): void => Log.info(TAG, 'setStatusBarColor done')
|
||||
);
|
||||
} catch (err) {
|
||||
Log.error(TAG, "setNavigationBarColor err: " + err);
|
||||
}
|
||||
}
|
||||
|
||||
setSystemUi(isShowBar: boolean): void {
|
||||
Log.debug(TAG, 'setSystemUi start');
|
||||
let topWindow: window.Window = AppStorage.Get<window.Window>(WindowConstants.MAIN_WINDOW);
|
||||
Log.debug(TAG, 'getTopWindow start');
|
||||
let names: string[] = ["navigation"];
|
||||
if (!isShowBar) {
|
||||
names = [];
|
||||
}
|
||||
Log.debug(TAG, "getTopWindow names: " + names + " end");
|
||||
try {
|
||||
// @ts-ignore
|
||||
topWindow.setSystemBarEnable(names, (): void => {
|
||||
Log.debug(TAG, 'setFullScreen Succeeded');
|
||||
if (isShowBar) {
|
||||
topWindow.getAvoidArea(0, (err: Error, data: window.AvoidArea): void => {
|
||||
Log.info(TAG, 'Succeeded in obtaining the area. Data:' + JSON.stringify(data));
|
||||
this.onLeftBlankChanged(data);
|
||||
});
|
||||
}
|
||||
})
|
||||
} catch (err) {
|
||||
Log.error(TAG, "setSystemUi err: " + err);
|
||||
}
|
||||
}
|
||||
|
||||
private onLeftBlankChanged(area: window.AvoidArea): void {
|
||||
if (area == null || area == undefined || area.bottomRect.height == 0) {
|
||||
return;
|
||||
}
|
||||
let leftBlankBefore: StatusNaviHeight = {
|
||||
status: this.statusBarHeight,
|
||||
navi: this.naviBarHeight
|
||||
};
|
||||
this.statusBarHeight = 0;
|
||||
this.naviBarHeight = area.bottomRect.height;
|
||||
this.leftBlank = [this.leftBlank[0], this.leftBlank[1], this.leftBlank[2], area.bottomRect.height];
|
||||
if (leftBlankBefore.status != this.statusBarHeight || leftBlankBefore.navi != this.naviBarHeight) {
|
||||
Log.info(TAG, "leftBlank changed: " + JSON.stringify(leftBlankBefore) + "-" + JSON.stringify(this.leftBlank))
|
||||
AppStorage.SetOrCreate<number[]>(BroadcastConstants.LEFT_BLANK, this.leftBlank);
|
||||
}
|
||||
}
|
||||
|
||||
private onWinSizeChanged(size): void {
|
||||
Log.info(TAG, "onWinSizeChanged " + JSON.stringify(size));
|
||||
if (size == null || size == undefined) {
|
||||
return;
|
||||
}
|
||||
let sizeBefore: Size = {
|
||||
width: this.winWidth,
|
||||
height: this.winHeight
|
||||
};
|
||||
this.winWidth = size.width;
|
||||
this.winHeight = size.height;
|
||||
|
||||
|
||||
if (sizeBefore.width != this.winWidth || sizeBefore.height != this.winHeight) {
|
||||
Log.info(TAG, "winSize changed: " + JSON.stringify(sizeBefore) + " -> " + JSON.stringify(size));
|
||||
this.emit(screenManager.ON_WIN_SIZE_CHANGED, [size]);
|
||||
}
|
||||
}
|
||||
|
||||
private onRotationAngleChanged(angle): void {
|
||||
if (angle == null || angle == undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (angle == 0) {
|
||||
this.horizontal = false;
|
||||
} else {
|
||||
this.horizontal = true;
|
||||
}
|
||||
AppStorage.SetOrCreate<boolean>(SCREEN_ORIENTATION_HORIZONTAL, this.horizontal);
|
||||
}
|
||||
|
||||
isHorizontal(): boolean {
|
||||
if (AppStorage.Get<boolean>(SCREEN_ORIENTATION_HORIZONTAL) == null) {
|
||||
AppStorage.SetOrCreate<boolean>(SCREEN_ORIENTATION_HORIZONTAL, this.horizontal);
|
||||
}
|
||||
return AppStorage.Get<boolean>(SCREEN_ORIENTATION_HORIZONTAL);
|
||||
}
|
||||
|
||||
isSidebar(): boolean {
|
||||
if (AppStorage.Get<boolean>(SCREEN_SIDEBAR) == null) {
|
||||
AppStorage.SetOrCreate<boolean>(SCREEN_SIDEBAR, this.sidebar);
|
||||
}
|
||||
return AppStorage.Get<boolean>(SCREEN_SIDEBAR);
|
||||
}
|
||||
|
||||
getColumnsWidth(count: number): number {
|
||||
let columns = this.getScreenColumns()
|
||||
Log.info(TAG, "getColumnsWidth count is " + count + " columns: " + columns);
|
||||
let columnWidth = (px2vp(this.winWidth) - COLUMN_MARGIN) / columns;
|
||||
return columnWidth * count - COLUMN_GUTTER;
|
||||
}
|
||||
|
||||
getScreenColumns(): number {
|
||||
let width = px2vp(this.winWidth)
|
||||
if (width < ScreenWidth.WIDTH_MEDIUM) {
|
||||
return ColumnSize.COLUMN_FOUR;
|
||||
} else if (width >= ScreenWidth.WIDTH_MEDIUM && width < ScreenWidth.WIDTH_LARGE) {
|
||||
return ColumnSize.COLUMN_EIGHT;
|
||||
} else {
|
||||
return ColumnSize.COLUMN_TWELVE;
|
||||
}
|
||||
}
|
||||
|
||||
setKeepScreenOn(): void {
|
||||
Log.info(TAG, 'setKeepScreenOn start');
|
||||
let topWindow: window.Window = AppStorage.Get<window.Window>('mainWindow');
|
||||
try {
|
||||
topWindow.setKeepScreenOn(true, (): void => Log.info(TAG, 'setKeepScreenOn Succeeded'))
|
||||
} catch (err) {
|
||||
Log.error(TAG, "setKeepScreenOn err: " + err);
|
||||
}
|
||||
}
|
||||
|
||||
setKeepScreenOff(): void {
|
||||
Log.info(TAG, 'setKeepScreenOff start');
|
||||
let topWindow: window.Window = AppStorage.Get<window.Window>('mainWindow');
|
||||
try {
|
||||
topWindow.setKeepScreenOn(false, (): void => Log.info(TAG, 'setKeepScreenOff Succeeded'))
|
||||
} catch (err) {
|
||||
Log.error(TAG, "setKeepScreenOff err: " + err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export let screenManager: ScreenManager = stashOrGetObject<ScreenManager>(new ScreenManager(), TAG);
|
@ -1,39 +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 { stashOrGetObject } from '../utils/SingleInstanceUtils';
|
||||
|
||||
const TAG = ""
|
||||
|
||||
class SelectManager {
|
||||
private status: Map<string, boolean> = new Map<string, boolean>();
|
||||
|
||||
isSelect(key: string, defaultValue: boolean): boolean {
|
||||
if (this.status.has(key)) {
|
||||
return this.status.get(key);
|
||||
} else {
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
setSelect(key: string, value: boolean): void {
|
||||
this.status.set(key, value);
|
||||
}
|
||||
|
||||
deleteSelect(key: string): void {
|
||||
this.status.delete(key);
|
||||
}
|
||||
}
|
||||
|
||||
export let selectManager: SelectManager = stashOrGetObject<SelectManager>(new SelectManager(), TAG);
|
@ -1,187 +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 MediaLib from '@ohos.multimedia.mediaLibrary';
|
||||
import { Log } from '../utils/Log';
|
||||
import { AlbumDataItem } from '../data/AlbumDataItem';
|
||||
import { MediaConstants } from '../constants/MediaConstants';
|
||||
import { mediaModel } from '../model/MediaModel';
|
||||
import { getAlbumDisplayName, getFetchOptions } from '../helper/MediaDataHelper';
|
||||
import { QueryConstants } from '../constants/QueryConstants';
|
||||
|
||||
const TAG = "AlbumDataImpl"
|
||||
|
||||
export class AlbumDataImpl {
|
||||
private blackList: string[] = [];
|
||||
private selectType: number = MediaConstants.SELECT_TYPE_ALL;
|
||||
private deviceId: string = '';
|
||||
|
||||
setBlackList(blackList: string[]): void {
|
||||
this.blackList = blackList;
|
||||
}
|
||||
|
||||
setSelectType(selectType: number): void {
|
||||
this.selectType = selectType;
|
||||
}
|
||||
|
||||
setDeviceId(deviceId: string): void {
|
||||
this.deviceId = deviceId;
|
||||
}
|
||||
|
||||
async reloadAlbumItemData(): Promise<AlbumDataItem[]> {
|
||||
let albumDataItems: AlbumDataItem[] = [];
|
||||
for (let i = 0;i < MediaConstants.ALBUM_DEFAULT_SORT_LIST.length; i++) {
|
||||
await this.getAlbumItem(MediaConstants.ALBUM_DEFAULT_SORT_LIST[i], albumDataItems);
|
||||
}
|
||||
await this.getCommonAlbumItem(albumDataItems);
|
||||
await this.getAlbumItem(MediaConstants.ALBUM_ID_RECYCLE, albumDataItems);
|
||||
return albumDataItems;
|
||||
}
|
||||
|
||||
private async getCommonAlbumItem(albumDataItems: AlbumDataItem[]): Promise<void> {
|
||||
let fetchOption: MediaLib.MediaFetchOptions = await getFetchOptions(this.selectType, "", this.deviceId);
|
||||
if (fetchOption == undefined) {
|
||||
return;
|
||||
}
|
||||
fetchOption.selections = "(" + fetchOption.selections + ") and (" + MediaLib.FileKey.ALBUM_NAME + " <> ? and " + MediaLib.FileKey.ALBUM_NAME + " <> ?)";
|
||||
fetchOption.selectionArgs.push('Camera', 'Screenshots');
|
||||
let albums: MediaLib.Album[] = await mediaModel.getAlbums(fetchOption);
|
||||
for (let i = 0;i < albums.length; i++) {
|
||||
let album: MediaLib.Album = albums[i];
|
||||
if (this.blackList.indexOf(album.albumId.toString()) >= 0) {
|
||||
continue;
|
||||
}
|
||||
let fetchFileResult: MediaLib.FetchFileResult = await album.getFileAssets();
|
||||
try {
|
||||
let count = fetchFileResult.getCount();
|
||||
if (count == 0) {
|
||||
continue;
|
||||
}
|
||||
let item = new AlbumDataItem(album.albumId.toString(), count, album.albumName, this.selectType, this.deviceId);
|
||||
item.update(await fetchFileResult.getFirstObject());
|
||||
albumDataItems.push(item);
|
||||
} catch (err) {
|
||||
Log.error(TAG, "on err: " + JSON.stringify(err));
|
||||
} finally {
|
||||
fetchFileResult.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async getAlbumItem(id: string, albumDataItems: AlbumDataItem[]): Promise<void> {
|
||||
if (this.blackList.indexOf(id) >= 0) {
|
||||
Log.debug(TAG, "no need as in black list");
|
||||
return;
|
||||
}
|
||||
if (this.deviceId.length > 0 && (id != MediaConstants.ALBUM_ID_SNAPSHOT && id != MediaConstants.ALBUM_ID_CAMERA)) {
|
||||
Log.debug(TAG, "no need");
|
||||
return;
|
||||
}
|
||||
let fetchOption: MediaLib.MediaFetchOptions = await getFetchOptions(this.selectType, id, this.deviceId);
|
||||
if (fetchOption == undefined) {
|
||||
Log.warn(TAG, id + " fetchOption is undefined");
|
||||
return;
|
||||
}
|
||||
let item = await mediaModel.getAllMediaItem(id, fetchOption, false);
|
||||
if (item.counts == 0) {
|
||||
Log.warn(TAG, id + " is empty");
|
||||
return;
|
||||
}
|
||||
|
||||
let displayName = await getAlbumDisplayName(id);
|
||||
let albumItem: AlbumDataItem = new AlbumDataItem(id, item.counts, displayName, this.selectType, this.deviceId);
|
||||
albumItem.update(item.fileAsset);
|
||||
albumDataItems.push(albumItem);
|
||||
return;
|
||||
}
|
||||
|
||||
async reloadAlbumListItemData(): Promise<AlbumDataItem[]> {
|
||||
Log.info(TAG, 'reloadAlbumListItemData start');
|
||||
let albumDataItems: AlbumDataItem[] = [];
|
||||
for (let i = 0;i < MediaConstants.ALBUM_DEFAULT_SORT_LIST.length; i++) {
|
||||
await this.getAlbumItem(MediaConstants.ALBUM_DEFAULT_SORT_LIST[i], albumDataItems);
|
||||
}
|
||||
await this.getCommonListAlbumItem(albumDataItems, 0, QueryConstants.ALBUM_COPY_FIRST_PAGE_QUERY_LENGTH);
|
||||
return albumDataItems;
|
||||
}
|
||||
|
||||
async reloadResetAlbumItemData(): Promise<AlbumDataItem[]> {
|
||||
Log.info(TAG, 'reloadResetAlbumItemData start');
|
||||
let albumResetDataItems: AlbumDataItem[] = [];
|
||||
await this.loadAlbumReset(albumResetDataItems, QueryConstants.ALBUM_COPY_FIRST_PAGE_QUERY_LENGTH);
|
||||
await this.getAlbumItem(MediaConstants.ALBUM_ID_RECYCLE, albumResetDataItems);
|
||||
return albumResetDataItems;
|
||||
}
|
||||
|
||||
private async getCommonListAlbumItem(albumDataItems: AlbumDataItem[], start: number, count: number): Promise<void> {
|
||||
let fetchOption: MediaLib.MediaFetchOptions = await this.getLimitCountFetchOption(start, count);
|
||||
if (fetchOption == undefined) {
|
||||
return;
|
||||
}
|
||||
let albums: MediaLib.Album[] = await mediaModel.getAlbums(fetchOption);
|
||||
await this.addAlbumDataItem(albumDataItems, albums);
|
||||
}
|
||||
|
||||
private async addAlbumDataItem(albumDataItems: AlbumDataItem[], albums: MediaLib.Album[]): Promise<void> {
|
||||
for (let i = 0;i < albums.length; i++) {
|
||||
let album: MediaLib.Album = albums[i];
|
||||
if (this.blackList.indexOf(album.albumId.toString()) >= 0) {
|
||||
continue;
|
||||
}
|
||||
let fetchFileResult: MediaLib.FetchFileResult = await album.getFileAssets();
|
||||
try {
|
||||
let count = fetchFileResult.getCount();
|
||||
if (count == 0) {
|
||||
continue;
|
||||
}
|
||||
let item = new AlbumDataItem(album.albumId.toString(), count, album.albumName, this.selectType, this.deviceId);
|
||||
item.update(await fetchFileResult.getFirstObject());
|
||||
albumDataItems.push(item);
|
||||
} catch (err) {
|
||||
Log.error(TAG, "on err: " + JSON.stringify(err));
|
||||
} finally {
|
||||
fetchFileResult.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async getLimitCountFetchOption(start: number, count: number): Promise<MediaLib.MediaFetchOptions> {
|
||||
let fetchOption: MediaLib.MediaFetchOptions = await getFetchOptions(this.selectType, "", this.deviceId);
|
||||
if (fetchOption == undefined) {
|
||||
return;
|
||||
}
|
||||
fetchOption.selections = "(" + fetchOption.selections + ") and (" + MediaLib.FileKey.ALBUM_NAME + " <> ? and " + MediaLib.FileKey.ALBUM_NAME + " <> ?)";
|
||||
fetchOption.selectionArgs.push('Camera', 'Screenshots');
|
||||
fetchOption.order = "bucket_id DESC LIMIT " + start + "," + count;
|
||||
return fetchOption;
|
||||
}
|
||||
|
||||
private async loadAlbumReset(albumDataItems: AlbumDataItem[], count): Promise<void> {
|
||||
Log.info(TAG, "loadReset start");
|
||||
for (let i = 1;; i++) {
|
||||
let fetchOption: MediaLib.MediaFetchOptions = await this.getLimitCountFetchOption(i * count, count);
|
||||
if (fetchOption == undefined) {
|
||||
return;
|
||||
}
|
||||
let albums: MediaLib.Album[] = await mediaModel.getAlbums(fetchOption);
|
||||
await this.addAlbumDataItem(albumDataItems, albums);
|
||||
//last page
|
||||
if (albums.length < count) {
|
||||
Log.info(TAG, "loadReset last ROUND : " + i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
Log.info(TAG, 'loadAlbumReset end');
|
||||
}
|
||||
}
|
@ -1,46 +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 MediaLib from '@ohos.multimedia.mediaLibrary';
|
||||
import { Log } from '../utils/Log';
|
||||
import { mediaModel } from '../model/MediaModel';
|
||||
import { PeerDataItem } from '../data/PeerDataItem';
|
||||
|
||||
const TAG = "DistributedDataImpl"
|
||||
|
||||
export class DistributedDataImpl {
|
||||
async reloadAlbumItemData(): Promise<PeerDataItem[]> {
|
||||
let peerDataItems: PeerDataItem[] = [];
|
||||
let peers: MediaLib.PeerInfo[] = await mediaModel.getActivePeers();
|
||||
Log.info(TAG, "peers: " + JSON.stringify(peers));
|
||||
for (let i = 0;i < peers.length; i++) {
|
||||
let selections: string = MediaLib.FileKey.MEDIA_TYPE + " = ? or " + MediaLib.FileKey.MEDIA_TYPE + " = ?";
|
||||
let selectionArgs: string[] = [MediaLib.MediaType.IMAGE.toString(), MediaLib.MediaType.VIDEO.toString()];
|
||||
let fetchOption: MediaLib.MediaFetchOptions = {
|
||||
selections: selections,
|
||||
selectionArgs: selectionArgs,
|
||||
networkId: peers[i].networkId,
|
||||
order: "date_added DESC"
|
||||
};
|
||||
let item = await mediaModel.getAllCommonMediaItem(fetchOption, false);
|
||||
if (item.counts == 0) {
|
||||
continue;
|
||||
}
|
||||
peerDataItems.push(new PeerDataItem(item.counts, peers[i], item.fileAsset));
|
||||
}
|
||||
|
||||
return peerDataItems;
|
||||
}
|
||||
}
|
@ -1,216 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2023 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 MediaLib from '@ohos.multimedia.mediaLibrary';
|
||||
import { Log } from '../utils/Log';
|
||||
import { WindowConstants } from '../constants/WindowConstants';
|
||||
import { mediaModel } from '../model/MediaModel';
|
||||
import { screenManager } from '../manager/ScreenManager';
|
||||
import { MediaConstants } from '../constants/MediaConstants';
|
||||
import { getFetchOptions } from '../helper/MediaDataHelper';
|
||||
import { MediaDataItem } from '../data/MediaDataItem';
|
||||
import { FavorMediaDataItem } from '../data/FavorMediaDataItem';
|
||||
import { TrashMediaDataItem } from '../data/TrashMediaDataItem';
|
||||
import { mediaDataItemCache } from '../data/MediaDataItemCache';
|
||||
import { trashMediaDataItemCache } from '../data/TrashMediaDataItemCache';
|
||||
|
||||
|
||||
const TAG = "GroupDataImpl"
|
||||
|
||||
export class GroupDataImpl {
|
||||
private selectType: number = MediaConstants.SELECT_TYPE_ALL;
|
||||
private albumId: string = "";
|
||||
private deviceId: string = "";
|
||||
|
||||
setSelectType(selectType: number): void {
|
||||
this.selectType = selectType;
|
||||
}
|
||||
|
||||
setAlbumId(id: string): void {
|
||||
Log.info(TAG, "setAlbumId: " + id);
|
||||
this.albumId = id;
|
||||
}
|
||||
|
||||
setDeviceId(id: string): void {
|
||||
Log.info(TAG, "setDeviceId: " + id);
|
||||
this.deviceId = id;
|
||||
}
|
||||
|
||||
async reloadGroupItemData(isGrid: boolean): Promise<MediaDataItem[]> {
|
||||
if (isGrid) {
|
||||
return this.reloadGridGroupItemData();
|
||||
} else {
|
||||
return this.reloadBrowserGroupItemData();
|
||||
}
|
||||
}
|
||||
|
||||
async reloadBrowserGroupItemData(): Promise<MediaDataItem[]> {
|
||||
Log.debug(TAG, "reloadBrowserGroupItemData");
|
||||
let groupDataItem: MediaDataItem[] = [];
|
||||
let fetchOption = await getFetchOptions(this.selectType, this.albumId, this.deviceId);
|
||||
if (fetchOption == undefined) {
|
||||
return [] as MediaDataItem[];
|
||||
}
|
||||
let count: number = 0;
|
||||
let groupCount: number = this.getCount();
|
||||
let mediaFileAssets = await this.getMediaItemFileAssets(fetchOption, 0, groupCount);
|
||||
if (this.albumId == MediaConstants.ALBUM_ID_FAVOR) {
|
||||
count = (await mediaModel.getAllFavorMediaItem(fetchOption, true)).counts;
|
||||
for (let i = 0;i < count; i++) {
|
||||
let favorMediaItem = new FavorMediaDataItem(fetchOption.selections, fetchOption.selectionArgs, i);
|
||||
if (i < mediaFileAssets.length) {
|
||||
if (mediaDataItemCache.hasKey(mediaFileAssets[i].uri)) {
|
||||
favorMediaItem.favouriteStatus = mediaDataItemCache.get(mediaFileAssets[i].uri).favouriteStatus;
|
||||
favorMediaItem.orientation = mediaDataItemCache.get(mediaFileAssets[i].uri).orientation;
|
||||
}
|
||||
favorMediaItem.update(mediaFileAssets[i]);
|
||||
}
|
||||
groupDataItem.push(favorMediaItem);
|
||||
}
|
||||
} else if (this.albumId == MediaConstants.ALBUM_ID_RECYCLE) {
|
||||
count = (await mediaModel.getAllTrashMediaItem(fetchOption, true)).counts;
|
||||
for (let i = 0;i < count; i++) {
|
||||
let trashMediaItem = new TrashMediaDataItem(fetchOption.selections, fetchOption.selectionArgs, i);
|
||||
if (i < mediaFileAssets.length) {
|
||||
if (mediaDataItemCache.hasKey(mediaFileAssets[i].uri)) {
|
||||
trashMediaItem.favouriteStatus = mediaDataItemCache.get(mediaFileAssets[i].uri).favouriteStatus;
|
||||
trashMediaItem.orientation = mediaDataItemCache.get(mediaFileAssets[i].uri).orientation;
|
||||
}
|
||||
trashMediaItem.update(mediaFileAssets[i]);
|
||||
}
|
||||
groupDataItem.push(trashMediaItem);
|
||||
}
|
||||
} else {
|
||||
count = (await mediaModel.getAllCommonMediaItem(fetchOption, true)).counts;
|
||||
for (let i = 0;i < count; i++) {
|
||||
let mediaItem: MediaDataItem = new MediaDataItem(fetchOption.selections, fetchOption.selectionArgs, this.deviceId, i);
|
||||
if (i < mediaFileAssets.length) {
|
||||
if (mediaDataItemCache.hasKey(mediaFileAssets[i].uri)) {
|
||||
mediaItem = mediaDataItemCache.get(mediaFileAssets[i].uri);
|
||||
} else {
|
||||
mediaDataItemCache.set(mediaFileAssets[i].uri, mediaItem);
|
||||
}
|
||||
mediaItem.update(mediaFileAssets[i]);
|
||||
}
|
||||
groupDataItem.push(mediaItem);
|
||||
}
|
||||
}
|
||||
|
||||
Log.debug(TAG, "reload finish count:" + count);
|
||||
return groupDataItem;
|
||||
}
|
||||
|
||||
async reloadGridGroupItemData(): Promise<MediaDataItem[]> {
|
||||
Log.debug(TAG, "reloadGridGroupItemData");
|
||||
let groupDataItem: MediaDataItem[] = [];
|
||||
let fetchOption = await getFetchOptions(this.selectType, this.albumId, this.deviceId);
|
||||
if (fetchOption == undefined) {
|
||||
return [] as MediaDataItem[];
|
||||
}
|
||||
let groupCount: number = this.getCount();
|
||||
let mediaFileAssets = await this.getMediaItemFileAssets(fetchOption, 0, groupCount);
|
||||
if (this.albumId == MediaConstants.ALBUM_ID_FAVOR) {
|
||||
let count: number = (await mediaModel.getAllFavorMediaItem(fetchOption, true)).counts;
|
||||
for (let i = 0;i < count; i++) {
|
||||
let item = new FavorMediaDataItem(fetchOption.selections, fetchOption.selectionArgs, i);
|
||||
if (i < mediaFileAssets.length) {
|
||||
if (mediaDataItemCache.hasKey(mediaFileAssets[i].uri)) {
|
||||
item = mediaDataItemCache.get(mediaFileAssets[i].uri);
|
||||
}
|
||||
else {
|
||||
mediaDataItemCache.set(mediaFileAssets[i].uri, item);
|
||||
}
|
||||
item.update(mediaFileAssets[i]);
|
||||
}
|
||||
groupDataItem.push(item);
|
||||
}
|
||||
} else if (this.albumId == MediaConstants.ALBUM_ID_RECYCLE) {
|
||||
let count: number = (await mediaModel.getAllTrashMediaItem(fetchOption, true)).counts;
|
||||
for (let i = 0;i < count; i++) {
|
||||
let item = new TrashMediaDataItem(fetchOption.selections, fetchOption.selectionArgs, i);
|
||||
if (i < mediaFileAssets.length) {
|
||||
if (trashMediaDataItemCache.hasKey(mediaFileAssets[i].uri)) {
|
||||
item = trashMediaDataItemCache.get(mediaFileAssets[i].uri);
|
||||
}
|
||||
else
|
||||
{
|
||||
trashMediaDataItemCache.set(mediaFileAssets[i].uri, item);
|
||||
}
|
||||
item.update(mediaFileAssets[i]);
|
||||
}
|
||||
groupDataItem.push(item);
|
||||
}
|
||||
} else {
|
||||
let count: number = (await mediaModel.getAllCommonMediaItem(fetchOption, true)).counts;
|
||||
for (let i = 0;i < count; i++) {
|
||||
let item = new MediaDataItem(fetchOption.selections, fetchOption.selectionArgs, this.deviceId, i);
|
||||
if (i < mediaFileAssets.length) {
|
||||
if (mediaDataItemCache.hasKey(mediaFileAssets[i].uri)) {
|
||||
item = mediaDataItemCache.get(mediaFileAssets[i].uri);
|
||||
} else {
|
||||
mediaDataItemCache.set(mediaFileAssets[i].uri, item);
|
||||
}
|
||||
item.update(mediaFileAssets[i]);
|
||||
}
|
||||
groupDataItem.push(item);
|
||||
}
|
||||
}
|
||||
// do not use await to avoid load cost too much time
|
||||
this.loadReset(fetchOption, groupDataItem, groupCount);
|
||||
|
||||
Log.debug(TAG, "reload finish");
|
||||
return groupDataItem;
|
||||
}
|
||||
|
||||
private async getMediaItemFileAssets(baseFetchOption: MediaLib.MediaFetchOptions, start: number, count: number): Promise<MediaLib.FileAsset[]> {
|
||||
let fetchOption: MediaLib.MediaFetchOptions = {
|
||||
selections: baseFetchOption.selections,
|
||||
selectionArgs: baseFetchOption.selectionArgs,
|
||||
order: "date_added DESC LIMIT " + start + "," + count
|
||||
} as MediaLib.MediaFetchOptions;
|
||||
if (this.deviceId.length > 0) {
|
||||
fetchOption.networkId = this.deviceId;
|
||||
}
|
||||
if (this.albumId == MediaConstants.ALBUM_ID_FAVOR) {
|
||||
return await mediaModel.getAllFavorMediaItems(fetchOption);
|
||||
} else if (this.albumId == MediaConstants.ALBUM_ID_RECYCLE) {
|
||||
return await mediaModel.getAllTrashMediaItems(fetchOption);
|
||||
} else {
|
||||
return await mediaModel.getAllMediaItems(fetchOption);
|
||||
}
|
||||
}
|
||||
|
||||
private getCount(): number {
|
||||
let contentWidth = screenManager.getWinWidth();
|
||||
let maxThumbWidth = px2vp(WindowConstants.GRID_IMAGE_SIZE) * WindowConstants.GRID_MAX_SIZE_RATIO;
|
||||
let columns = Math.max(WindowConstants.GRID_MIN_COUNT, Math.ceil((contentWidth + WindowConstants.GRID_GUTTER) / (maxThumbWidth + WindowConstants.GRID_GUTTER)));
|
||||
let contentHeight = screenManager.getWinHeight() - WindowConstants.ACTION_BAR_HEIGHT - screenManager.getNaviBarHeight();
|
||||
let rows = Math.ceil((contentHeight + WindowConstants.GRID_GUTTER) / (maxThumbWidth + WindowConstants.GRID_GUTTER)) + 4;
|
||||
return columns * rows;
|
||||
}
|
||||
|
||||
private async loadReset(fetchOption: MediaLib.MediaFetchOptions, items: MediaDataItem[], count): Promise<void> {
|
||||
let itemLen = items.length;
|
||||
let countLen = Math.ceil(itemLen / count);
|
||||
for (let i = 1;i < countLen; i++) {
|
||||
let mediaFileAsset: MediaLib.FileAsset[] = await this.getMediaItemFileAssets(fetchOption, i * count, count);
|
||||
for (let j = 0;j < count; j++) {
|
||||
if (i * count + j >= itemLen) {
|
||||
return;
|
||||
}
|
||||
items[i * count+j].update(mediaFileAsset[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,427 +0,0 @@
|
||||
// @ts-nocheck
|
||||
/*
|
||||
* Copyright (c) 2022 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import fileIO from '@ohos.fileio';
|
||||
import MediaLib from '@ohos.multimedia.mediaLibrary';
|
||||
import { MediaConstants } from '../constants/MediaConstants';
|
||||
import { stashOrGetObject } from '../utils/SingleInstanceUtils';
|
||||
import { Log } from '../utils/Log';
|
||||
import { startTrace, finishTrace } from '../utils/TraceControllerUtils';
|
||||
import { hiSysEventDataQueryTimedOut } from '../utils/hisysEventUtil';
|
||||
|
||||
const TAG = "MediaModel"
|
||||
|
||||
export class MediaModelItem {
|
||||
fileAsset: MediaLib.FileAsset;
|
||||
counts: number;
|
||||
}
|
||||
|
||||
class MediaModel {
|
||||
private media: MediaLib.MediaLibrary = undefined;
|
||||
private imageDir: string = "";
|
||||
private cameraDir: string = "";
|
||||
|
||||
constructor() {
|
||||
}
|
||||
|
||||
onCreate(context): void {
|
||||
if (this.media == undefined) {
|
||||
this.media = MediaLib.getMediaLibrary(context);
|
||||
}
|
||||
}
|
||||
|
||||
getMediaLibrary(): MediaLib.MediaLibrary {
|
||||
return this.media;
|
||||
}
|
||||
|
||||
async getPublicDirectory(directoryType: MediaLib.DirectoryType): Promise<string> {
|
||||
if (directoryType == MediaLib.DirectoryType.DIR_IMAGE) {
|
||||
if (this.imageDir == "" || this.imageDir == undefined) {
|
||||
let getPublicDirectoryImage = hiSysEventDataQueryTimedOut('getPublicDirectoryImage')
|
||||
this.imageDir = await this.media.getPublicDirectory(directoryType);
|
||||
clearTimeout(getPublicDirectoryImage);
|
||||
Log.debug(TAG, "imageDir " + this.imageDir);
|
||||
}
|
||||
Log.debug(TAG, "return imageDir " + this.imageDir);
|
||||
return this.imageDir;
|
||||
} else if (directoryType == MediaLib.DirectoryType.DIR_CAMERA) {
|
||||
if (this.cameraDir == "" || this.cameraDir == undefined) {
|
||||
let getPublicDirectoryCamera = hiSysEventDataQueryTimedOut('getPublicDirectoryCamera')
|
||||
this.cameraDir = await this.media.getPublicDirectory(directoryType);
|
||||
clearTimeout(getPublicDirectoryCamera);
|
||||
Log.debug(TAG, "cameraDir " + this.cameraDir);
|
||||
}
|
||||
Log.debug(TAG, "return cameraDir " + this.cameraDir);
|
||||
return this.cameraDir;
|
||||
} else {
|
||||
Log.warn(TAG, "invaild directoryType: " + directoryType);
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
async createOne(mediaType: MediaLib.MediaType, displayName: string, relativePath: string): Promise<MediaLib.FileAsset> {
|
||||
return await this.media.createAsset(mediaType, displayName, relativePath);
|
||||
}
|
||||
|
||||
async copyOne(source: MediaLib.FileAsset, target: MediaLib.FileAsset): Promise<void> {
|
||||
Log.info(TAG, "copy start: src:" + source.uri + " target: " + target.uri);
|
||||
startTrace('openAssetR');
|
||||
let fd: Number = await this.openAsset('R', source);
|
||||
finishTrace('openAssetR');
|
||||
if (fd <= 0) {
|
||||
throw new Error('fd is invalid');
|
||||
}
|
||||
|
||||
startTrace('openAssetRW');
|
||||
let targetFd: Number = await this.openAsset('RW', target);
|
||||
finishTrace('openAssetRW');
|
||||
if (targetFd <= 0) {
|
||||
throw new Error('targetFd is invalid');
|
||||
}
|
||||
|
||||
startTrace('copyFile');
|
||||
await fileIO.copyFile(fd, targetFd);
|
||||
finishTrace('copyFile');
|
||||
|
||||
startTrace('sourceClose');
|
||||
await this.closeAsset(fd, source);
|
||||
finishTrace('sourceClose');
|
||||
startTrace('targetClose');
|
||||
await this.closeAsset(targetFd, target);
|
||||
finishTrace('targetClose');
|
||||
|
||||
Log.debug(TAG, 'copy end');
|
||||
}
|
||||
|
||||
async deleteOne(uri: string): Promise<void> {
|
||||
Log.debug(TAG, "deleteAsset uri: " + uri);
|
||||
await this.media.deleteAsset(uri);
|
||||
}
|
||||
|
||||
async deleteAll(fetchOption: MediaLib.MediaFetchOptions): Promise<void> {
|
||||
Log.info(TAG, 'deleteAll');
|
||||
startTrace('deleteAll');
|
||||
let fetchFileResult: MediaLib.FetchFileResult = null;
|
||||
try {
|
||||
fetchFileResult = await this.media.getFileAssets(fetchOption);
|
||||
Log.debug(TAG, "deleteAll getFileAssets");
|
||||
let deleteAllGetAllObject = hiSysEventDataQueryTimedOut('deleteAllGetAllObject')
|
||||
let fileAssets: MediaLib.FileAsset[] = await fetchFileResult.getAllObject();
|
||||
clearTimeout(deleteAllGetAllObject);
|
||||
for (let i = 0;i < fileAssets.length; i++) {
|
||||
await fileAssets[i].trash(true);
|
||||
}
|
||||
Log.debug(TAG, "deleteAll getFirstObject");
|
||||
} catch (err) {
|
||||
Log.error(TAG, "deleteAll error:" + JSON.stringify(err));
|
||||
} finally {
|
||||
if (fetchFileResult != null) {
|
||||
fetchFileResult.close();
|
||||
}
|
||||
}
|
||||
finishTrace('deleteAll');
|
||||
Log.debug(TAG, 'deleteAll finish');
|
||||
}
|
||||
|
||||
async getAllMediaItems(fetchOption: MediaLib.MediaFetchOptions): Promise<MediaLib.FileAsset[]> {
|
||||
Log.info(TAG, 'getAllMediaItems');
|
||||
startTrace('getAllMediaItems');
|
||||
let fileAssets: MediaLib.FileAsset[] = [];
|
||||
let fetchFileResult: MediaLib.FetchFileResult = null;
|
||||
try {
|
||||
fetchFileResult = await this.media.getFileAssets(fetchOption);
|
||||
Log.debug(TAG, "getAllMediaItems getFileAssets:" + fetchFileResult.getCount());
|
||||
let getAllMediaItemsGetAllObject = hiSysEventDataQueryTimedOut('getAllMediaItemsGetAllObject')
|
||||
fileAssets = await fetchFileResult.getAllObject();
|
||||
clearTimeout(getAllMediaItemsGetAllObject);
|
||||
Log.debug(TAG, "getAllMediaItems getAllObject:" + fileAssets.length);
|
||||
} catch (err) {
|
||||
Log.error(TAG, "getAllMediaItems error:" + JSON.stringify(err));
|
||||
} finally {
|
||||
if (fetchFileResult != null) {
|
||||
fetchFileResult.close();
|
||||
}
|
||||
}
|
||||
finishTrace('getAllMediaItems');
|
||||
Log.debug(TAG, 'getAllMediaItems finish');
|
||||
return fileAssets;
|
||||
}
|
||||
|
||||
async getAllFavorMediaItems(fetchOption: MediaLib.MediaFetchOptions): Promise<MediaLib.FileAsset[]> {
|
||||
Log.info(TAG, 'getAllFavorMediaItems');
|
||||
startTrace('getAllFavorMediaItems');
|
||||
let fileAssets: MediaLib.FileAsset[] = [];
|
||||
let fetchFileResult: MediaLib.FetchFileResult = null;
|
||||
try {
|
||||
let getPrivateAlbumGetAllFavors = hiSysEventDataQueryTimedOut('getPrivateAlbumGetAllFavors')
|
||||
let albums = await this.media.getPrivateAlbum(MediaLib.PrivateAlbumType.TYPE_FAVORITE);
|
||||
clearTimeout(getPrivateAlbumGetAllFavors);
|
||||
if (albums.length > 0) {
|
||||
fetchFileResult = await albums[0].getFileAssets(fetchOption);
|
||||
Log.debug(TAG, "getAllFavorMediaItems getFileAssets");
|
||||
let getAllObjectGetAllFavors = hiSysEventDataQueryTimedOut('getAllObjectGetAllFavors')
|
||||
fileAssets = await fetchFileResult.getAllObject();
|
||||
clearTimeout(getAllObjectGetAllFavors);
|
||||
Log.debug(TAG, "getAllFavorMediaItems getFirstObject");
|
||||
}
|
||||
} catch (err) {
|
||||
Log.error(TAG, "getAllFavorMediaItems error:" + JSON.stringify(err));
|
||||
} finally {
|
||||
if (fetchFileResult != null) {
|
||||
fetchFileResult.close();
|
||||
}
|
||||
}
|
||||
finishTrace('getAllFavorMediaItems');
|
||||
Log.debug(TAG, 'getAllFavorMediaItems finish');
|
||||
return fileAssets;
|
||||
}
|
||||
|
||||
async getAllTrashMediaItems(fetchOption: MediaLib.MediaFetchOptions): Promise<MediaLib.FileAsset[]> {
|
||||
Log.info(TAG, 'getAllTrashMediaItems');
|
||||
startTrace('getAllTrashMediaItems');
|
||||
let fileAssets: MediaLib.FileAsset[] = [];
|
||||
let fetchFileResult: MediaLib.FetchFileResult = null;
|
||||
try {
|
||||
let getPrivateAlbumGetAllTrashItems = hiSysEventDataQueryTimedOut('getPrivateAlbumGetAllTrashItems')
|
||||
let albums = await this.media.getPrivateAlbum(MediaLib.PrivateAlbumType.TYPE_TRASH);
|
||||
clearTimeout(getPrivateAlbumGetAllTrashItems);
|
||||
if (albums.length > 0) {
|
||||
fetchFileResult = await albums[0].getFileAssets(fetchOption);
|
||||
Log.debug(TAG, "getAllTrashMediaItems getFileAssets");
|
||||
let getAllObjectGetAllTrashItems = hiSysEventDataQueryTimedOut('getAllObjectGetAllTrashItems')
|
||||
fileAssets = await fetchFileResult.getAllObject();
|
||||
clearTimeout(getAllObjectGetAllTrashItems);
|
||||
Log.debug(TAG, "getAllTrashMediaItems getFirstObject");
|
||||
}
|
||||
} catch (err) {
|
||||
Log.error(TAG, "getAllTrashMediaItems error:" + JSON.stringify(err));
|
||||
} finally {
|
||||
if (fetchFileResult != null) {
|
||||
fetchFileResult.close();
|
||||
}
|
||||
}
|
||||
finishTrace('getAllTrashMediaItems');
|
||||
Log.debug(TAG, 'getAllTrashMediaItems finish');
|
||||
return fileAssets;
|
||||
}
|
||||
|
||||
async getAllMediaItem(albumId: string, fetchOption: MediaLib.MediaFetchOptions, isCountOnly: boolean): Promise<MediaModelItem> {
|
||||
if (albumId == MediaConstants.ALBUM_ID_FAVOR) {
|
||||
return await this.getAllFavorMediaItem(fetchOption, isCountOnly);
|
||||
} else if (albumId == MediaConstants.ALBUM_ID_RECYCLE) {
|
||||
return await this.getAllTrashMediaItem(fetchOption, isCountOnly);
|
||||
} else {
|
||||
return await this.getAllCommonMediaItem(fetchOption, isCountOnly);
|
||||
}
|
||||
}
|
||||
|
||||
async getAllCommonMediaItem(fetchOption: MediaLib.MediaFetchOptions, isCountOnly: boolean): Promise<MediaModelItem> {
|
||||
Log.info(TAG, 'getAllCommonMediaItem');
|
||||
startTrace('getAllCommonMediaItem');
|
||||
let item: MediaModelItem = new MediaModelItem();
|
||||
let fetchFileResult: MediaLib.FetchFileResult = null;
|
||||
try {
|
||||
fetchFileResult = await this.media.getFileAssets(fetchOption);
|
||||
Log.debug(TAG, "getAllCommonMediaItem getFileAssets");
|
||||
item.counts = await fetchFileResult.getCount();
|
||||
if (!isCountOnly && item.counts > 0) {
|
||||
let getFirstObjectGetAllCommon = hiSysEventDataQueryTimedOut('getFirstObjectGetAllCommon')
|
||||
item.fileAsset = await fetchFileResult.getFirstObject();
|
||||
clearTimeout(getFirstObjectGetAllCommon);
|
||||
}
|
||||
Log.debug(TAG, "getAllCommonMediaItem getFirstObject");
|
||||
} catch (err) {
|
||||
Log.error(TAG, "getAllCommonMediaItem error:" + JSON.stringify(err));
|
||||
} finally {
|
||||
if (fetchFileResult != null) {
|
||||
fetchFileResult.close();
|
||||
}
|
||||
}
|
||||
finishTrace('getAllCommonMediaItem');
|
||||
Log.debug(TAG, 'getAllCommonMediaItem finish');
|
||||
return item;
|
||||
}
|
||||
|
||||
async getAllFavorMediaItem(fetchOption: MediaLib.MediaFetchOptions, isCountOnly: boolean): Promise<MediaModelItem> {
|
||||
Log.info(TAG, 'getAllFavorMediaItem');
|
||||
startTrace('getAllFavorMediaItem');
|
||||
let item: MediaModelItem = new MediaModelItem();
|
||||
let fetchFileResult: MediaLib.FetchFileResult = null;
|
||||
try {
|
||||
let getPrivateAlbumGetAllFavorItem = hiSysEventDataQueryTimedOut('getPrivateAlbumGetAllFavorItem')
|
||||
let albums = await this.media.getPrivateAlbum(MediaLib.PrivateAlbumType.TYPE_FAVORITE);
|
||||
clearTimeout(getPrivateAlbumGetAllFavorItem);
|
||||
if (albums.length > 0) {
|
||||
fetchFileResult = await albums[0].getFileAssets(fetchOption);
|
||||
Log.debug(TAG, "getAllFavorMediaItem getFileAssets");
|
||||
item.counts = await fetchFileResult.getCount();
|
||||
if (!isCountOnly && item.counts > 0) {
|
||||
let getFirstObjectGetAllFavorItem = hiSysEventDataQueryTimedOut('getFirstObjectGetAllFavorItem')
|
||||
item.fileAsset = await fetchFileResult.getFirstObject();
|
||||
clearTimeout(getFirstObjectGetAllFavorItem);
|
||||
}
|
||||
Log.debug(TAG, "getAllFavorMediaItem getFirstObject");
|
||||
}
|
||||
} catch (err) {
|
||||
Log.error(TAG, "getAllFavorMediaItem error:" + JSON.stringify(err));
|
||||
} finally {
|
||||
if (fetchFileResult != null) {
|
||||
fetchFileResult.close();
|
||||
}
|
||||
}
|
||||
finishTrace('getAllFavorMediaItem');
|
||||
Log.debug(TAG, 'getAllFavorMediaItem finish');
|
||||
return item;
|
||||
}
|
||||
|
||||
async getAllTrashMediaItem(fetchOption: MediaLib.MediaFetchOptions, isCountOnly: boolean): Promise<MediaModelItem> {
|
||||
Log.info(TAG, 'getAllTrashMediaItem');
|
||||
startTrace('getAllTrashMediaItem');
|
||||
let item: MediaModelItem = new MediaModelItem();
|
||||
let fetchFileResult: MediaLib.FetchFileResult = null;
|
||||
try {
|
||||
let getPrivateAlbumGetAllTrashItem = hiSysEventDataQueryTimedOut('getPrivateAlbumGetAllTrashItem')
|
||||
let albums = await this.media.getPrivateAlbum(MediaLib.PrivateAlbumType.TYPE_TRASH);
|
||||
clearTimeout(getPrivateAlbumGetAllTrashItem);
|
||||
if (albums.length > 0) {
|
||||
fetchFileResult = await albums[0].getFileAssets(fetchOption);
|
||||
Log.debug(TAG, "getAllTrashMediaItem getFileAssets");
|
||||
item.counts = await fetchFileResult.getCount();
|
||||
if (!isCountOnly && item.counts > 0) {
|
||||
let getFirstObjectGetAllTrashItem = hiSysEventDataQueryTimedOut('getFirstObjectGetAllTrashItem')
|
||||
item.fileAsset = await fetchFileResult.getFirstObject();
|
||||
clearTimeout(getFirstObjectGetAllTrashItem);
|
||||
}
|
||||
Log.debug(TAG, "getAllTrashMediaItem getFirstObject");
|
||||
}
|
||||
} catch (err) {
|
||||
Log.error(TAG, "getAllTrashMediaItem error:" + JSON.stringify(err));
|
||||
} finally {
|
||||
if (fetchFileResult != null) {
|
||||
fetchFileResult.close();
|
||||
}
|
||||
}
|
||||
finishTrace('getAllTrashMediaItem');
|
||||
Log.debug(TAG, 'getAllTrashMediaItem finish');
|
||||
return item
|
||||
}
|
||||
|
||||
async getAlbumCount(fetchOption: MediaLib.MediaFetchOptions): Promise<number> {
|
||||
Log.info(TAG, 'getAlbumCount');
|
||||
startTrace('getAlbumCount');
|
||||
let count = 0;
|
||||
let fetchFileResult: MediaLib.FetchFileResult = null;
|
||||
try {
|
||||
let getAlbumsGetAlbumCount = hiSysEventDataQueryTimedOut('getAlbumsGetAlbumCount')
|
||||
let albums: MediaLib.Album[] = await this.media.getAlbums(fetchOption);
|
||||
clearTimeout(getAlbumsGetAlbumCount);
|
||||
if (albums.length == 0) {
|
||||
return count;
|
||||
}
|
||||
fetchFileResult = await albums[0].getFileAssets();
|
||||
count = fetchFileResult.getCount();
|
||||
} catch (err) {
|
||||
Log.error(TAG, "getAlbumCount error:" + JSON.stringify(err));
|
||||
} finally {
|
||||
if (fetchFileResult != null) {
|
||||
fetchFileResult.close();
|
||||
}
|
||||
}
|
||||
finishTrace('getAlbumCount');
|
||||
Log.debug(TAG, 'getAlbumCount finish');
|
||||
return count;
|
||||
}
|
||||
|
||||
async getActivePeers(): Promise<MediaLib.PeerInfo[]> {
|
||||
Log.info(TAG, 'getActivePeers');
|
||||
startTrace('getActivePeers');
|
||||
let peers: MediaLib.PeerInfo[] = [];
|
||||
try {
|
||||
let getActivePeers = hiSysEventDataQueryTimedOut('getActivePeers')
|
||||
peers = await this.media.getActivePeers();
|
||||
clearTimeout(getActivePeers);
|
||||
} catch (err) {
|
||||
Log.error(TAG, "getActivePeers error:" + JSON.stringify(err));
|
||||
}
|
||||
finishTrace('getActivePeers');
|
||||
Log.debug(TAG, 'getActivePeers finish');
|
||||
return peers;
|
||||
}
|
||||
|
||||
async getAlbums(fetchOption: MediaLib.MediaFetchOptions): Promise<MediaLib.Album[]> {
|
||||
Log.info(TAG, 'getAlbums');
|
||||
startTrace('getAlbums');
|
||||
let albums: MediaLib.Album[] = [];
|
||||
try {
|
||||
let getAlbums = hiSysEventDataQueryTimedOut('getAlbums')
|
||||
albums = await this.media.getAlbums(fetchOption);
|
||||
clearTimeout(getAlbums);
|
||||
Log.info(TAG, "getAlbums albums " + albums.length);
|
||||
} catch (err) {
|
||||
Log.error(TAG, "getAlbums error:" + JSON.stringify(err));
|
||||
}
|
||||
finishTrace('getAlbums');
|
||||
Log.debug(TAG, 'getAlbums finish');
|
||||
return albums;
|
||||
}
|
||||
|
||||
async getTrashMedia(fetchOption: MediaLib.MediaFetchOptions): Promise<MediaLib.FileAsset> {
|
||||
Log.info(TAG, 'getTrashMedia');
|
||||
startTrace('getTrashMedia');
|
||||
let fileAsset: MediaLib.FileAsset = null;
|
||||
let fetchFileResult: MediaLib.FetchFileResult = null;
|
||||
try {
|
||||
let getPrivateAlbumGetTrash = hiSysEventDataQueryTimedOut('getPrivateAlbumGetTrash')
|
||||
let albums = await this.media.getPrivateAlbum(MediaLib.PrivateAlbumType.TYPE_TRASH);
|
||||
clearTimeout(getPrivateAlbumGetTrash);
|
||||
if (albums.length > 0) {
|
||||
fetchFileResult = await albums[0].getFileAssets(fetchOption);
|
||||
Log.debug(TAG, "getTrashMedia getFileAssets");
|
||||
if (fetchFileResult.getCount() > 0) {
|
||||
let getFirstObjectGetTrash = hiSysEventDataQueryTimedOut('getFirstObjectGetTrash')
|
||||
fileAsset = await fetchFileResult.getFirstObject();
|
||||
clearTimeout(getFirstObjectGetTrash);
|
||||
}
|
||||
Log.debug(TAG, "getTrashMedia getFirstObject");
|
||||
}
|
||||
} catch (err) {
|
||||
Log.error(TAG, "getTrashMedia error:" + JSON.stringify(err));
|
||||
} finally {
|
||||
if (fetchFileResult != null) {
|
||||
fetchFileResult.close();
|
||||
}
|
||||
}
|
||||
finishTrace('getTrashMedia');
|
||||
Log.debug(TAG, 'getTrashMedia finish');
|
||||
return fileAsset;
|
||||
}
|
||||
|
||||
async openAsset(mode: string, fileAsset: MediaLib.FileAsset): Promise<number> {
|
||||
Log.debug(TAG, 'openAsset start');
|
||||
let fd: number = await fileAsset.open(mode);
|
||||
Log.info(TAG, "openAsset end. fd: " + fd);
|
||||
if (fd <= 0) {
|
||||
Log.info(TAG, 'openAsset Fail');
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
async closeAsset(fd: number, fileAsset: MediaLib.FileAsset): Promise<void> {
|
||||
Log.debug(TAG, 'closeAsset start');
|
||||
await fileAsset.close(fd);
|
||||
}
|
||||
}
|
||||
|
||||
export let mediaModel: MediaModel = stashOrGetObject<MediaModel>(new MediaModel(), TAG);
|
@ -1,91 +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 { stashOrGetObject } from '../utils/SingleInstanceUtils';
|
||||
import { Log } from '../utils/Log';
|
||||
import { MediaConstants } from '../constants/MediaConstants';
|
||||
import { mediaModel } from '../model/MediaModel';
|
||||
import { MediaObserverCallback } from '../interface/MediaObserverCallback';
|
||||
|
||||
const TAG = "MediaObserver"
|
||||
|
||||
class 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';
|
||||
|
||||
registerObserver(callback: MediaObserverCallback): void {
|
||||
Log.info(TAG, 'registerObserver');
|
||||
if (callback == null) {
|
||||
Log.warn(TAG, 'registerObserver with empty callback');
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.callbacks.indexOf(callback) < 0) {
|
||||
this.callbacks.push(callback);
|
||||
} else {
|
||||
Log.info(TAG, 'registerObserver already exist');
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.callbacks.length == 1) {
|
||||
Log.info(TAG, 'registerObserver register media');
|
||||
try {
|
||||
mediaModel.getMediaLibrary().on('imageChange', (): void => {
|
||||
Log.info(TAG, 'registerObserver on image');
|
||||
this.sendNotify(MediaConstants.MEDIA_TYPE_IMAGE);
|
||||
})
|
||||
mediaModel.getMediaLibrary().on('videoChange', (): void => {
|
||||
Log.info(TAG, 'registerObserver on video');
|
||||
this.sendNotify(MediaConstants.MEDIA_TYPE_VIDEO);
|
||||
})
|
||||
mediaModel.getMediaLibrary().on('deviceChange', (): void => {
|
||||
Log.info(TAG, 'registerObserver on device');
|
||||
this.sendNotify(MediaConstants.MEDIA_TYPE_DEVICE);
|
||||
})
|
||||
mediaModel.getMediaLibrary().on('albumChange', (): void => {
|
||||
Log.info(TAG, 'registerObserver on album');
|
||||
this.sendNotify(MediaConstants.MEDIA_TYPE_ALBUM);
|
||||
})
|
||||
mediaModel.getMediaLibrary().on('remoteFileChange', (): void => {
|
||||
Log.info(TAG, 'registerObserver on remoteFile');
|
||||
this.sendNotify(MediaConstants.MEDIA_TYPE_REMOTE);
|
||||
})
|
||||
} catch (err) {
|
||||
Log.error(TAG, "registerObserver faild, err: " + JSON.stringify(err));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sendNotify(mediaType: string): void {
|
||||
Log.info(TAG, "registerObserver sendNotify size: " + this.callbacks.length);
|
||||
for (let callback of this.callbacks) {
|
||||
callback.onChange(mediaType);
|
||||
}
|
||||
}
|
||||
|
||||
unregisterObserver(callback: MediaObserverCallback): void {
|
||||
Log.info(TAG, 'unregisterObserver');
|
||||
const pos = this.callbacks.indexOf(callback);
|
||||
if (pos >= 0) {
|
||||
this.callbacks.splice(pos, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export let mediaObserver: MediaObserver = stashOrGetObject<MediaObserver>(new MediaObserver(), TAG);
|
@ -1,181 +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 router from '@system.router';
|
||||
import { RouterOptions } from '@system.router';
|
||||
import MediaLib from '@ohos.multimedia.mediaLibrary';
|
||||
import { Log } from '../utils/Log';
|
||||
import { getResourceString } from '../utils/ResourceUtils';
|
||||
import { BroadcastConstants } from '../constants/BroadcastConstants';
|
||||
import { MenuOperationCallback } from './MenuOperationCallback';
|
||||
import { MenuOperation } from './MenuOperation';
|
||||
import { MenuContext } from './MenuContext';
|
||||
import { JumpSourceToMain } from '../data/JumpSourceToMain';
|
||||
import { SimpleAlbumDataItem } from '../data/SimpleAlbumDataItem';
|
||||
import { getFetchOptionsByAlbumItem } from '../helper/MediaDataHelper';
|
||||
import { showToast } from '../utils/UiUtil';
|
||||
import { mediaModel } from '../model/MediaModel';
|
||||
import { AlbumDataItem } from '../data/AlbumDataItem';
|
||||
import { LazyItem } from '../vm/ItemDataSource';
|
||||
import { MediaConstants } from '../constants/MediaConstants';
|
||||
|
||||
const TAG = "AlbumSetNewMenuOperation"
|
||||
|
||||
export class AlbumSetNewMenuOperation implements MenuOperation, MenuOperationCallback {
|
||||
private menuContext: MenuContext;
|
||||
private onOperationEnd: Function;
|
||||
|
||||
constructor(menuContext: MenuContext) {
|
||||
this.menuContext = menuContext;
|
||||
}
|
||||
|
||||
doAction(): void {
|
||||
if (this.menuContext == null) {
|
||||
Log.warn(TAG, 'menuContext is null, return');
|
||||
return;
|
||||
}
|
||||
getResourceString($r('app.string.album_new_album')).then<void, void>((name: string): void => {
|
||||
Log.info(TAG, "The display name is " + name);
|
||||
this.getNewAlbumDisplayName(name).then<void, void>((newAlbumDisplayName: string): void => {
|
||||
Log.info(TAG, "The display name of new album is " + newAlbumDisplayName);
|
||||
|
||||
this.confirmCallback = (displayName: string): Promise<void> => this.confirmCallbackBindImpl(displayName);
|
||||
this.cancelCallback = (): void => this.cancelCallbackBindImpl();
|
||||
|
||||
this.menuContext.broadCast.emit(BroadcastConstants.SHOW_NEW_ALBUM_PHOTO_DIALOG,
|
||||
[newAlbumDisplayName, this.confirmCallback, this.cancelCallback]);
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
private async getNewAlbumDisplayName(name: string): Promise<string> {
|
||||
let relativeRoot = await mediaModel.getPublicDirectory(MediaLib.DirectoryType.DIR_CAMERA);
|
||||
return await this.getNewAlbumDefaultName(relativeRoot, name);
|
||||
}
|
||||
|
||||
private async confirmCallback(displayName: string): Promise<void> {
|
||||
return await this.confirmCallbackBindImpl(displayName)
|
||||
}
|
||||
|
||||
private async confirmCallbackBindImpl(displayName: string): Promise<void> {
|
||||
Log.info(TAG, "AlbumSet new album confirm and the new name is: " + displayName);
|
||||
let relativePath = await mediaModel.getPublicDirectory(MediaLib.DirectoryType.DIR_CAMERA) + displayName + "/";
|
||||
let simpleAlbumDataItem: SimpleAlbumDataItem = new SimpleAlbumDataItem("", displayName, relativePath, "", "");
|
||||
if (displayName != undefined && displayName != null) {
|
||||
let isExit = await this.checkAlbumExit(simpleAlbumDataItem);
|
||||
if (isExit) {
|
||||
getResourceString($r('app.string.name_already_use')).then<void, void>((message: string): void => {
|
||||
showToast(message);
|
||||
})
|
||||
return;
|
||||
}
|
||||
}
|
||||
this.onOperationEnd = this.menuContext.onOperationEnd;
|
||||
let onOperationStart: Function = this.menuContext.onOperationStart;
|
||||
if(onOperationStart != null) onOperationStart();
|
||||
|
||||
if (this.menuContext.jumpSourceToMain == JumpSourceToMain.ALBUM) {
|
||||
Log.info(TAG, 'go back to photo grid');
|
||||
this.menuContext.broadCast.emit(BroadcastConstants.MEDIA_OPERATION, [simpleAlbumDataItem, (): void => this.onCompletedBindImpl()]);
|
||||
} else {
|
||||
let params: Object = {
|
||||
albumInfo: JSON.stringify(simpleAlbumDataItem),
|
||||
isNewAlbum: true
|
||||
};
|
||||
let routerOptions: RouterOptions = {
|
||||
uri: 'feature/albumSelect/view/AlbumSelect',
|
||||
params: params
|
||||
};
|
||||
router.push(routerOptions);
|
||||
this.onCompleted();
|
||||
}
|
||||
}
|
||||
|
||||
private async checkAlbumExit(simpleAlbumDataItem: SimpleAlbumDataItem): Promise<boolean> {
|
||||
let fetchOptions: MediaLib.MediaFetchOptions = await getFetchOptionsByAlbumItem(simpleAlbumDataItem);
|
||||
return await mediaModel.getAlbumCount(fetchOptions) > 0;
|
||||
}
|
||||
|
||||
private cancelCallback(): void {
|
||||
this.cancelCallbackBindImpl()
|
||||
}
|
||||
|
||||
private cancelCallbackBindImpl(): void {
|
||||
Log.info(TAG, 'AlbumSet new album cancel');
|
||||
}
|
||||
|
||||
onCompleted(): void {
|
||||
this.onCompletedBindImpl()
|
||||
}
|
||||
|
||||
private onCompletedBindImpl(): void {
|
||||
Log.info(TAG, 'new album data succeed!');
|
||||
if(this.onOperationEnd != null) this.onOperationEnd();
|
||||
}
|
||||
|
||||
onError(): void {
|
||||
Log.error(TAG, 'new album data failed!');
|
||||
if(this.onOperationEnd != null) this.onOperationEnd();
|
||||
}
|
||||
|
||||
private matchAlbumDefaultName(albumInfo: string, numbers: number[], root: string, prefixName: string): void {
|
||||
let res: string[] = albumInfo.match(new RegExp("^" + root + prefixName + "[1-9][0-9]*/$"));
|
||||
if (res != null) {
|
||||
let number: string[] = res[0].match(new RegExp("[1-9][0-9]*"));
|
||||
numbers.push(parseInt(number[0]));
|
||||
}
|
||||
}
|
||||
|
||||
private async getNewAlbumDefaultName(root: string, prefixName: string): Promise<string> {
|
||||
let numbers : number[] = [];
|
||||
for (let i = 0; i < this.menuContext.dataSource.totalCount(); i++) {
|
||||
let item = (this.menuContext.dataSource.getData(i) as LazyItem<AlbumDataItem>).get();
|
||||
if (MediaConstants.ALBUM_ID_RECYCLE == item.id) {
|
||||
continue;
|
||||
}
|
||||
this.matchAlbumDefaultName(await item.getRelativePath(), numbers, root, prefixName);
|
||||
}
|
||||
if (this.menuContext.albumInfo != null) {
|
||||
this.matchAlbumDefaultName(this.menuContext.albumInfo.relativePath, numbers, root, prefixName);
|
||||
}
|
||||
Log.debug(TAG, 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((a: number, b: number): number => {
|
||||
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);
|
||||
}
|
||||
}
|
@ -1,129 +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 { Log } from '../utils/Log';
|
||||
import { ItemDataSource } from '../vm/ItemDataSource';
|
||||
import { MenuContext } from './MenuContext';
|
||||
import { BroadcastConstants } from '../constants/BroadcastConstants';
|
||||
import { ProcessMenuOperation } from './ProcessMenuOperation';
|
||||
import { MediaDataItem } from '../data/MediaDataItem';
|
||||
import { MediaConstants } from '../constants/MediaConstants';
|
||||
|
||||
const TAG = "BatchDeleteMenuOperation"
|
||||
|
||||
export class BatchDeleteMenuOperation extends ProcessMenuOperation {
|
||||
constructor(menuContext: MenuContext) {
|
||||
super(menuContext);
|
||||
}
|
||||
|
||||
doAction(): void {
|
||||
Log.info(TAG, 'delete doAction');
|
||||
if (this.menuContext == null) {
|
||||
Log.warn(TAG, 'menuContext is null, return');
|
||||
return;
|
||||
}
|
||||
|
||||
let dataSource: ItemDataSource = this.menuContext.dataSource;
|
||||
if (dataSource == null) {
|
||||
this.count = this.menuContext.items.length;
|
||||
} else {
|
||||
this.count = dataSource.getSelectedCount();
|
||||
}
|
||||
if (this.count <= 0) {
|
||||
Log.warn(TAG, 'count <= 0, return');
|
||||
return;
|
||||
}
|
||||
|
||||
this.confirmCallback = (): void => this.confirmCallbackBindImpl();
|
||||
this.cancelCallback = (): void => this.cancelCallbackBindImpl();
|
||||
|
||||
let resource: Resource = this.getDeleteMessageResource(dataSource);
|
||||
let deleteResource: Resource = this.menuContext.albumId == MediaConstants.ALBUM_ID_RECYCLE ? $r('app.string.dialog_recycle') : $r('app.string.dialog_delete');
|
||||
this.menuContext.broadCast.emit(BroadcastConstants.SHOW_DELETE_DIALOG, [resource, deleteResource, this.confirmCallback, this.cancelCallback]);
|
||||
}
|
||||
|
||||
getResourceFromBrowser(): Resource {
|
||||
return this.menuContext.albumId == MediaConstants.ALBUM_ID_RECYCLE ? $r('app.string.recycle_single_file_tips') : $r('app.string.delete_single_file_tips')
|
||||
}
|
||||
|
||||
getResourceFromGrid(dataSource: ItemDataSource): Resource {
|
||||
if (dataSource != null && dataSource.isSelect()) {
|
||||
return this.menuContext.albumId == MediaConstants.ALBUM_ID_RECYCLE ? $r('app.string.recycle_all_files_tips') : $r('app.string.delete_all_files_tips');
|
||||
} else if (this.count == 1) {
|
||||
return this.menuContext.albumId == MediaConstants.ALBUM_ID_RECYCLE ? $r('app.string.recycle_single_file_tips') : $r('app.string.delete_single_file_tips');
|
||||
} else {
|
||||
return this.menuContext.albumId == MediaConstants.ALBUM_ID_RECYCLE ? $r('app.string.recycle_files_tips', this.count) : $r('app.string.delete_files_tips', this.count);
|
||||
}
|
||||
}
|
||||
|
||||
getDeleteMessageResource(dataSource: ItemDataSource): Resource {
|
||||
let resource: Resource;
|
||||
if (this.menuContext.deletePageFromType == BroadcastConstants.DELETE_FROM_BROWSER) {
|
||||
resource = this.getResourceFromBrowser();
|
||||
} else {
|
||||
resource = this.getResourceFromGrid(dataSource);
|
||||
}
|
||||
return resource;
|
||||
}
|
||||
|
||||
confirmCallback(): void {
|
||||
this.confirmCallbackBindImpl()
|
||||
}
|
||||
|
||||
protected confirmCallbackBindImpl(): void {
|
||||
Log.info(TAG, 'Batch delete confirm');
|
||||
AppStorage.SetOrCreate<number>("isDelete", 1);
|
||||
|
||||
// 1. Variable initialization
|
||||
this.onOperationEnd = this.menuContext.onOperationEnd;
|
||||
|
||||
// 2. onDeleteStart exit selection mode
|
||||
let onOperationStart: Function = this.menuContext.onOperationStart;
|
||||
if (onOperationStart != null) {
|
||||
onOperationStart()
|
||||
}
|
||||
|
||||
this.menuContext.broadCast.emit(BroadcastConstants.DELETE_PROGRESS_DIALOG,
|
||||
[$r('app.string.action_delete'), this.count]);
|
||||
|
||||
// 3. selectManager gets the URI of the data and starts processing deletion in the callback
|
||||
let dataSource: ItemDataSource = this.menuContext.dataSource;
|
||||
if (dataSource == null) {
|
||||
this.items = this.menuContext.items;
|
||||
} else {
|
||||
this.items = dataSource.getSelectedItems();
|
||||
}
|
||||
this.processOperation();
|
||||
}
|
||||
|
||||
requestOneBatchOperation(): void {
|
||||
let item = this.items[this.currentBatch] as MediaDataItem;
|
||||
if (item != null) {
|
||||
item.onDelete().then<void, void>((): void => {
|
||||
this.currentBatch++;
|
||||
this.menuContext.broadCast.emit(BroadcastConstants.UPDATE_PROGRESS, [this.getExpectProgress(), this.currentBatch]);
|
||||
this.cyclicOperation();
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
cancelCallback(): void {
|
||||
this.cancelCallbackBindImpl()
|
||||
}
|
||||
|
||||
protected cancelCallbackBindImpl(): void {
|
||||
Log.info(TAG, 'Batch delete cancel');
|
||||
}
|
||||
}
|
@ -1,72 +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 { TrashMediaDataItem } from '../data/TrashMediaDataItem';
|
||||
import { Log } from '../utils/Log';
|
||||
import { ItemDataSource } from '../vm/ItemDataSource';
|
||||
import { MenuContext } from './MenuContext'
|
||||
import { ProcessMenuOperation } from './ProcessMenuOperation';
|
||||
import { BroadcastConstants } from '../constants/BroadcastConstants';
|
||||
|
||||
const TAG = "BatchRecoverMenuOperation"
|
||||
|
||||
export class BatchRecoverMenuOperation extends ProcessMenuOperation {
|
||||
constructor(menuContext: MenuContext) {
|
||||
super(menuContext);
|
||||
}
|
||||
|
||||
doAction(): void {
|
||||
Log.info(TAG, 'delete doAction');
|
||||
if (this.menuContext == null) {
|
||||
Log.warn(TAG, 'menuContext is null, return');
|
||||
return;
|
||||
}
|
||||
|
||||
let dataSource: ItemDataSource = this.menuContext.dataSource;
|
||||
if (dataSource == null) {
|
||||
this.count = this.menuContext.items.length;
|
||||
} else {
|
||||
this.count = dataSource.getSelectedCount();
|
||||
}
|
||||
if (this.count <= 0) {
|
||||
Log.warn(TAG, 'count <= 0, return');
|
||||
return;
|
||||
}
|
||||
|
||||
this.onOperationEnd = this.menuContext.onOperationEnd;
|
||||
let onOperationStart = this.menuContext.onOperationStart;
|
||||
if(onOperationStart != null) onOperationStart();
|
||||
|
||||
this.menuContext.broadCast.emit(BroadcastConstants.DELETE_PROGRESS_DIALOG,
|
||||
[$r('app.string.action_recover'), this.count]);
|
||||
|
||||
|
||||
if (dataSource == null) {
|
||||
this.items = this.menuContext.items;
|
||||
} else {
|
||||
this.items = dataSource.getSelectedItems();
|
||||
}
|
||||
this.processOperation();
|
||||
}
|
||||
|
||||
// Delete a batch of data
|
||||
requestOneBatchOperation(): void {
|
||||
let item = this.items[this.currentBatch] as TrashMediaDataItem;
|
||||
item.onRecover().then<void, void>((): void => {
|
||||
this.currentBatch++;
|
||||
this.menuContext.broadCast.emit(BroadcastConstants.UPDATE_PROGRESS, [this.getExpectProgress(), this.currentBatch]);
|
||||
this.cyclicOperation();
|
||||
})
|
||||
}
|
||||
}
|
@ -1,80 +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 { ItemDataSource } from '../vm/ItemDataSource';
|
||||
import { MenuContext } from './MenuContext';
|
||||
import { BatchDeleteMenuOperation } from './BatchDeleteMenuOperation';
|
||||
import { Log } from '../utils/Log';
|
||||
import { BroadcastConstants } from '../constants/BroadcastConstants';
|
||||
|
||||
const TAG = "ClearRecycleMenuOperation"
|
||||
|
||||
export class ClearRecycleMenuOperation extends BatchDeleteMenuOperation {
|
||||
constructor(menuContext: MenuContext) {
|
||||
super(menuContext);
|
||||
}
|
||||
|
||||
doAction(): void {
|
||||
Log.info(TAG, 'delete doAction');
|
||||
if (this.menuContext == null) {
|
||||
Log.warn(TAG, 'menuContext is null, return');
|
||||
return;
|
||||
}
|
||||
|
||||
let dataSource: ItemDataSource = this.menuContext.dataSource;
|
||||
if (dataSource == null) {
|
||||
this.count = this.menuContext.items.length;
|
||||
} else {
|
||||
//@ts-ignore
|
||||
this.count = dataSource.getItems().length;
|
||||
}
|
||||
if (this.count <= 0) {
|
||||
Log.warn(TAG, 'count <= 0, return');
|
||||
return;
|
||||
}
|
||||
|
||||
this.confirmCallback = (): void => this.confirmCallbackBindImpl();
|
||||
this.cancelCallback = (): void => this.cancelCallbackBindImpl();
|
||||
|
||||
this.menuContext.broadCast.emit(BroadcastConstants.SHOW_DELETE_DIALOG, [$r('app.string.recycleAlbum_clear_message'), $r('app.string.dialog_clear'), this.confirmCallback, this.cancelCallback]);
|
||||
}
|
||||
|
||||
confirmCallback(): void {
|
||||
this.confirmCallbackBindImpl()
|
||||
}
|
||||
|
||||
protected confirmCallbackBindImpl(): void {
|
||||
Log.info(TAG, 'Clear Recycle confirm');
|
||||
// 1. Variable initialization
|
||||
this.onOperationEnd = this.menuContext.onOperationEnd;
|
||||
|
||||
// 2. onDeleteStart exit selection mode
|
||||
let onOperationStart: Function = this.menuContext.onOperationStart;
|
||||
if(onOperationStart != null) onOperationStart();
|
||||
|
||||
this.menuContext.broadCast.emit(BroadcastConstants.DELETE_PROGRESS_DIALOG,
|
||||
[$r('app.string.action_delete'), this.count]);
|
||||
|
||||
// 3. selectManager gets the URI of the data and starts processing deletion in the callback
|
||||
let dataSource: ItemDataSource = this.menuContext.dataSource;
|
||||
if (dataSource == null) {
|
||||
this.items = this.menuContext.items;
|
||||
} else {
|
||||
//@ts-ignore
|
||||
this.items = dataSource.getItems();
|
||||
}
|
||||
this.processOperation();
|
||||
}
|
||||
|
||||
}
|
@ -1,195 +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 MediaLib from '@ohos.multimedia.mediaLibrary';
|
||||
import { MediaConstants } from '../constants/MediaConstants';
|
||||
import { Log } from '../utils/Log';
|
||||
import { MenuContext } from './MenuContext';
|
||||
import { ProcessMenuOperation, FindSameOperation, Assets } from './ProcessMenuOperation';
|
||||
import { BroadcastConstants } from '../constants/BroadcastConstants';
|
||||
import { mediaModel } from '../model/MediaModel';
|
||||
import { MediaOperationType } from '../data/MediaOperationType';
|
||||
import { startTraceWithTaskId, finishTraceWithTaskId } from '../utils/TraceControllerUtils';
|
||||
import { ItemDataSource } from '../vm/ItemDataSource';
|
||||
import { MediaDataItem } from '../data/MediaDataItem';
|
||||
import { SimpleAlbumDataItem } from '../data/SimpleAlbumDataItem';
|
||||
|
||||
const TAG = "CopyMenuOperation"
|
||||
|
||||
export class CopyMenuOperation extends ProcessMenuOperation {
|
||||
private albumInfo: SimpleAlbumDataItem;
|
||||
|
||||
constructor(menuContext: MenuContext) {
|
||||
super(menuContext);
|
||||
this.albumInfo = menuContext.albumInfo;
|
||||
}
|
||||
|
||||
doAction(): void {
|
||||
Log.info(TAG, 'copy doAction');
|
||||
if (this.menuContext == null) {
|
||||
Log.warn(TAG, 'menuContext is null, return');
|
||||
return;
|
||||
}
|
||||
|
||||
let dataSource: ItemDataSource = this.menuContext.dataSource;
|
||||
if (dataSource == null) {
|
||||
this.count = this.menuContext.items.length;
|
||||
} else {
|
||||
this.count = dataSource.getSelectedCount();
|
||||
}
|
||||
if (this.count <= 0) {
|
||||
Log.warn(TAG, 'count <= 0, return');
|
||||
return;
|
||||
}
|
||||
|
||||
this.onOperationEnd = this.menuContext.onOperationEnd;
|
||||
let onOperationStart = this.menuContext.onOperationStart;
|
||||
|
||||
if(onOperationStart != null) onOperationStart();
|
||||
|
||||
if (this.menuContext.deviceId != null) {
|
||||
this.menuContext.broadCast.emit(BroadcastConstants.SHOW_PROGRESS_DIALOG,
|
||||
[$r('app.string.download_progress_message'),
|
||||
MediaOperationType.Copy, (): void => this.cancelFuncBindImpl()]);
|
||||
} else {
|
||||
this.menuContext.broadCast.emit(BroadcastConstants.SHOW_PROGRESS_DIALOG,
|
||||
[$r('app.string.copy_progress_message', this.albumInfo.displayName),
|
||||
MediaOperationType.Copy, (): void => this.cancelFuncBindImpl()]);
|
||||
}
|
||||
|
||||
if (dataSource == null) {
|
||||
this.items = this.menuContext.items;
|
||||
} else {
|
||||
this.items = dataSource.getSelectedItems();
|
||||
}
|
||||
this.processOperation();
|
||||
}
|
||||
|
||||
requestOneBatchOperation(): void {
|
||||
let item = this.items[this.currentBatch++] as MediaDataItem;
|
||||
this.copyOne(item);
|
||||
}
|
||||
|
||||
private async copyOne(item: MediaDataItem): Promise<void> {
|
||||
if (this.menuContext.deviceId != null) {
|
||||
let path = await mediaModel.getPublicDirectory(MediaLib.DirectoryType.DIR_CAMERA) + MediaConstants.REMOTE_ALBUM_PATH + "/";
|
||||
this.albumInfo = new SimpleAlbumDataItem("", "", path, "", "");
|
||||
|
||||
}
|
||||
let fileAsset = await item.loadFileAsset();
|
||||
let assets: Assets = await this.getFileCopyOrMoveInfo(fileAsset, this.albumInfo);
|
||||
if (this.menuContext.deviceId != null) {
|
||||
let displayName = assets.sourceAsset.displayName;
|
||||
let index = displayName.lastIndexOf('.');
|
||||
let start = displayName.lastIndexOf('_');
|
||||
displayName = displayName.slice(0, start) + "_$" + new Date().getTime() + "$" + displayName.slice(index);
|
||||
let params: Object = {
|
||||
mediaType: assets.sourceAsset.mediaType,
|
||||
name: displayName,
|
||||
path: this.albumInfo.relativePath
|
||||
};
|
||||
this.copy(assets.sourceAsset, null, params);
|
||||
return;
|
||||
}
|
||||
if (assets.targetAsset != null) {
|
||||
if (assets.targetAsset.uri == assets.sourceAsset.uri) {
|
||||
Log.info(TAG, 'copy same fileAsset');
|
||||
this.onOperateContinue();
|
||||
return;
|
||||
}
|
||||
Log.info(TAG, 'show find same file dialog');
|
||||
switch (this.findSameOperation) {
|
||||
case FindSameOperation.NONE:
|
||||
this.menuContext.broadCast.emit(BroadcastConstants.FIND_SAME_FILE_DIALOG,
|
||||
[assets, this.count, (): void => {
|
||||
this.copy(assets.sourceAsset, assets.targetAsset);
|
||||
}, (): void => this.onOperateContinueBindImpl(), (): void => this.onOperateCancelledBindImpl(),
|
||||
(newOp: number): void => this.setFindSameOperation(newOp)]);
|
||||
break;
|
||||
case FindSameOperation.REPLACE:
|
||||
this.copy(assets.sourceAsset, assets.targetAsset);
|
||||
break;
|
||||
case FindSameOperation.SKIP:
|
||||
this.onOperateContinue();
|
||||
break;
|
||||
default:
|
||||
Log.warn(TAG, "findSameOperation is error " + this.findSameOperation);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
let params: Object = {
|
||||
mediaType: assets.sourceAsset.mediaType,
|
||||
name: assets.sourceAsset.displayName,
|
||||
path: this.albumInfo.relativePath
|
||||
};
|
||||
this.copy(assets.sourceAsset, null, params);
|
||||
}
|
||||
}
|
||||
|
||||
async copy(source, target, param?): Promise<void> {
|
||||
try {
|
||||
if (!Boolean<object>(target).valueOf()) {
|
||||
startTraceWithTaskId('create', this.currentBatch);
|
||||
target = await mediaModel.createOne(param.mediaType, param.name, param.path);
|
||||
finishTraceWithTaskId('create', this.currentBatch);
|
||||
if (target == null) {
|
||||
Log.warn(TAG, "Target file creat failed when copyFile!");
|
||||
this.onError();
|
||||
return;
|
||||
}
|
||||
}
|
||||
startTraceWithTaskId('openWriteClose', this.currentBatch);
|
||||
await mediaModel.copyOne(source, target);
|
||||
finishTraceWithTaskId('openWriteClose', this.currentBatch);
|
||||
this.onCompleted();
|
||||
} catch (error) {
|
||||
finishTraceWithTaskId('create', this.currentBatch);
|
||||
Log.error(TAG, "copyFile is error " + error);
|
||||
this.onError();
|
||||
}
|
||||
}
|
||||
|
||||
cancelFunc(): void {
|
||||
this.cancelFuncBindImpl()
|
||||
}
|
||||
|
||||
private cancelFuncBindImpl(): void {
|
||||
Log.info(TAG, "progress cancel");
|
||||
this.onOperatePause();
|
||||
let cancelMessage = $r('app.string.copy_cancel_message', this.getExpectProgress().toString());
|
||||
|
||||
if(this.menuContext.broadCast != null) {
|
||||
if (this.menuContext.deviceId != null) {
|
||||
this.menuContext.broadCast.emit(BroadcastConstants.DOWNLOAD_CANCEL_OPERATE,
|
||||
[cancelMessage, (): void => this.onOperateContinueBindImpl(), (): void => this.onOperateCancelledBindImpl()]);
|
||||
} else {
|
||||
this.menuContext.broadCast.emit(BroadcastConstants.CANCEL_OPERATE,
|
||||
[cancelMessage, (): void => this.onOperateContinueBindImpl(), (): void => this.onOperateCancelledBindImpl()]);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Copy cancel callback
|
||||
onOperateContinue(): void {
|
||||
this.onOperateContinueBindImpl()
|
||||
}
|
||||
|
||||
private onOperateContinueBindImpl(): void {
|
||||
Log.info(TAG, 'Operate Continue');
|
||||
this.isPause = false;
|
||||
this.cyclicOperation();
|
||||
}
|
||||
}
|
@ -1,91 +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 { ItemDataSource } from '../vm/ItemDataSource';
|
||||
import { MediaDataItem } from '../data/MediaDataItem'
|
||||
import { Broadcast } from '../utils/Broadcast'
|
||||
import { SimpleAlbumDataItem } from '../data/SimpleAlbumDataItem';
|
||||
|
||||
export class MenuContext {
|
||||
items: MediaDataItem[] = [];
|
||||
dataSource: ItemDataSource;
|
||||
|
||||
albumInfo: SimpleAlbumDataItem;
|
||||
|
||||
broadCast: Broadcast;
|
||||
onOperationStart: Function;
|
||||
onOperationCancel: Function;
|
||||
onOperationEnd: Function;
|
||||
|
||||
jumpSourceToMain: number;
|
||||
deviceId: string;
|
||||
|
||||
albumId: string;
|
||||
deletePageFromType: number; // 0. photoBrowser 1. photoGridPage
|
||||
|
||||
withDeletePageFromType(deletePageFromType: number): MenuContext {
|
||||
this.deletePageFromType = deletePageFromType;
|
||||
return this;
|
||||
}
|
||||
|
||||
withItems(items: MediaDataItem[]): MenuContext {
|
||||
this.items = items;
|
||||
return this;
|
||||
}
|
||||
|
||||
withAlbumId(albumId: string): MenuContext {
|
||||
this.albumId = albumId;
|
||||
return this;
|
||||
}
|
||||
|
||||
withDataSource(dataSource): MenuContext{
|
||||
this.dataSource = dataSource;
|
||||
return this;
|
||||
}
|
||||
|
||||
withOperationStartCallback(onOperationStart: Function): MenuContext {
|
||||
this.onOperationStart = onOperationStart;
|
||||
return this;
|
||||
}
|
||||
|
||||
withOperationEndCallback(onOperationEnd: Function): MenuContext {
|
||||
this.onOperationEnd = onOperationEnd;
|
||||
return this;
|
||||
}
|
||||
|
||||
withOperationCancelCallback(onOperationCancel: Function): MenuContext {
|
||||
this.onOperationCancel = onOperationCancel;
|
||||
return this;
|
||||
}
|
||||
|
||||
withBroadCast(param: Broadcast): MenuContext {
|
||||
this.broadCast = param;
|
||||
return this;
|
||||
}
|
||||
|
||||
withJumpSourceToMain(jumpSourceToMain: number): MenuContext {
|
||||
this.jumpSourceToMain = jumpSourceToMain;
|
||||
return this;
|
||||
}
|
||||
|
||||
withRemoteDevice(deviceId): MenuContext {
|
||||
this.deviceId = deviceId;
|
||||
return this;
|
||||
}
|
||||
|
||||
withAlbumInfo(albumInfo: SimpleAlbumDataItem): MenuContext {
|
||||
this.albumInfo = albumInfo;
|
||||
return this;
|
||||
}
|
||||
}
|
@ -1,150 +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 MediaLib from '@ohos.multimedia.mediaLibrary';
|
||||
import { mediaModel } from '../model/MediaModel';
|
||||
import { Log } from '../utils/Log';
|
||||
import { MenuContext } from './MenuContext';
|
||||
import { ProcessMenuOperation, FindSameOperation } from './ProcessMenuOperation';
|
||||
import { MediaOperationType } from '../data/MediaOperationType';
|
||||
import { BroadcastConstants } from '../constants/BroadcastConstants';
|
||||
import { startTraceWithTaskId, finishTraceWithTaskId } from '../utils/TraceControllerUtils';
|
||||
import { ItemDataSource } from '../vm/ItemDataSource';
|
||||
import { MediaDataItem } from '../data/MediaDataItem';
|
||||
import { SimpleAlbumDataItem } from '../data/SimpleAlbumDataItem';
|
||||
|
||||
const TAG = "MoveMenuOperation"
|
||||
|
||||
export class MoveMenuOperation extends ProcessMenuOperation {
|
||||
albumInfo: SimpleAlbumDataItem;
|
||||
|
||||
constructor(menuContext: MenuContext) {
|
||||
super(menuContext);
|
||||
this.albumInfo = menuContext.albumInfo;
|
||||
}
|
||||
|
||||
doAction(): void {
|
||||
Log.info(TAG, 'move doAction');
|
||||
if (this.menuContext == null) {
|
||||
Log.warn(TAG, 'menuContext is null, return');
|
||||
return;
|
||||
}
|
||||
|
||||
let dataSource: ItemDataSource = this.menuContext.dataSource;
|
||||
if (dataSource == null) {
|
||||
this.count = this.menuContext.items.length;
|
||||
} else {
|
||||
this.count = dataSource.getSelectedCount();
|
||||
}
|
||||
if (this.count <= 0) {
|
||||
Log.warn(TAG, 'count <= 0, return');
|
||||
return;
|
||||
}
|
||||
|
||||
this.onOperationEnd = this.menuContext.onOperationEnd;
|
||||
let onOperationStart = this.menuContext.onOperationStart;
|
||||
|
||||
if(onOperationStart != null) onOperationStart();
|
||||
|
||||
this.menuContext.broadCast.emit(
|
||||
BroadcastConstants.SHOW_PROGRESS_DIALOG, [$r('app.string.move_progress_message', this.albumInfo.displayName),
|
||||
MediaOperationType.Move, (): void => this.cancelFuncBindImpl()]);
|
||||
|
||||
if (dataSource == null) {
|
||||
this.items = this.menuContext.items;
|
||||
} else {
|
||||
this.items = dataSource.getSelectedItems();
|
||||
}
|
||||
this.processOperation();
|
||||
}
|
||||
|
||||
requestOneBatchOperation(): void {
|
||||
let item = this.items[this.currentBatch++] as MediaDataItem;
|
||||
this.moveOne(item);
|
||||
}
|
||||
|
||||
private async moveOne(item: MediaDataItem): Promise<void> {
|
||||
let fileAsset = await item.loadFileAsset();
|
||||
let assets = await this.getFileCopyOrMoveInfo(fileAsset, this.albumInfo);
|
||||
if (assets.targetAsset != null) {
|
||||
if (assets.targetAsset.uri == assets.sourceAsset.uri) {
|
||||
Log.info(TAG, 'move same fileAsset');
|
||||
this.onOperateContinue();
|
||||
return;
|
||||
}
|
||||
Log.info(TAG, 'show find same file dialog');
|
||||
switch (this.findSameOperation) {
|
||||
case FindSameOperation.NONE:
|
||||
this.menuContext.broadCast.emit(BroadcastConstants.FIND_SAME_FILE_DIALOG,
|
||||
[assets, this.count, (): void => {
|
||||
this.move(assets.sourceAsset, this.albumInfo.relativePath, assets.targetAsset);
|
||||
}, (): void => this.onOperateContinueBindImpl(), (): void => this.onOperateCancelledBindImpl(),
|
||||
(newOp: number): void => this.setFindSameOperationBindImpl(newOp)]);
|
||||
break;
|
||||
case FindSameOperation.REPLACE:
|
||||
this.move(assets.sourceAsset, this.albumInfo.relativePath, assets.targetAsset);
|
||||
break;
|
||||
case FindSameOperation.SKIP:
|
||||
this.onOperateContinue();
|
||||
break;
|
||||
default:
|
||||
Log.warn(TAG, "findSameOperation is error " + this.findSameOperation);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
this.move(assets.sourceAsset, this.albumInfo.relativePath);
|
||||
}
|
||||
}
|
||||
|
||||
async move(file: MediaLib.FileAsset, path: string, targetFile?): Promise<void> {
|
||||
startTraceWithTaskId('move', this.currentBatch);
|
||||
try {
|
||||
if (targetFile != null) {
|
||||
await mediaModel.deleteOne(targetFile.uri);
|
||||
}
|
||||
file.relativePath = path;
|
||||
file.commitModify();
|
||||
finishTraceWithTaskId('move', this.currentBatch);
|
||||
this.onCompleted();
|
||||
} catch (error) {
|
||||
Log.error(TAG, "move error: " + error)
|
||||
this.onError();
|
||||
}
|
||||
}
|
||||
|
||||
cancelFunc(): void {
|
||||
this.cancelFuncBindImpl()
|
||||
}
|
||||
|
||||
private cancelFuncBindImpl(): void {
|
||||
Log.info(TAG, "progress cancel");
|
||||
this.onOperatePause();
|
||||
let cancelMessage = $r('app.string.move_cancel_message', this.getExpectProgress().toString());
|
||||
if(this.menuContext.broadCast != null) {
|
||||
this.menuContext.broadCast.emit(BroadcastConstants.CANCEL_OPERATE,
|
||||
[cancelMessage, (): void => this.onOperateContinueBindImpl(), (): void => this.onOperateCancelledBindImpl()]);
|
||||
}
|
||||
}
|
||||
|
||||
// Move cancel callback
|
||||
onOperateContinue(): void {
|
||||
this.onOperateContinueBindImpl()
|
||||
}
|
||||
|
||||
private onOperateContinueBindImpl(): void {
|
||||
Log.info(TAG, 'Operate Continue');
|
||||
this.isPause = false;
|
||||
this.cyclicOperation();
|
||||
}
|
||||
}
|
@ -1,192 +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 MediaLib from '@ohos.multimedia.mediaLibrary';
|
||||
import { AsyncCallback } from '../interface/AsyncCallback';
|
||||
import { Log } from '../utils/Log';
|
||||
import { MenuOperationCallback } from './MenuOperationCallback';
|
||||
import { MenuOperation } from './MenuOperation';
|
||||
import { MenuContext } from './MenuContext';
|
||||
import { BroadcastConstants } from '../constants/BroadcastConstants';
|
||||
import { startTraceWithTaskId, finishTraceWithTaskId } from '../utils/TraceControllerUtils';
|
||||
import { getFetchOptionsByItem } from '../helper/MediaDataHelper';
|
||||
import { SimpleAlbumDataItem } from '../data/SimpleAlbumDataItem';
|
||||
import { mediaModel } from '../model/MediaModel';
|
||||
|
||||
export enum FindSameOperation {
|
||||
NONE,
|
||||
REPLACE,
|
||||
SKIP
|
||||
}
|
||||
|
||||
export interface Assets {
|
||||
sourceAsset: MediaLib.FileAsset,
|
||||
targetAsset: MediaLib.FileAsset
|
||||
}
|
||||
|
||||
const TAG = "ProcessMenuOperation"
|
||||
|
||||
export class ProcessMenuOperation implements MenuOperation, AsyncCallback<String[]>, MenuOperationCallback {
|
||||
// Number of data operated in a batch
|
||||
readonly BATCH_SIZE: number = 1;
|
||||
|
||||
// Maximum progress
|
||||
readonly MAX_PROGRESS: number = 100;
|
||||
items: Object[] = [];
|
||||
menuContext: MenuContext;
|
||||
uris: string[];
|
||||
count: number;
|
||||
onOperationEnd: Function;
|
||||
|
||||
// Total batches operated
|
||||
totalBatches: number;
|
||||
|
||||
// Currently operated batch
|
||||
currentBatch: number = 0;
|
||||
successBatch: number = 0;
|
||||
isCancelled: boolean = false;
|
||||
startTime: number;
|
||||
isPause: boolean = false;
|
||||
isError: boolean = false;
|
||||
findSameOperation: number = FindSameOperation.NONE;
|
||||
requestTime: number;
|
||||
|
||||
constructor(menuContext: MenuContext) {
|
||||
this.menuContext = menuContext;
|
||||
this.requestTime = Date.now();
|
||||
}
|
||||
|
||||
doAction(): void {
|
||||
}
|
||||
|
||||
// Asynchronous callback for getSelection
|
||||
callback(uris: string[]): void {
|
||||
this.callbackBindImpl(uris)
|
||||
}
|
||||
|
||||
protected callbackBindImpl(uris: string[]): void {
|
||||
}
|
||||
|
||||
onCompleted(): void {
|
||||
Log.info(TAG, "onCompleted " + this.isPause);
|
||||
this.successBatch++;
|
||||
if (!this.isPause) {
|
||||
this.cyclicOperation();
|
||||
}
|
||||
}
|
||||
|
||||
onError(): void {
|
||||
Log.error(TAG, "Operate the " + this.currentBatch + " batch data error, total " + this.totalBatches + " batches");
|
||||
this.isError = true;
|
||||
this.cyclicOperation();
|
||||
}
|
||||
|
||||
// Start processing operation
|
||||
processOperation(): void {
|
||||
Log.info(TAG, 'processOperation start');
|
||||
startTraceWithTaskId('ProgressOperation', this.requestTime);
|
||||
let length = this.items.length;
|
||||
Log.info(TAG, "selected count: " + this.count + ", uris's length: " + length);
|
||||
// Batch deletion
|
||||
this.totalBatches = Math.floor(length / this.BATCH_SIZE) + (((length % this.BATCH_SIZE) ? 1 : 0) as number);
|
||||
Log.info(TAG, "The count to be operate is " + length + ", operate in " + this.totalBatches + " batches");
|
||||
if (this.isCancelled) {
|
||||
this.isCancelled = false;
|
||||
}
|
||||
this.startTime = Date.now();
|
||||
|
||||
this.requestOneBatchOperation()
|
||||
}
|
||||
|
||||
// Batch circular deletion
|
||||
cyclicOperation(): void {
|
||||
Log.info(TAG, 'cyclicOperation');
|
||||
this.menuContext.broadCast.emit(BroadcastConstants.UPDATE_PROGRESS, [this.getExpectProgress(), this.currentBatch]);
|
||||
|
||||
if (this.isCancelled) {
|
||||
this.onProcessDone();
|
||||
}
|
||||
|
||||
if (this.currentBatch >= this.totalBatches || this.isError) {
|
||||
this.onProcessDone();
|
||||
} else {
|
||||
this.requestOneBatchOperation();
|
||||
}
|
||||
}
|
||||
|
||||
// Operate a batch of data
|
||||
requestOneBatchOperation(): void {
|
||||
}
|
||||
|
||||
onProcessDone(): void {
|
||||
this.menuContext.broadCast.emit(BroadcastConstants.UPDATE_PROGRESS, [100]);
|
||||
this.findSameOperation = FindSameOperation.NONE;
|
||||
if (this.startTime != null) {
|
||||
let operateCount = this.currentBatch >= this.totalBatches ? this.count : this.currentBatch * this.BATCH_SIZE;
|
||||
let costTime = Date.now() - this.startTime;
|
||||
Log.debug(TAG, "process data operate done, operate " + operateCount + " items, cost time " + costTime +
|
||||
" ms, average " + (costTime / operateCount) + " ms/item.");
|
||||
}
|
||||
this.isCancelled = false;
|
||||
finishTraceWithTaskId('ProgressOperation', this.requestTime);
|
||||
if(this.onOperationEnd != null) this.onOperationEnd(this.isError, this.successBatch, this.count);
|
||||
}
|
||||
|
||||
// Operate cancel callback
|
||||
onOperateCancelled(): void {
|
||||
this.onOperateCancelledBindImpl()
|
||||
}
|
||||
|
||||
protected onOperateCancelledBindImpl(): void {
|
||||
Log.info(TAG, 'Operate Cancel');
|
||||
this.isCancelled = true;
|
||||
this.onProcessDone();
|
||||
}
|
||||
|
||||
// Operate cancel callback
|
||||
onOperatePause(): void {
|
||||
Log.info(TAG, 'Operate Pause');
|
||||
this.isPause = true;
|
||||
}
|
||||
|
||||
// Calculate the operation progress according to the batch
|
||||
getExpectProgress(): number {
|
||||
Log.info(TAG, 'getExpectProgress');
|
||||
let progress = Math.min(
|
||||
Math.floor(this.MAX_PROGRESS * this.currentBatch * this.BATCH_SIZE / this.count), this.MAX_PROGRESS);
|
||||
return progress;
|
||||
}
|
||||
|
||||
setFindSameOperation(newOperation: number): void {
|
||||
this.setFindSameOperationBindImpl(newOperation)
|
||||
}
|
||||
|
||||
protected setFindSameOperationBindImpl(newOperation: number): void {
|
||||
Log.info(TAG, "setFindSameOperation " + newOperation);
|
||||
this.findSameOperation = newOperation;
|
||||
}
|
||||
|
||||
async getFileCopyOrMoveInfo(fileAsset: MediaLib.FileAsset, albumInfo: SimpleAlbumDataItem): Promise<Assets> {
|
||||
Log.debug(TAG, 'getFileCopyOrMoveInfo start');
|
||||
let item: SimpleAlbumDataItem = new SimpleAlbumDataItem("", fileAsset.displayName, albumInfo.relativePath, "", "");
|
||||
let fetchOptions = await getFetchOptionsByItem(item);
|
||||
let targetAsset = (await mediaModel.getAllCommonMediaItem(fetchOptions, false)).fileAsset;
|
||||
if (targetAsset == null || targetAsset == undefined) {
|
||||
Log.debug(TAG, 'targetAsset not found');
|
||||
}
|
||||
|
||||
let assets: Assets = { sourceAsset: fileAsset, targetAsset: targetAsset };
|
||||
return assets;
|
||||
}
|
||||
}
|
@ -1,61 +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 Want from '@ohos.application.Want';
|
||||
import { Log } from '../utils/Log';
|
||||
import { startAbility } from '../utils/AbilityUtils';
|
||||
import { MenuOperation } from './MenuOperation';
|
||||
import { MenuContext } from './MenuContext';
|
||||
import { ItemDataSource } from '../vm/ItemDataSource';
|
||||
|
||||
const TAG = "ShareMenuOperation"
|
||||
|
||||
export class ShareMenuOperation implements MenuOperation {
|
||||
private menuContext: MenuContext;
|
||||
private uris: string[];
|
||||
|
||||
constructor(menuContext: MenuContext) {
|
||||
this.menuContext = menuContext;
|
||||
}
|
||||
|
||||
doAction(): void {
|
||||
if (this.menuContext == null) {
|
||||
Log.warn(TAG, 'menuContext is null, return');
|
||||
return;
|
||||
}
|
||||
let dataSource: ItemDataSource = this.menuContext.dataSource;
|
||||
if (dataSource == null) {
|
||||
return;
|
||||
}
|
||||
this.uris = dataSource.getSelectedUris();
|
||||
this.shareFileAsset();
|
||||
}
|
||||
|
||||
shareFileAsset(): void {
|
||||
Log.info(TAG, 'shareFileAsset');
|
||||
let param1: Map<string, string[]> = new Map<string, string[]>();
|
||||
param1.set('ability.params.stream', this.uris);
|
||||
let param2: Map<string, Object> = new Map<string, Object>();
|
||||
param2.set('action', 'ability.intent.SEND_DATA');
|
||||
param2.set('type', '*/*');
|
||||
param2.set('parameters', Object.fromEntries<Object>(param1));
|
||||
let param3: Map<string, Object> = new Map<string, Object>();
|
||||
param3.set('ability.want.params.INTENT', Object.fromEntries<Object>(param2));
|
||||
let want: Want = {
|
||||
action: 'com.huawei.intent.action.hwCHOOSER',
|
||||
parameters: Object.fromEntries<Object>(param3)
|
||||
};
|
||||
startAbility(want);
|
||||
}
|
||||
}
|
@ -1,130 +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 { Log } from '../utils/Log';
|
||||
import { ItemDataSource } from '../vm/ItemDataSource';
|
||||
import { MenuContext } from './MenuContext';
|
||||
import { BroadcastConstants } from '../constants/BroadcastConstants';
|
||||
import { ProcessMenuOperation } from './ProcessMenuOperation';
|
||||
import { MediaDataItem } from '../data/MediaDataItem';
|
||||
import { MediaConstants } from '../constants/MediaConstants';
|
||||
import { getIdFromUri } from '../utils/StringUtil';
|
||||
|
||||
const TAG = "ThirdDeleteMenuOperation"
|
||||
|
||||
export class ThirdDeleteOperation extends ProcessMenuOperation {
|
||||
constructor(menuContext: MenuContext) {
|
||||
super(menuContext);
|
||||
this.callback = (uris: string[]): void => this.callbackBindImpl(uris);
|
||||
}
|
||||
|
||||
doAction(): void {
|
||||
Log.info(TAG, 'delete doAction');
|
||||
if (this.menuContext == null) {
|
||||
Log.warn(TAG, 'menuContext is null, return');
|
||||
return;
|
||||
}
|
||||
|
||||
let dataSource: ItemDataSource = this.menuContext.dataSource;
|
||||
if (dataSource == null) {
|
||||
this.count = this.menuContext.items.length;
|
||||
} else {
|
||||
this.count = dataSource.getSelectedCount();
|
||||
}
|
||||
if (this.count <= 0) {
|
||||
Log.warn(TAG, 'count <= 0, return');
|
||||
return;
|
||||
}
|
||||
|
||||
this.confirmCallback = (): void => this.confirmCallbackBindImpl();
|
||||
this.cancelCallback = (): void => this.cancelCallbackBindImpl();
|
||||
|
||||
let resource: Resource = this.getDeleteMessageResource(dataSource);
|
||||
let deleteResource: Resource = $r('app.string.dialog_delete');
|
||||
this.menuContext.broadCast.emit(BroadcastConstants.SHOW_THIRD_DELETE_DIALOG, [resource, deleteResource, this.confirmCallback, this.cancelCallback]);
|
||||
}
|
||||
|
||||
getResourceFromBrowser(): Resource {
|
||||
return $r('app.string.delete_single_file_tips')
|
||||
}
|
||||
|
||||
getResourceFromGrid(dataSource: ItemDataSource): Resource {
|
||||
if (dataSource != null && dataSource.isSelect()) {
|
||||
return this.menuContext.albumId == MediaConstants.ALBUM_ID_RECYCLE ? $r('app.string.recycle_all_files_tips') : $r('app.string.delete_all_files_tips');
|
||||
} else if (this.count == 1) {
|
||||
return this.menuContext.albumId == MediaConstants.ALBUM_ID_RECYCLE ? $r('app.string.recycle_single_file_tips') : $r('app.string.delete_single_file_tips');
|
||||
} else {
|
||||
return this.menuContext.albumId == MediaConstants.ALBUM_ID_RECYCLE ? $r('app.string.recycle_files_tips', this.count) : $r('app.string.delete_files_tips', this.count);
|
||||
}
|
||||
}
|
||||
|
||||
getDeleteMessageResource(dataSource: ItemDataSource): Resource {
|
||||
let resource: Resource = this.getResourceFromGrid(dataSource);
|
||||
return resource;
|
||||
}
|
||||
|
||||
confirmCallback(): void {
|
||||
this.confirmCallbackBindImpl()
|
||||
}
|
||||
|
||||
private confirmCallbackBindImpl(): void {
|
||||
Log.info(TAG, 'Batch delete confirm');
|
||||
AppStorage.SetOrCreate<number>("isDelete", 1);
|
||||
|
||||
// 1. Variable initialization
|
||||
this.onOperationEnd = this.menuContext.onOperationEnd;
|
||||
|
||||
// 2. onDeleteStart exit selection mode
|
||||
let onOperationStart: Function = this.menuContext.onOperationStart;
|
||||
if(onOperationStart != null) onOperationStart();
|
||||
|
||||
this.menuContext.broadCast.emit(BroadcastConstants.DELETE_PROGRESS_DIALOG,
|
||||
[$r('app.string.action_delete'), this.count]);
|
||||
|
||||
// 3. selectManager gets the URI of the data and starts processing deletion in the callback
|
||||
let dataSource: ItemDataSource = this.menuContext.dataSource;
|
||||
if (dataSource == null) {
|
||||
this.items = this.menuContext.items;
|
||||
} else {
|
||||
this.items = dataSource.getSelectedItems();
|
||||
}
|
||||
this.processOperation();
|
||||
}
|
||||
|
||||
requestOneBatchOperation(): void {
|
||||
Log.info(TAG, 'requestOneBatchOperation');
|
||||
if (this.isCancelled) {
|
||||
return;
|
||||
}
|
||||
let item = this.items[this.currentBatch] as MediaDataItem;
|
||||
if (item != null) {
|
||||
item.onDelete().then<void, void>((): void => {
|
||||
this.currentBatch++;
|
||||
this.menuContext.broadCast.emit(BroadcastConstants.UPDATE_PROGRESS, [this.getExpectProgress(), this.currentBatch]);
|
||||
this.cyclicOperation();
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
cancelCallback(): void {
|
||||
this.cancelCallbackBindImpl()
|
||||
}
|
||||
|
||||
private cancelCallbackBindImpl(): void {
|
||||
Log.info(TAG, 'Batch delete cancel');
|
||||
let onOperationCancel: Function = this.menuContext.onOperationCancel;
|
||||
if(onOperationCancel != null) onOperationCancel();
|
||||
}
|
||||
}
|
@ -1,40 +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 Want from "@ohos.application.Want";
|
||||
import common from '@ohos.app.ability.common';
|
||||
import { Log } from '../utils/Log';
|
||||
import { GlobalContext } from "../utils/GlobalContext";
|
||||
|
||||
const TAG = "AbilityUtils"
|
||||
|
||||
export async function startAbility(want: Want): Promise<void> {
|
||||
try {
|
||||
let appContext: common.UIAbilityContext = GlobalContext.getContext().getObject("appContext") as common.UIAbilityContext;
|
||||
await appContext.startAbility(want);
|
||||
Log.debug(TAG, 'raul startAbility complete');
|
||||
} catch (error) {
|
||||
Log.error(TAG, "raul startAbility failed, error: " + JSON.stringify(error));
|
||||
}
|
||||
}
|
||||
|
||||
export async function terminateSelf(): Promise<void> {
|
||||
let appContext: common.UIAbilityContext = GlobalContext.getContext().getObject("appContext") as common.UIAbilityContext;
|
||||
await appContext.terminateSelf();
|
||||
}
|
||||
|
||||
export async function terminateSelfWithResult(parameter): Promise<void> {
|
||||
let appContext: common.UIAbilityContext = GlobalContext.getContext().getObject("appContext") as common.UIAbilityContext;
|
||||
await appContext.terminateSelfWithResult(parameter);
|
||||
}
|
@ -1,83 +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.
|
||||
*/
|
||||
|
||||
type CallbackType = Function
|
||||
|
||||
export class Broadcast {
|
||||
private callBackArray: Map<string, CallbackType[]> = new Map<string, CallbackType[]>();
|
||||
|
||||
constructor() {
|
||||
}
|
||||
|
||||
public on(event: string, callback: CallbackType): void {
|
||||
if(this.callBackArray.get(event) === null || this.callBackArray.get(event) === undefined){
|
||||
this.callBackArray.set(event, [])
|
||||
}
|
||||
this.callBackArray.get(event).push(callback)
|
||||
}
|
||||
|
||||
public off(event: string | null, callback: CallbackType | null): void {
|
||||
if (event == null) {
|
||||
this.callBackArray.clear();
|
||||
}
|
||||
|
||||
const cbs: CallbackType[] = this.callBackArray.get(event);
|
||||
if (!Boolean<Function[]>(cbs).valueOf()) {
|
||||
return;
|
||||
}
|
||||
if (callback == null) {
|
||||
this.callBackArray.set(event, null);
|
||||
}
|
||||
let cb;
|
||||
let l = cbs.length;
|
||||
for (let i = 0; i < l; i++) {
|
||||
cb = cbs[i];
|
||||
if (cb === callback || cb.fn === callback) {
|
||||
cbs.splice(i, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public emit(event: string, args: Object[]): void {
|
||||
let _self = this;
|
||||
if (!Boolean<Function[]>(this.callBackArray.get(event)).valueOf()) {
|
||||
return;
|
||||
}
|
||||
|
||||
let cbs: CallbackType[] = [];
|
||||
for (let i = 0; i < this.callBackArray.get(event).length; i++) {
|
||||
cbs.push(this.callBackArray.get(event)[i])
|
||||
}
|
||||
|
||||
if (cbs != null) {
|
||||
let l = cbs.length;
|
||||
for (let i = 0; i < l; i++) {
|
||||
try {
|
||||
cbs[i].apply(_self, args);
|
||||
} catch (e) {
|
||||
new Error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public release(): void {
|
||||
this.callBackArray.forEach((array: Object[]): void => {
|
||||
array.length = 0;
|
||||
});
|
||||
this.callBackArray.clear();
|
||||
}
|
||||
}
|
@ -1,140 +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 preferences from '@ohos.data.preferences';
|
||||
import common from '@ohos.app.ability.common';
|
||||
import { Log } from '../utils/Log';
|
||||
import { stashOrGetObject } from './SingleInstanceUtils';
|
||||
import { GlobalContext } from '../utils/GlobalContext';
|
||||
|
||||
const TAG = "DataStoreUtil"
|
||||
|
||||
class DataStoreUtil {
|
||||
private preferences: preferences.Preferences | null = null;
|
||||
private static readonly PREFERENCES_KEY_MY_FORM_STORE = 'myFormStore';
|
||||
private static readonly FROM_DATA_STORE_UTIL = 'form_data_store_util';
|
||||
private globalThis = GlobalContext.getContext();
|
||||
|
||||
constructor() {
|
||||
Log.info(TAG, 'constructor');
|
||||
}
|
||||
|
||||
public getInstance(): DataStoreUtil {
|
||||
if (AppStorage.Get<void>( DataStoreUtil.FROM_DATA_STORE_UTIL) == null) {
|
||||
AppStorage.SetOrCreate<DataStoreUtil>( DataStoreUtil.FROM_DATA_STORE_UTIL, new DataStoreUtil());
|
||||
}
|
||||
return AppStorage.Get<DataStoreUtil>( DataStoreUtil.FROM_DATA_STORE_UTIL);
|
||||
}
|
||||
|
||||
public async init(): Promise<void> {
|
||||
Log.debug(TAG, 'init start!');
|
||||
if (this.preferences != undefined) {
|
||||
Log.info(TAG, "init preferences before");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
let context: common.Context = this.globalThis.getObject("applicationContext") as common.Context;
|
||||
this.preferences = await preferences.getPreferences(context, DataStoreUtil.PREFERENCES_KEY_MY_FORM_STORE);
|
||||
Log.info(TAG, "init preferences " + preferences);
|
||||
} catch (err) {
|
||||
Log.error(TAG, "init err " + err);
|
||||
}
|
||||
Log.debug(TAG, 'init end!');
|
||||
}
|
||||
|
||||
public async getData(key: string, defValue): Promise<Object> {
|
||||
Log.debug(TAG, 'getData start!');
|
||||
if (this.preferences == undefined) {
|
||||
Log.warn(TAG, "getData preferences is undefined");
|
||||
await this.init();
|
||||
}
|
||||
let temValue = defValue;
|
||||
try {
|
||||
temValue = await this.preferences.get(key, defValue);
|
||||
Log.debug(TAG, "The value of startup is " + temValue);
|
||||
} catch (err) {
|
||||
Log.error(TAG, "Get the value failed with err: " + err);
|
||||
}
|
||||
return temValue;
|
||||
}
|
||||
|
||||
public async putData(key: string, value): Promise<void> {
|
||||
Log.debug(TAG, 'putData start!');
|
||||
if (this.preferences == undefined) {
|
||||
Log.warn(TAG, 'putData preferences is undefined');
|
||||
await this.init();
|
||||
}
|
||||
|
||||
try {
|
||||
await this.preferences.put(key, value);
|
||||
Log.debug(TAG, 'Put the value successfully.');
|
||||
} catch (err) {
|
||||
Log.error(TAG, "Put the value failed with err: " + err);
|
||||
}
|
||||
}
|
||||
|
||||
public async delData(key: string): Promise<void> {
|
||||
Log.debug(TAG, 'delData start!');
|
||||
if (this.preferences == undefined) {
|
||||
Log.warn(TAG, "delData preferences is undefined");
|
||||
await this.init();
|
||||
}
|
||||
try {
|
||||
await this.preferences.delete(key);
|
||||
Log.debug(TAG, "Delete the value successfully.");
|
||||
} catch (err) {
|
||||
Log.error(TAG, "Delete the value failed with err: " + err);
|
||||
}
|
||||
}
|
||||
|
||||
public async flush(): Promise<void> {
|
||||
Log.debug(TAG, 'flush start!');
|
||||
if (this.preferences == undefined) {
|
||||
Log.warn(TAG, "flush preferences is undefined");
|
||||
await this.init();
|
||||
}
|
||||
await this.preferences.flush();
|
||||
}
|
||||
|
||||
public async hasData(key: string): Promise<boolean> {
|
||||
Log.debug(TAG, "hasData start! preferences " + this.preferences);
|
||||
let ret = false;
|
||||
if (this.preferences == undefined) {
|
||||
Log.warn(TAG, "hasData preferences is undefined");
|
||||
await this.init();
|
||||
}
|
||||
try {
|
||||
ret = await this.preferences.has(key);
|
||||
Log.debug(TAG, "hasData the value successfully.");
|
||||
} catch (err) {
|
||||
ret = false;
|
||||
Log.error(TAG, "hasData the value failed with err: " + err);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public async removeCache(): Promise<void> {
|
||||
Log.info(TAG,'removeCache start!');
|
||||
let context: common.Context = this.globalThis.getObject("applicationContext") as common.Context;
|
||||
await preferences.removePreferencesFromCache(context, DataStoreUtil.PREFERENCES_KEY_MY_FORM_STORE).then<void, void>((): void => {
|
||||
Log.info(TAG, "this.preferences = " + this.preferences);
|
||||
this.preferences = undefined;
|
||||
Log.info(TAG,"removeCache successfully.")
|
||||
}).catch<void>((err: Error): void => {
|
||||
Log.info(TAG,"removeCache failed with err: " + err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export let dataStore: DataStoreUtil = stashOrGetObject<DataStoreUtil>(new DataStoreUtil(), TAG);
|
@ -1,208 +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 { Log } from './Log';
|
||||
import i18n from '@ohos.i18n';
|
||||
import Intl from '@ohos.intl';
|
||||
|
||||
const TAG = "DateUtil"
|
||||
|
||||
export class DateUtil {
|
||||
private static LANGUAGE_LOCALES_MAP: Map<string, string> = null;
|
||||
|
||||
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 = 3600;
|
||||
|
||||
private static initLanguageLocalesMap(): void {
|
||||
if (DateUtil.LANGUAGE_LOCALES_MAP == null) {
|
||||
DateUtil.LANGUAGE_LOCALES_MAP = new Map<string, string>();
|
||||
DateUtil.LANGUAGE_LOCALES_MAP.set("zh", "zh-CN");
|
||||
DateUtil.LANGUAGE_LOCALES_MAP.set("en", "en-US");
|
||||
}
|
||||
}
|
||||
|
||||
// Get the date after localization (year-month-day)
|
||||
public static getLocalizedDate(milliseconds: number): string {
|
||||
let locales: string = this.getLocales();
|
||||
|
||||
return new Intl.DateTimeFormat(locales, this.buildDateTimeOpt('numeric', 'long', 'numeric', '', '')).format(new Date(milliseconds));
|
||||
}
|
||||
|
||||
public static format(time: Date, format_s?: string): string {
|
||||
if (!Boolean<string>(format_s).valueOf()) {
|
||||
return time.valueOf().toString();
|
||||
}
|
||||
let opts: Map<string, number> = new Map<string, number>();
|
||||
opts.set('MM', time.getMonth() + 1);
|
||||
opts.set('dd', time.getDate());
|
||||
opts.set('HH', time.getHours());
|
||||
opts.set('mm', time.getMinutes());
|
||||
opts.set('ss', time.getSeconds());
|
||||
|
||||
let check: RegExp = new RegExp("/(y+)/");
|
||||
if (check.test(format_s)) {
|
||||
format_s = format_s.replace('yyyy', time.getFullYear().toString().substr(0));
|
||||
}
|
||||
opts.forEach((value: number, key: string): void => {
|
||||
if (new RegExp('(' + key + ')').test(format_s)) {
|
||||
format_s = format_s.replace(key,
|
||||
(key.length == 1)
|
||||
? value.toString()
|
||||
: (("00" + value).substr(value.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
|
||||
public static getGroupDataLocalizedDate(milliseconds: number): Resource {
|
||||
let date = new Date(milliseconds);
|
||||
let today = new Date();
|
||||
if (date.getFullYear() == today.getFullYear() && date.getMonth() == today.getMonth()) {
|
||||
if (date.getDate() == today.getDate()) {
|
||||
return $r('app.string.date_today');
|
||||
}
|
||||
if (today.getDate() - date.getDate() == 1) {
|
||||
return $r('app.string.date_yesterday');
|
||||
}
|
||||
}
|
||||
return $r('app.string.common_place_holder', this.getLocalizedDate(milliseconds));
|
||||
}
|
||||
|
||||
public static getLocalizedYear(milliseconds: number): Resource {
|
||||
let locales: string = this.getLocales();
|
||||
|
||||
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, this.buildDateTimeOpt('numeric', 'long', '', '', '')).format(new Date(milliseconds));
|
||||
}
|
||||
|
||||
public static getLocalizedYearString(milliseconds: number): string {
|
||||
let locales: string = this.getLocales();
|
||||
|
||||
return new Intl.DateTimeFormat(locales, this.buildDateTimeOpt('numeric', '', '', '', '')).format(new Date(milliseconds)).toString();
|
||||
}
|
||||
|
||||
public static getLocalizedTime(milliseconds: number): string {
|
||||
let locales: string = this.getLocales();
|
||||
let is24HourClock = i18n.is24HourClock();
|
||||
Log.info(TAG, "get is24HourClock " + is24HourClock);
|
||||
|
||||
return new Intl.DateTimeFormat(locales, this.buildDateTimeOpt('', '', '', (!Boolean<boolean>(is24HourClock).valueOf() ? '2-digit' : 'numeric'), '2-digit')).format(new Date(milliseconds));
|
||||
}
|
||||
|
||||
static getLocales(): string {
|
||||
DateUtil.initLanguageLocalesMap();
|
||||
let systemLocale: string = i18n.getSystemLanguage().toString();
|
||||
let language = systemLocale.split('-')[0];
|
||||
let locales: string = this.LANGUAGE_LOCALES_MAP.get("en");
|
||||
if (this.LANGUAGE_LOCALES_MAP.has(language)) {
|
||||
locales = this.LANGUAGE_LOCALES_MAP.get(language);
|
||||
}
|
||||
return locales;
|
||||
}
|
||||
|
||||
// Format duration
|
||||
public static getFormattedDuration(milliSecond: number): string {
|
||||
if (milliSecond == null) {
|
||||
Log.warn(TAG, 'getFormattedDuration, input is null!');
|
||||
return '00:00';
|
||||
}
|
||||
if (milliSecond <= 0) {
|
||||
Log.warn(TAG, 'getFormattedDuration, input is negative number!');
|
||||
return '00:00';
|
||||
}
|
||||
if (milliSecond < this.MILLISECONDS_PER_SECOND) {
|
||||
return '00:01';
|
||||
}
|
||||
let seconds = Math.floor(milliSecond / this.MILLISECONDS_PER_SECOND);
|
||||
let hourTime: number = Math.floor(seconds / this.SECONDS_PER_HOUR);
|
||||
let minuteTime: number = Math.floor(Math.floor(seconds / this.SECONDS_PER_MINUTE) % this.SECONDS_PER_MINUTE);
|
||||
let secondTime: number = Math.floor(seconds % this.SECONDS_PER_MINUTE);
|
||||
if (hourTime > 0) {
|
||||
return hourTime + ":" + this.checkTime(minuteTime) + ":" + this.checkTime(secondTime);
|
||||
} else {
|
||||
return this.checkTime(minuteTime) + ":" + this.checkTime(secondTime);
|
||||
}
|
||||
}
|
||||
|
||||
private static checkTime(time: number): string{
|
||||
if (time < 0) {
|
||||
Log.warn(TAG, 'checkTime, input is negative number!');
|
||||
return '00';
|
||||
}
|
||||
let formatTime: string = time.toString();
|
||||
if (time < DateUtil.FORMAT_DECIMAL) {
|
||||
let zeroString = '0';
|
||||
formatTime = zeroString.concat(formatTime);
|
||||
}
|
||||
return formatTime;
|
||||
}
|
||||
|
||||
public static isTheSameDay(startTime: number, endTime: number): boolean {
|
||||
if (startTime == null || endTime == null) {
|
||||
return false;
|
||||
}
|
||||
const startTimeMs = new Date(startTime).setHours(0, 0, 0, 0);
|
||||
const endTimeMs = new Date(endTime).setHours(0, 0, 0, 0);
|
||||
return startTimeMs === endTimeMs ? true : false;
|
||||
}
|
||||
|
||||
public static isTheSameYear(startTime: number, endTime: number): boolean {
|
||||
if (startTime == null || endTime == null) {
|
||||
return false;
|
||||
}
|
||||
const startYear = new Date(startTime).getFullYear();
|
||||
const endYear = new Date(endTime).getFullYear();
|
||||
return startYear === endYear ? true : false;
|
||||
}
|
||||
|
||||
public static buildDateTimeOpt(year: string, month: string, day: string, hour: string, minute: string): Object {
|
||||
let obj: Object = {
|
||||
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: '',
|
||||
};
|
||||
return obj;
|
||||
}
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
|
||||
export class GlobalContext {
|
||||
private constructor() { }
|
||||
private static instance: GlobalContext;
|
||||
private _objects = new Map<string, Object>();
|
||||
|
||||
public static getContext(): GlobalContext {
|
||||
if (!(new Boolean(GlobalContext.instance)).valueOf()) {
|
||||
GlobalContext.instance = new GlobalContext();
|
||||
}
|
||||
return GlobalContext.instance;
|
||||
}
|
||||
|
||||
getObject(value: string): Object {
|
||||
return this._objects.get(value);
|
||||
}
|
||||
|
||||
setObject(key: string, objectClass: Object): void {
|
||||
this._objects.set(key, objectClass);
|
||||
}
|
||||
}
|
@ -1,61 +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 { Log } from '../utils/Log';
|
||||
|
||||
const TAG = "ImageUtil"
|
||||
const MAX_BIT = 30;
|
||||
const BIT_SIXTEEN = 16;
|
||||
const BIT_EIGHT = 8;
|
||||
const BIT_FOUR = 4;
|
||||
const BIT_TWO = 2;
|
||||
const BIT_ONE = 1;
|
||||
|
||||
export function computeSampleSize(width: number, height: number, minSideLength: number, maxNumOfPixels: number): number {
|
||||
if (width == 0 || height == 0 || minSideLength == 0 || maxNumOfPixels == 0) {
|
||||
return 2;
|
||||
}
|
||||
let initialSize = computeInitialSampleSize(width, height, minSideLength, maxNumOfPixels);
|
||||
Log.info(TAG, "initialSize: " + initialSize);
|
||||
return initialSize <= 8 ? nextPowerOf2(initialSize) : Math.floor((initialSize + 8 - 1) / 8) * 8;
|
||||
}
|
||||
|
||||
function computeInitialSampleSize(width: number, height: number, minSideLength: number, maxNumOfPixels: number): number {
|
||||
if ((maxNumOfPixels == -1) && (minSideLength == -1)) {
|
||||
return 1;
|
||||
}
|
||||
let lowerBound: number = (maxNumOfPixels == -1) ? 1 : Math.ceil(Math.sqrt((width * height) / maxNumOfPixels));
|
||||
Log.info(TAG, "lowerBound: " + lowerBound);
|
||||
if (minSideLength == -1) {
|
||||
return lowerBound;
|
||||
} else {
|
||||
let sampleSize = Math.min(width / minSideLength, height / minSideLength);
|
||||
return Math.max(sampleSize, lowerBound);
|
||||
}
|
||||
}
|
||||
|
||||
function nextPowerOf2(value: number): number {
|
||||
let useValue = value;
|
||||
if (useValue <= 0 || useValue > (1 << MAX_BIT)) {
|
||||
}
|
||||
useValue -= 1;
|
||||
useValue |= useValue >> BIT_SIXTEEN;
|
||||
useValue |= useValue >> BIT_EIGHT;
|
||||
useValue |= useValue >> BIT_FOUR;
|
||||
useValue |= useValue >> BIT_TWO;
|
||||
useValue |= useValue >> BIT_ONE;
|
||||
Log.info(TAG, "nextPowerOf2:" + useValue);
|
||||
return useValue + 1;
|
||||
}
|
@ -1,57 +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 HiLog from "@ohos.hilog";
|
||||
|
||||
export class Log {
|
||||
private static readonly DOMAIN = 0x0230;
|
||||
private static readonly TAG: string = '[PhotoApp]';
|
||||
public static readonly LEVEL_DEBUG = HiLog.LogLevel.DEBUG;
|
||||
public static readonly LEVEL_INFO = HiLog.LogLevel.INFO;
|
||||
public static readonly LEVEL_WARN = HiLog.LogLevel.WARN;
|
||||
public static readonly LEVEL_ERROR = HiLog.LogLevel.ERROR;
|
||||
public static readonly LEVEL_FATAL = HiLog.LogLevel.FATAL;
|
||||
public static LOG_LEVEL = Log.LEVEL_INFO;
|
||||
|
||||
public static debug(TAG: string, message: string): void {
|
||||
if (this.LOG_LEVEL <= this.LEVEL_DEBUG) {
|
||||
HiLog.debug(this.DOMAIN, this.TAG, "[" + TAG + "]: " + message);
|
||||
}
|
||||
}
|
||||
|
||||
public static info(TAG: string, message: string): void {
|
||||
if (this.LOG_LEVEL <= this.LEVEL_INFO) {
|
||||
HiLog.info(this.DOMAIN, this.TAG, "[" + TAG + "]: " + message);
|
||||
}
|
||||
}
|
||||
|
||||
public static warn(TAG: string, message: string): void {
|
||||
if (this.LOG_LEVEL <= this.LEVEL_WARN) {
|
||||
HiLog.warn(this.DOMAIN, this.TAG, "[" + TAG + "]: " + message);
|
||||
}
|
||||
}
|
||||
|
||||
public static error(TAG: string, message: string): void {
|
||||
if (this.LOG_LEVEL <= this.LEVEL_ERROR) {
|
||||
HiLog.error(this.DOMAIN, this.TAG, "[" + TAG + "]: " + message);
|
||||
}
|
||||
}
|
||||
|
||||
public static fatal(TAG: string, message: string): void {
|
||||
if (this.LOG_LEVEL <= this.LEVEL_FATAL) {
|
||||
HiLog.info(this.DOMAIN, this.TAG, "[" + TAG + "]: " + message);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
// @ts-nocheck
|
||||
/*
|
||||
* 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 resourceManager from '@ohos.resourceManager';
|
||||
import { Log } from '../utils/Log';
|
||||
import { GlobalContext } from '../utils/GlobalContext';
|
||||
|
||||
const TAG = "ResourceUtils"
|
||||
|
||||
export async function getResourceString(resource: Resource): Promise<string> {
|
||||
try {
|
||||
Log.debug(TAG, "getResourceString: " + JSON.stringify(resource));
|
||||
let context = GlobalContext.getContext().getObject("appContext");
|
||||
let mgr: resourceManager.ResourceManager = await resourceManager.getResourceManager(context);
|
||||
if (mgr != null || mgr != undefined) {
|
||||
return await mgr.getString(resource.id);
|
||||
} else {
|
||||
Log.warn(TAG, "getResourceManager instance is none");
|
||||
return null;
|
||||
}
|
||||
} catch (error) {
|
||||
Log.error(TAG, "getResourceString error: " + error);
|
||||
return null;
|
||||
}
|
||||
}
|
@ -1,53 +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.
|
||||
*/
|
||||
//@ts-ignore
|
||||
import fileShare from '@ohos.fileshare';
|
||||
import wantConstant from '@ohos.app.ability.wantConstant';
|
||||
import { Log } from './Log';
|
||||
|
||||
const TAG = "SelectUtil"
|
||||
export class SelectUtil {
|
||||
static readonly THIRD_URI_READ_PERMISSIONS: string = "r";
|
||||
|
||||
static getUriArray(selectedPhotos: Set<string>): string[] {
|
||||
let uriArray: string[] = [];
|
||||
if (selectedPhotos == undefined) {
|
||||
return uriArray;
|
||||
}
|
||||
selectedPhotos.forEach((uri: string): void => {
|
||||
uriArray.push(uri);
|
||||
})
|
||||
return uriArray;
|
||||
}
|
||||
|
||||
private static async grantPermissionForUri(uri: string, bundleName: string): Promise<void> {
|
||||
Log.debug(TAG, "start uri grant. bundleName: " + bundleName);
|
||||
// @ts-ignore
|
||||
await fileShare.grantUriPermission(uri, bundleName, wantConstant.Flags.FLAG_AUTH_READ_URI_PERMISSION);
|
||||
}
|
||||
|
||||
static async grantPermissionForUris(uris: string[], bundleName: string): Promise<void> {
|
||||
Log.info(TAG, "start uris grant. bundleName: " + bundleName);
|
||||
let promises: Promise<void>[] = [];
|
||||
for (let uri of uris) {
|
||||
try {
|
||||
promises.push(SelectUtil.grantPermissionForUri(uri, bundleName));
|
||||
} catch(err) {
|
||||
Log.error(TAG, "grant permission error: " + JSON.stringify(err));
|
||||
}
|
||||
}
|
||||
await Promise.all<void>(promises);
|
||||
}
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2021-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 { Log } from '../utils/Log';
|
||||
import { GlobalContext } from '../utils/GlobalContext';
|
||||
|
||||
const TAG = "SingleInstanceHelper";
|
||||
let globalThis = GlobalContext.getContext();
|
||||
|
||||
export function stashOrGetObject<T>(objectClass: object, storageKey: string): T {
|
||||
if (! new Boolean(globalThis.getObject(storageKey)).valueOf()) {
|
||||
globalThis.setObject(storageKey, objectClass);
|
||||
Log.debug(TAG, "Create key of " + storageKey);
|
||||
}
|
||||
return globalThis.getObject(storageKey) as T;
|
||||
}
|
@ -1,30 +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 prompt, { ShowToastOptions } from '@system.prompt';
|
||||
import { Log } from '../utils/Log';
|
||||
import { screenManager } from '../manager/ScreenManager';
|
||||
|
||||
const TAG = "UiUtil"
|
||||
const TOAST_DURATION = 3000;
|
||||
export function showToast(message: string): void {
|
||||
let naviBarHeight = screenManager.getNaviBarHeight()
|
||||
Log.debug(TAG, "showToast: " + message);
|
||||
let showToastOptions: ShowToastOptions = {
|
||||
message: message,
|
||||
duration: TOAST_DURATION,
|
||||
bottom: (64 + naviBarHeight) + "vp"
|
||||
};
|
||||
prompt.showToast(showToastOptions);
|
||||
}
|
@ -1,39 +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 hiSysEvent from '@ohos.hiSysEvent';
|
||||
import { Log } from './Log';
|
||||
|
||||
const TAG = "hisysEventUtil"
|
||||
|
||||
export function hiSysEventDataQueryTimedOut(interfaceName: string): number {
|
||||
let timeOutId = setTimeout((): void => {
|
||||
let params: Object = {
|
||||
FAULT_ID: "DATA_QUERY_OVERTIME",
|
||||
MSG: interfaceName + " Querying 1s data timed out."
|
||||
};
|
||||
let info: hiSysEvent.SysEventInfo = {
|
||||
domain: "PHOTOS_APP",
|
||||
name: "PHOTOS_FAULT",
|
||||
eventType: hiSysEvent.EventType.FAULT,
|
||||
params: params
|
||||
};
|
||||
hiSysEvent.write(info, (err: Error): void => {
|
||||
if(err != null) {
|
||||
Log.error(TAG, 'fail to return hiSysEvent');
|
||||
}
|
||||
});
|
||||
}, 1000);
|
||||
return timeOutId;
|
||||
}
|
@ -1,189 +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 { Log } from '../utils/Log';
|
||||
import { AlbumDataImpl } from '../model/AlbumDataImpl';
|
||||
import { LazyItem, ItemDataSource } from './ItemDataSource';
|
||||
import { AlbumDataItem } from '../data/AlbumDataItem';
|
||||
import { MediaConstants } from '../constants/MediaConstants'
|
||||
|
||||
const TAG = "AlbumsDataSource"
|
||||
|
||||
export class AlbumsDataSource extends ItemDataSource {
|
||||
private albumDataItems: AlbumDataItem[] = [];
|
||||
private albumDataImpl: AlbumDataImpl = new AlbumDataImpl();
|
||||
|
||||
setBlackList(blackList: string[]): void {
|
||||
this.albumDataImpl.setBlackList(blackList);
|
||||
}
|
||||
|
||||
setSelectType(selectType: number): void {
|
||||
this.albumDataImpl.setSelectType(selectType);
|
||||
}
|
||||
|
||||
setDeviceId(deviceId: string): void {
|
||||
this.albumDataImpl.setDeviceId(deviceId);
|
||||
}
|
||||
|
||||
totalCount(): number {
|
||||
return this.albumDataItems.length;
|
||||
}
|
||||
|
||||
getData(index: number): LazyItem<AlbumDataItem> {
|
||||
return new LazyItem<AlbumDataItem>(this.getDataByIndex(index), index, (index: number): void => this.onDataUpdateBindImpl(index))
|
||||
}
|
||||
|
||||
getDataByIndex(index: number): AlbumDataItem {
|
||||
if (index < 0 || index >= this.albumDataItems.length) {
|
||||
Log.warn(TAG, index + "/" + this.albumDataItems.length);
|
||||
return undefined;
|
||||
}
|
||||
this.albumDataItems[index].index = index;
|
||||
return this.albumDataItems[index]
|
||||
}
|
||||
|
||||
isSelect(): boolean {
|
||||
let isSelect = true;
|
||||
for (let i = 0;i < this.albumDataItems.length; i++) {
|
||||
if (!this.albumDataItems[i].isSelect) {
|
||||
isSelect = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return isSelect;
|
||||
}
|
||||
|
||||
resetLoadState(): void {
|
||||
for (let i = 0;i < this.albumDataItems.length; i++) {
|
||||
if (this.albumDataItems[i].status == MediaConstants.LOADED) {
|
||||
this.albumDataItems[i].status = MediaConstants.UNDEFINED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getAlbumDataItemById(id: string): AlbumDataItem | null {
|
||||
let albumDataItem: AlbumDataItem = null;
|
||||
for (let i = 0;i < this.albumDataItems.length; i++) {
|
||||
if (this.albumDataItems[i].id == id) {
|
||||
albumDataItem = this.albumDataItems[i];
|
||||
}
|
||||
}
|
||||
return albumDataItem;
|
||||
}
|
||||
|
||||
getSelectedUris(): string[] {
|
||||
let uris: string[] = [];
|
||||
this.albumDataItems.forEach((item: AlbumDataItem): void => {
|
||||
if (item.isSelect) {
|
||||
uris.push(item.uri);
|
||||
}
|
||||
})
|
||||
return uris;
|
||||
}
|
||||
|
||||
isDisableRename(): boolean {
|
||||
let isDisableRename = false;
|
||||
for (let i = 0;i < this.albumDataItems.length; i++) {
|
||||
if (this.albumDataItems[i].isSelect && this.albumDataItems[i].isDisableRename) {
|
||||
isDisableRename = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return isDisableRename;
|
||||
}
|
||||
|
||||
isDisableDelete(): boolean {
|
||||
let isDisableDelete = false;
|
||||
for (let i = 0;i < this.albumDataItems.length; i++) {
|
||||
if (this.albumDataItems[i].isSelect && this.albumDataItems[i].isDisableDelete) {
|
||||
isDisableDelete = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return isDisableDelete;
|
||||
}
|
||||
|
||||
setSelect(isSelect: boolean): void {
|
||||
this.albumDataItems.forEach((item: AlbumDataItem): void => {
|
||||
item.setSelect(isSelect);
|
||||
})
|
||||
}
|
||||
|
||||
getSelectedCount(): number {
|
||||
let count = 0;
|
||||
for (let i = 0;i < this.albumDataItems.length; i++) {
|
||||
if (this.albumDataItems[i].isSelect) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
getSelectedItems(): Object[] {
|
||||
let items: AlbumDataItem[] = [];
|
||||
this.albumDataItems.forEach((item: AlbumDataItem): void => {
|
||||
if (item.isSelect) {
|
||||
items.push(item);
|
||||
}
|
||||
})
|
||||
return items;
|
||||
}
|
||||
|
||||
onDataUpdate(index: number): void {
|
||||
this.onDataUpdateBindImpl(index)
|
||||
}
|
||||
|
||||
private onDataUpdateBindImpl(index: number): void {
|
||||
Log.info(TAG, "onDataUpdate " + index);
|
||||
this.notifyDataChange(index);
|
||||
}
|
||||
|
||||
dataReload(): void {
|
||||
this.reloadAlbumItemData().then<void, void>((isEmpty: boolean): void => {
|
||||
this.notifyDataReload();
|
||||
})
|
||||
}
|
||||
|
||||
dataRemove(): void {
|
||||
for (let i = this.albumDataItems.length - 1;i >= 0; i--) {
|
||||
if (this.albumDataItems[i].isDeleted()) {
|
||||
this.albumDataItems.splice(i, 1);
|
||||
super.notifyDataDelete(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async reloadAlbumItemData(): Promise<boolean> {
|
||||
this.albumDataItems = await this.albumDataImpl.reloadAlbumItemData();
|
||||
return this.albumDataItems.length == 0;
|
||||
}
|
||||
|
||||
async reloadAlbumListItemData(): Promise<boolean> {
|
||||
Log.info(TAG, "reloadAlbumListItemData");
|
||||
this.albumDataItems = await this.albumDataImpl.reloadAlbumListItemData();
|
||||
this.reloadResetAlbumItemData().then<void, void>((count: number): void => {
|
||||
Log.info(TAG, "reloadResetAlbumItemData reset: " + count);
|
||||
})
|
||||
return this.albumDataItems.length == 0;
|
||||
}
|
||||
|
||||
async reloadResetAlbumItemData(): Promise<number> {
|
||||
let albumResetDataItems = await this.albumDataImpl.reloadResetAlbumItemData();
|
||||
albumResetDataItems.forEach((item: AlbumDataItem): void => {
|
||||
this.albumDataItems.push(item);
|
||||
});
|
||||
this.notifyDataReload();
|
||||
return albumResetDataItems.length;
|
||||
}
|
||||
}
|
@ -1,95 +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 { DistributedDataImpl } from '../model/DistributedDataImpl'
|
||||
import { ItemDataSource } from './ItemDataSource'
|
||||
import { PeerDataItem } from '../data/PeerDataItem'
|
||||
import { Log } from '../utils/Log';
|
||||
|
||||
const TAG = "DistributedDataSource"
|
||||
|
||||
export class DistributedDataSource extends ItemDataSource {
|
||||
private peerDataItems: PeerDataItem[] = [];
|
||||
private distributedDataImpl: DistributedDataImpl = new DistributedDataImpl();
|
||||
|
||||
totalCount(): number {
|
||||
return this.peerDataItems.length;
|
||||
}
|
||||
|
||||
getData(index: number): PeerDataItem {
|
||||
this.peerDataItems[index].index = index;
|
||||
return this.peerDataItems[index];
|
||||
}
|
||||
|
||||
isSelect(): boolean {
|
||||
let isSelect = true;
|
||||
for (let i = 0;i < this.peerDataItems.length; i++) {
|
||||
if (!this.peerDataItems[i].isSelect) {
|
||||
isSelect = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return isSelect;
|
||||
}
|
||||
|
||||
setSelect(isSelect: boolean): void {
|
||||
this.peerDataItems.forEach((item: PeerDataItem): void => {
|
||||
item.setSelect(isSelect);
|
||||
})
|
||||
}
|
||||
|
||||
getSelectedUris(): string[]{
|
||||
let uris: string[] = [];
|
||||
this.peerDataItems.forEach((item: PeerDataItem): void => {
|
||||
if (item.isSelect) {
|
||||
uris.push(item.uri);
|
||||
}
|
||||
})
|
||||
return uris;
|
||||
}
|
||||
|
||||
getSelectedCount(): number {
|
||||
let count = 0;
|
||||
for (let i = 0;i < this.peerDataItems.length; i++) {
|
||||
if (this.peerDataItems[i].isSelect) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
getSelectedItems(): Object[]{
|
||||
return [];
|
||||
}
|
||||
|
||||
onDataUpdate(index: number): void {
|
||||
Log.info(TAG, "onDataUpdate " + index);
|
||||
this.notifyDataChange(index);
|
||||
}
|
||||
|
||||
dataReload(): void {
|
||||
this.reloadAlbumItemData().then<void, void>((isEmpty: number): void => {
|
||||
this.notifyDataReload();
|
||||
})
|
||||
}
|
||||
|
||||
dataRemove(): void {
|
||||
}
|
||||
|
||||
async reloadAlbumItemData(): Promise<number> {
|
||||
let before = this.peerDataItems.length;
|
||||
this.peerDataItems = await this.distributedDataImpl.reloadAlbumItemData();
|
||||
return this.peerDataItems.length - before;
|
||||
}
|
||||
}
|
@ -1,178 +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 { Log } from '../utils/Log';
|
||||
import { GroupDataImpl } from '../model/GroupDataImpl';
|
||||
import { LazyItem, ItemDataSource } from '../vm/ItemDataSource';
|
||||
import { MediaDataItem } from '../data/MediaDataItem';
|
||||
|
||||
const TAG = "GroupItemDataSource"
|
||||
|
||||
export class GroupItemDataSource extends ItemDataSource {
|
||||
groupDataItem: MediaDataItem[] = [];
|
||||
private groupDataImpl: GroupDataImpl = new GroupDataImpl();
|
||||
|
||||
constructor() {
|
||||
super()
|
||||
}
|
||||
|
||||
setSelectType(selectType: number): void {
|
||||
this.groupDataImpl.setSelectType(selectType);
|
||||
}
|
||||
|
||||
setAlbumId(id: string): void {
|
||||
Log.info(TAG, "setAlbumId: " + id);
|
||||
this.groupDataImpl.setAlbumId(id);
|
||||
}
|
||||
|
||||
setDeviceId(id: string): void {
|
||||
Log.info(TAG, "setDeviceId: " + id);
|
||||
this.groupDataImpl.setDeviceId(id);
|
||||
}
|
||||
|
||||
totalCount(): number {
|
||||
return this.groupDataItem.length;
|
||||
}
|
||||
|
||||
getIndexByItem(item: MediaDataItem): number {
|
||||
let index = -1;
|
||||
let length = this.groupDataItem.length;
|
||||
for (let i = 0;i < length; i++) {
|
||||
if (this.groupDataItem[i].uri == item.uri) {
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
getData(index: number): LazyItem<MediaDataItem> {
|
||||
if (index < 0 || index >= this.groupDataItem.length) {
|
||||
Log.warn(TAG, index + "/" + this.groupDataItem.length);
|
||||
return undefined;
|
||||
}
|
||||
if (this.groupDataItem[index] != null && this.groupDataItem[index] != undefined) {
|
||||
this.groupDataItem[index].index = index;
|
||||
}
|
||||
return new LazyItem<MediaDataItem>(this.groupDataItem[index], index, (index: number): void => this.onDataUpdateBindImpl(index));
|
||||
}
|
||||
|
||||
getDataByIndex(index: number): MediaDataItem {
|
||||
if (index < 0 || index >= this.groupDataItem.length) {
|
||||
Log.warn(TAG, index + "/" + this.groupDataItem.length);
|
||||
return undefined;
|
||||
}
|
||||
if (this.groupDataItem[index] != null && this.groupDataItem[index] != undefined) {
|
||||
this.groupDataItem[index].index = index;
|
||||
}
|
||||
return this.groupDataItem[index];
|
||||
}
|
||||
|
||||
isSelect(): boolean {
|
||||
let isSelect = true;
|
||||
for (let i = 0;i < this.groupDataItem.length; i++) {
|
||||
if (!this.groupDataItem[i].isSelect) {
|
||||
isSelect = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return isSelect;
|
||||
}
|
||||
|
||||
getSelectedCount(): number {
|
||||
let count = 0;
|
||||
this.groupDataItem.forEach((item: MediaDataItem): void => {
|
||||
if (item.isSelect) {
|
||||
count++;
|
||||
}
|
||||
})
|
||||
return count;
|
||||
}
|
||||
|
||||
getItems(): MediaDataItem[] {
|
||||
let items: MediaDataItem[] = [];
|
||||
this.groupDataItem.forEach((item: MediaDataItem): void => {
|
||||
items.push(item);
|
||||
})
|
||||
return items;
|
||||
}
|
||||
|
||||
getSelectedItems(): Object[] {
|
||||
let items: MediaDataItem[] = [];
|
||||
this.groupDataItem.forEach((item: MediaDataItem): void => {
|
||||
if (item.isSelect) {
|
||||
items.push(item);
|
||||
}
|
||||
})
|
||||
return items;
|
||||
}
|
||||
|
||||
getSelectedUris(): string[] {
|
||||
let uris: string[] = [];
|
||||
this.groupDataItem.forEach((item: MediaDataItem): void => {
|
||||
if (item.isSelect) {
|
||||
uris.push(item.uri);
|
||||
}
|
||||
})
|
||||
return uris;
|
||||
}
|
||||
|
||||
setSelect(isSelect: boolean): void {
|
||||
this.groupDataItem.forEach((item: MediaDataItem): void => {
|
||||
item.setSelect(isSelect);
|
||||
})
|
||||
this.notifyDataReload();
|
||||
}
|
||||
|
||||
async reloadGroupItemData(isGrid: boolean): Promise<boolean> {
|
||||
this.groupDataItem = await this.groupDataImpl.reloadGroupItemData(isGrid);
|
||||
return this.groupDataItem.length == 0;
|
||||
}
|
||||
|
||||
onDataUpdate(index: number): void {
|
||||
this.onDataUpdateBindImpl(index)
|
||||
}
|
||||
|
||||
private onDataUpdateBindImpl(index: number): void {
|
||||
Log.debug(TAG, "onDataUpdate " + index);
|
||||
if (index != -1) {
|
||||
this.notifyDataChange(index);
|
||||
}
|
||||
}
|
||||
|
||||
dataReload(isGrid: boolean): void {
|
||||
this.reloadGroupItemData(isGrid).then<void, void>((isEmpty: boolean): void => {
|
||||
this.notifyDataReload();
|
||||
})
|
||||
}
|
||||
|
||||
dataRemove(): void {
|
||||
for (let i = this.groupDataItem.length - 1;i >= 0; i--) {
|
||||
if (this.groupDataItem[i] != undefined && this.groupDataItem[i].isDeleted()) {
|
||||
this.groupDataItem.splice(i, 1);
|
||||
super.notifyDataDelete(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dataDelete(uri: string): void {
|
||||
const mediaDataItemIndex = this.groupDataItem.findIndex((item: MediaDataItem): boolean => {
|
||||
return item.uri === uri;
|
||||
})
|
||||
if (mediaDataItemIndex != -1 && this.groupDataItem[mediaDataItemIndex].isDeleted()) {
|
||||
this.groupDataItem.splice(mediaDataItemIndex, 1);
|
||||
super.notifyDataDelete(mediaDataItemIndex);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,102 +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 { Log } from '../utils/Log';
|
||||
|
||||
const TAG = "ItemDataSource"
|
||||
|
||||
export class LazyItem<T> {
|
||||
item: T
|
||||
onItemUpdate: Function
|
||||
index: number = -1
|
||||
|
||||
constructor(item:T, index: number, onItemUpdate?: Function) {
|
||||
this.item = item
|
||||
this.onItemUpdate = onItemUpdate
|
||||
this.index = index
|
||||
}
|
||||
|
||||
update(item: T): void {
|
||||
if (this.onItemUpdate != null && this.index != -1) {
|
||||
this.onItemUpdate(this.index, item)
|
||||
}
|
||||
}
|
||||
|
||||
getHashCode(): string {
|
||||
// @ts-ignore
|
||||
return this.index + "" + this.item.getHashCode()
|
||||
}
|
||||
|
||||
get(): T {
|
||||
return this.item
|
||||
}
|
||||
|
||||
set(item:T): void {
|
||||
this.item = item
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export abstract class ItemDataSource implements IDataSource {
|
||||
private listeners: DataChangeListener[] = [];
|
||||
|
||||
abstract totalCount(): number;
|
||||
|
||||
abstract getData(index: number): Object;
|
||||
|
||||
abstract isSelect(): boolean;
|
||||
|
||||
abstract getSelectedCount(): number;
|
||||
|
||||
abstract getSelectedItems(): Object[];
|
||||
|
||||
abstract getSelectedUris(): string[];
|
||||
|
||||
abstract dataRemove(): void;
|
||||
|
||||
registerDataChangeListener(listener: DataChangeListener): void {
|
||||
Log.info(TAG, 'registerDataChangeListener');
|
||||
if (this.listeners.indexOf(listener) < 0) {
|
||||
this.listeners.push(listener);
|
||||
Log.info(TAG, "registerDataChangeListener, add listener, length: " + this.listeners.length);
|
||||
}
|
||||
}
|
||||
|
||||
unregisterDataChangeListener(listener: DataChangeListener): void {
|
||||
Log.info(TAG, 'unregisterDataChangeListener');
|
||||
const pos = this.listeners.indexOf(listener);
|
||||
if (pos >= 0) {
|
||||
this.listeners.splice(pos, 1);
|
||||
Log.info(TAG, "registerDataChangeListener, remove listener, length: " + this.listeners.length);
|
||||
}
|
||||
}
|
||||
|
||||
notifyDataChange(index: number): void {
|
||||
this.listeners.forEach((listener: DataChangeListener): void => {
|
||||
listener.onDataChange(index);
|
||||
})
|
||||
}
|
||||
|
||||
notifyDataReload(): void {
|
||||
this.listeners.forEach((listener: DataChangeListener): void => {
|
||||
listener.onDataReloaded();
|
||||
})
|
||||
}
|
||||
|
||||
notifyDataDelete(index: number): void {
|
||||
this.listeners.forEach((listener: DataChangeListener): void => {
|
||||
listener.onDataDelete(index);
|
||||
})
|
||||
}
|
||||
}
|
@ -1,56 +0,0 @@
|
||||
{
|
||||
"color": [
|
||||
{
|
||||
"name": "white",
|
||||
"value": "#FFFFFF"
|
||||
},
|
||||
{
|
||||
"name": "black",
|
||||
"value": "#000000"
|
||||
},
|
||||
{
|
||||
"name": "album_cover_stroke_color",
|
||||
"value": "#14000000"
|
||||
},
|
||||
{
|
||||
"name": "album_cover_gradient_start_color",
|
||||
"value": "#33000000"
|
||||
},
|
||||
{
|
||||
"name": "album_scrollbar_color",
|
||||
"value": "#ffb3b3b3"
|
||||
},
|
||||
{
|
||||
"name": "transparent",
|
||||
"value": "#00000000"
|
||||
},
|
||||
{
|
||||
"name": "text_color_above_picture",
|
||||
"value": "#FFFFFF"
|
||||
},
|
||||
{
|
||||
"name": "item_selection_bg_color",
|
||||
"value": "#80FFFFFF"
|
||||
},
|
||||
{
|
||||
"name": "default_background_color",
|
||||
"value": "#FFF1F3F5"
|
||||
},
|
||||
{
|
||||
"name": "empty_or_recycle_album_icon",
|
||||
"value": "#99FFFFFF"
|
||||
},
|
||||
{
|
||||
"name": "empty_or_recycle_album_back",
|
||||
"value": "#9E9E9E"
|
||||
},
|
||||
{
|
||||
"name": "color_control_highlight",
|
||||
"value": "#007DFF"
|
||||
},
|
||||
{
|
||||
"name": "dialog_default_shadow_m_color",
|
||||
"value": "#2600001E"
|
||||
}
|
||||
]
|
||||
}
|
@ -1,228 +0,0 @@
|
||||
{
|
||||
"float": [
|
||||
{
|
||||
"name": "icon_size",
|
||||
"value": "24vp"
|
||||
},
|
||||
{
|
||||
"name": "icon_size_hot",
|
||||
"value": "32vp"
|
||||
},
|
||||
{
|
||||
"name": "max_padding_start",
|
||||
"value": "24vp"
|
||||
},
|
||||
{
|
||||
"name": "max_padding_end",
|
||||
"value": "24vp"
|
||||
},
|
||||
{
|
||||
"name": "grid_item_text_line_height",
|
||||
"value": "12vp"
|
||||
},
|
||||
{
|
||||
"name": "grid_item_duration_markAnchor_x",
|
||||
"value": "-4vp"
|
||||
},
|
||||
{
|
||||
"name": "grid_item_duration_markAnchor_y",
|
||||
"value": "16vp"
|
||||
},
|
||||
{
|
||||
"name": "grid_item_duration_margin_right",
|
||||
"value": "32vp"
|
||||
},
|
||||
{
|
||||
"name": "grid_item_favor_markAnchor_x",
|
||||
"value": "28vp"
|
||||
},
|
||||
{
|
||||
"name": "grid_item_favor_markAnchor_y",
|
||||
"value": "-4vp"
|
||||
},
|
||||
{
|
||||
"name": "grid_item_preview_padding",
|
||||
"value": "4vp"
|
||||
},
|
||||
{
|
||||
"name": "grid_item_checkbox_markAnchor",
|
||||
"value": "28vp"
|
||||
},
|
||||
{
|
||||
"name": "scroll_bar_margin_small",
|
||||
"value": "48vp"
|
||||
},
|
||||
{
|
||||
"name": "scroll_bar_small_width",
|
||||
"value": "32vp"
|
||||
},
|
||||
{
|
||||
"name": "scroll_bar_small_height",
|
||||
"value": "56vp"
|
||||
},
|
||||
{
|
||||
"name": "scroll_bar_big_width",
|
||||
"value": "40vp"
|
||||
},
|
||||
{
|
||||
"name": "scroll_bar_big_height",
|
||||
"value": "69vp"
|
||||
},
|
||||
{
|
||||
"name": "album_scrollbar_normal_size",
|
||||
"value": "6vp"
|
||||
},
|
||||
{
|
||||
"name": "album_scrollbar_select_size",
|
||||
"value": "12vp"
|
||||
},
|
||||
{
|
||||
"name": "album_scrollbar_height_size",
|
||||
"value": "80vp"
|
||||
},
|
||||
{
|
||||
"name": "album_scrollbar_radius",
|
||||
"value": "50vp"
|
||||
},
|
||||
{
|
||||
"name": "recycle_album_cover_icon_size",
|
||||
"value": "48vp"
|
||||
},
|
||||
{
|
||||
"name": "album_set_name_margin_right",
|
||||
"value": "16vp"
|
||||
},
|
||||
{
|
||||
"name": "album_set_count_margin_left",
|
||||
"value": "8vp"
|
||||
},
|
||||
{
|
||||
"name": "album_set_count_margin_bottom",
|
||||
"value": "8vp"
|
||||
},
|
||||
{
|
||||
"name": "album_set_new_style_icon",
|
||||
"value": "22vp"
|
||||
},
|
||||
{
|
||||
"name": "album_set_tab_bar_height",
|
||||
"value": "56vp"
|
||||
},
|
||||
{
|
||||
"name": "album_set_page_padding_end",
|
||||
"value": "56vp"
|
||||
},
|
||||
{
|
||||
"name": "album_set_page_padding_end_112",
|
||||
"value": "112vp"
|
||||
},
|
||||
{
|
||||
"name": "album_set_page_padding_end_168",
|
||||
"value": "168vp"
|
||||
},
|
||||
{
|
||||
"name": "album_cover_stroke_width",
|
||||
"value": "0.5vp"
|
||||
},
|
||||
{
|
||||
"name": "crop_vertical_padding",
|
||||
"value": "16vp"
|
||||
},
|
||||
{
|
||||
"name": "dialog_border_radius",
|
||||
"value": "36vp"
|
||||
},
|
||||
{
|
||||
"name": "dialog_title_height",
|
||||
"value": "56vp"
|
||||
},
|
||||
{
|
||||
"name": "dialog_content_margin",
|
||||
"value": "24vp"
|
||||
},
|
||||
{
|
||||
"name": "details_dialog_button_height",
|
||||
"value": "40vp"
|
||||
},
|
||||
{
|
||||
"name": "camera_icon_side",
|
||||
"value": "24vp"
|
||||
},
|
||||
{
|
||||
"name": "third_selected_panel_height",
|
||||
"value": "152vp"
|
||||
},
|
||||
{
|
||||
"name": "third_selected_panel_original_markAnchor",
|
||||
"value": "-11vp"
|
||||
},
|
||||
{
|
||||
"name": "third_selected_toggle_icon_margin_right",
|
||||
"value": "4vp"
|
||||
},
|
||||
{
|
||||
"name": "third_selected_panel_title_height",
|
||||
"value": "48vp"
|
||||
},
|
||||
{
|
||||
"name": "third_selected_panel_image_height",
|
||||
"value": "104vp"
|
||||
},
|
||||
{
|
||||
"name": "third_selected_panel_image_padding_top",
|
||||
"value": "8vp"
|
||||
},
|
||||
{
|
||||
"name": "edit_reset_margin_bottom",
|
||||
"value": "6vp"
|
||||
},
|
||||
{
|
||||
"name": "third_delete_dialog_ico_height",
|
||||
"value": "180vp"
|
||||
},
|
||||
{
|
||||
"name": "third_delete_dialog_ico_height_multi",
|
||||
"value": "172vp"
|
||||
},
|
||||
{
|
||||
"name": "third_delete_dialog_second_ico_margin",
|
||||
"value": "16vp"
|
||||
},
|
||||
{
|
||||
"name": "third_delete_dialog_button_area_height",
|
||||
"value": "56vp"
|
||||
},
|
||||
{
|
||||
"name": "third_delete_dialog_ico_margin_bottom_single",
|
||||
"value": "0vp"
|
||||
},
|
||||
{
|
||||
"name": "third_delete_dialog_ico_margin_bottom_multi",
|
||||
"value": "8vp"
|
||||
},
|
||||
{
|
||||
"name": "dialog_button_and_text_margin",
|
||||
"value": "8vp"
|
||||
},
|
||||
{
|
||||
"name": "dialog_double_buttons_margin",
|
||||
"value": "8vp"
|
||||
},
|
||||
{
|
||||
"name": "dialog_default_shadow_m_radius",
|
||||
"value": "50"
|
||||
},
|
||||
{
|
||||
"name": "dialog_default_shadow_m_offsetX",
|
||||
"value": "0"
|
||||
},
|
||||
{
|
||||
"name": "dialog_default_shadow_m_offsetY",
|
||||
"value": "10"
|
||||
},
|
||||
{
|
||||
"name": "first_delete_dialog_ico_margin_bottom",
|
||||
"value": "16vp"
|
||||
}
|
||||
]
|
||||
}
|
@ -1,64 +0,0 @@
|
||||
{
|
||||
"string": [
|
||||
{
|
||||
"name": "page_show",
|
||||
"value": "page from npm package"
|
||||
},
|
||||
{
|
||||
"name": "id_text_font_family_medium",
|
||||
"value": "HwChinese-medium"
|
||||
},
|
||||
{
|
||||
"name": "id_text_font_family_regular",
|
||||
"value": "sans-serif"
|
||||
},
|
||||
{
|
||||
"name": "album_all",
|
||||
"value": "All photos"
|
||||
},
|
||||
{
|
||||
"name": "album_camera",
|
||||
"value": "Camera"
|
||||
},
|
||||
{
|
||||
"name": "album_video",
|
||||
"value": "Videos"
|
||||
},
|
||||
{
|
||||
"name": "album_favor",
|
||||
"value": "My favorites"
|
||||
},
|
||||
{
|
||||
"name": "album_remote_device",
|
||||
"value": "From other devices"
|
||||
},
|
||||
{
|
||||
"name": "album_screen_shot",
|
||||
"value": "Screenshots"
|
||||
},
|
||||
{
|
||||
"name": "album_recycle",
|
||||
"value": "Recently deleted"
|
||||
},
|
||||
{
|
||||
"name": "yes",
|
||||
"value": "OK"
|
||||
},
|
||||
{
|
||||
"name": "no",
|
||||
"value": "CANCEL"
|
||||
},
|
||||
{
|
||||
"name": "camera_btn_text_photo",
|
||||
"value": "Photo"
|
||||
},
|
||||
{
|
||||
"name": "selected_photos_count",
|
||||
"value": "%1$d/%2$d"
|
||||
},
|
||||
{
|
||||
"name": "third_delete_dialog_message",
|
||||
"value": "Whether allow %s to delete %d files?"
|
||||
}
|
||||
]
|
||||
}
|
@ -1,60 +0,0 @@
|
||||
{
|
||||
"string": [
|
||||
{
|
||||
"name": "id_text_font_family_medium",
|
||||
"value": "中粗"
|
||||
},
|
||||
{
|
||||
"name": "id_text_font_family_regular",
|
||||
"value": "标准"
|
||||
},
|
||||
{
|
||||
"name": "album_all",
|
||||
"value": "所有照片"
|
||||
},
|
||||
{
|
||||
"name": "album_camera",
|
||||
"value": "相机"
|
||||
},
|
||||
{
|
||||
"name": "album_video",
|
||||
"value": "视频"
|
||||
},
|
||||
{
|
||||
"name": "album_favor",
|
||||
"value": "我的收藏"
|
||||
},
|
||||
{
|
||||
"name": "album_screen_shot",
|
||||
"value": "截屏录屏"
|
||||
},
|
||||
{
|
||||
"name": "album_remote_device",
|
||||
"value": "其他设备保存"
|
||||
},
|
||||
{
|
||||
"name": "album_recycle",
|
||||
"value": "最近删除"
|
||||
},
|
||||
{
|
||||
"name": "yes",
|
||||
"value": "确定"
|
||||
},
|
||||
{
|
||||
"name": "no",
|
||||
"value": "取消"
|
||||
},
|
||||
{
|
||||
"name": "camera_btn_text_photo",
|
||||
"value": "拍照"
|
||||
},
|
||||
{
|
||||
"name": "selected_photos_count",
|
||||
"value": "%1$d/%2$d"
|
||||
},
|
||||
{
|
||||
"name": "third_delete_dialog_message",
|
||||
"value": "是否允许 %s 删除 %d 个文件?"
|
||||
}
|
||||
]
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
{
|
||||
"string": [
|
||||
{
|
||||
"name": "yes",
|
||||
"value": "[CJ_874431]_OK"
|
||||
},
|
||||
{
|
||||
"name": "no",
|
||||
"value": "[CJ_874432]_Cancel"
|
||||
}
|
||||
]
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2022 Huawei Device Co., Ltd.
|
||||
* Copyright (c) 2022-2023 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
|
||||
@ -12,5 +12,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import { MainPage } from './src/main/ets/components/MainPage/MainPage'
|
||||
import { ThirdDeleteOperation } from './src/main/ets/operation/ThirdDeleteOperation'
|
||||
|
||||
// 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').harTasks
|
||||
|
275
common/index.ts
Normal file
275
common/index.ts
Normal file
@ -0,0 +1,275 @@
|
||||
/**
|
||||
* Copyright (c) 2022-2023 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 perPhotoSwipermissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
export { UserFileManagerAccess } from './src/main/ets/default/access/UserFileManagerAccess';
|
||||
|
||||
export type { FileAsset } from './src/main/ets/default/access/UserFileManagerAccess';
|
||||
|
||||
export { BrowserDataFactory } from './src/main/ets/default/interface/BrowserDataFactory';
|
||||
|
||||
export type { BrowserDataInterface } from './src/main/ets/default/interface/BrowserDataInterface';
|
||||
|
||||
export { BrowserOperationFactory } from './src/main/ets/default/interface/BrowserOperationFactory';
|
||||
|
||||
export type { BrowserOperationInterface } from './src/main/ets/default/interface/BrowserOperationInterface';
|
||||
|
||||
export { MenuOperationFactory } from './src/main/ets/default/interface/MenuOperationFactory';
|
||||
|
||||
export { AbsDataSource } from './src/main/ets/default/model/browser/AbsDataSource';
|
||||
|
||||
export type { AlbumSimpleInfo } from './src/main/ets/default/model/browser/album/AlbumDataImpl';
|
||||
|
||||
export { AlbumDataImpl } from './src/main/ets/default/model/browser/album/AlbumDataImpl';
|
||||
|
||||
export { AlbumInfo } from './src/main/ets/default/model/browser/album/AlbumInfo';
|
||||
|
||||
export { AlbumOperationImpl } from './src/main/ets/default/model/browser/album/AlbumOperationImpl';
|
||||
|
||||
export { AlbumSetDataSource } from './src/main/ets/default/model/browser/album/AlbumSetDataSource';
|
||||
|
||||
export { AlbumDefine } from './src/main/ets/default/model/browser/AlbumDefine';
|
||||
|
||||
export { CommonObserverCallback } from './src/main/ets/default/model/browser/CommonObserverCallback';
|
||||
|
||||
export { MediaObserver } from './src/main/ets/default/model/browser/dataObserver/MediaObserver';
|
||||
|
||||
export type { LoadingListener } from './src/main/ets/default/model/browser/LoadingListener';
|
||||
|
||||
export { Constants as BrowserConstants } from './src/main/ets/default/model/browser/photo/Constants';
|
||||
|
||||
export { EventPipeline } from './src/main/ets/default/model/browser/photo/EventPipeline';
|
||||
|
||||
export { FifoCache } from './src/main/ets/default/model/browser/photo/FifoCache';
|
||||
|
||||
export { GetItemsCallback } from './src/main/ets/default/model/browser/photo/GetItemsCallback';
|
||||
|
||||
export { GetMediaCountCallback } from './src/main/ets/default/model/browser/photo/GetMediaCountCallback';
|
||||
|
||||
export { ImageGridItem } from './src/main/ets/default/model/browser/photo/ImageGridItem';
|
||||
|
||||
export { JumpSourceToMain } from './src/main/ets/default/model/browser/photo/JumpSourceToMain';
|
||||
|
||||
export { MediaDataSource } from './src/main/ets/default/model/browser/photo/MediaDataSource';
|
||||
|
||||
export { MediaItem } from './src/main/ets/default/model/browser/photo/MediaItem';
|
||||
|
||||
export { OperationImpl } from './src/main/ets/default/model/browser/photo/OperationImpl';
|
||||
|
||||
export type { PendingCondition } from './src/main/ets/default/model/browser/photo/PendingCondition';
|
||||
|
||||
export { PendingTask } from './src/main/ets/default/model/browser/photo/PendingTask';
|
||||
|
||||
export { PhotoDataImpl } from './src/main/ets/default/model/browser/photo/PhotoDataImpl';
|
||||
|
||||
export { PhotoDataSource } from './src/main/ets/default/model/browser/photo/PhotoDataSource';
|
||||
|
||||
export { SelectUtil } from './src/main/ets/default/model/browser/photo/SelectUtil';
|
||||
|
||||
export { Thumbnail } from './src/main/ets/default/model/browser/photo/Thumbnail';
|
||||
|
||||
export { TimelineData } from './src/main/ets/default/model/browser/photo/TimelineData';
|
||||
|
||||
export { TimelineDataImpl } from './src/main/ets/default/model/browser/photo/TimelineDataImpl';
|
||||
|
||||
export { UriDataSource } from './src/main/ets/default/model/browser/photo/UriDataSource';
|
||||
|
||||
export { ViewData } from './src/main/ets/default/model/browser/photo/ViewData';
|
||||
|
||||
export { ViewType } from './src/main/ets/default/model/browser/photo/ViewType';
|
||||
|
||||
export { SelectionState } from './src/main/ets/default/model/browser/SelectionState';
|
||||
|
||||
export {
|
||||
SelectManager,
|
||||
AlbumSetSelectManager,
|
||||
TimelineSelectManager,
|
||||
ThirdSelectManager,
|
||||
ItemCoordinate,
|
||||
BucketSelectionEntry
|
||||
} from './src/main/ets/default/model/browser/SelectManager';
|
||||
|
||||
export { AlbumSetDataInfo } from './src/main/ets/default/model/common/AlbumSetDataInfo';
|
||||
|
||||
export type { AsyncCallback } from './src/main/ets/default/model/common/AsyncCallback';
|
||||
|
||||
export { BroadCastConstants } from './src/main/ets/default/model/common/BroadCastConstants';
|
||||
|
||||
export { BroadCastManager } from './src/main/ets/default/model/common/BroadCastManager';
|
||||
|
||||
export { Constants } from './src/main/ets/default/model/common/Constants';
|
||||
|
||||
export type { Size } from './src/main/ets/default/model/common/DataTypes';
|
||||
|
||||
export type { DialogCallback } from './src/main/ets/default/model/common/DialogUtil';
|
||||
|
||||
export { MediaOperationType } from './src/main/ets/default/model/common/MediaOperationType';
|
||||
|
||||
export {
|
||||
MultimodalInputManager,
|
||||
mMultimodalInputManager
|
||||
} from './src/main/ets/default/model/common/MultimodalInputManager';
|
||||
|
||||
export type { Releasable } from './src/main/ets/default/model/common/Releasable';
|
||||
|
||||
export { ScreenManager, ColumnSize } from './src/main/ets/default/model/common/ScreenManager';
|
||||
|
||||
export { StatusBarColorController } from './src/main/ets/default/model/common/StatusBarColorController';
|
||||
|
||||
export { TabItem, TabItemWithText } from './src/main/ets/default/model/common/TabItem';
|
||||
|
||||
export { BroadCast } from './src/main/ets/default/utils/BroadCast';
|
||||
|
||||
export { DataStoreUtil } from './src/main/ets/default/utils/DataStoreUtil';
|
||||
|
||||
export { DateUtil } from './src/main/ets/default/utils/DateUtil';
|
||||
|
||||
export { ImageUtil } from './src/main/ets/default/utils/ImageUtil';
|
||||
|
||||
export { WindowUtil } from './src/main/ets/default/utils/WindowUtil';
|
||||
|
||||
export { Log } from './src/main/ets/default/utils/Log';
|
||||
|
||||
export { MathUtil } from './src/main/ets/default/utils/MathUtil';
|
||||
|
||||
export { ReportToBigDataUtil, BigDataConstants } from './src/main/ets/default/utils/ReportToBigDataUtil';
|
||||
|
||||
export { StringUtil } from './src/main/ets/default/utils/StringUtil';
|
||||
|
||||
export { SystemUtil } from './src/main/ets/default/utils/SystemUtil';
|
||||
|
||||
export { TraceControllerUtils } from './src/main/ets/default/utils/TraceControllerUtils';
|
||||
|
||||
export { UiUtil } from './src/main/ets/default/utils/UiUtil';
|
||||
|
||||
export { ActionBar } from './src/main/ets/default/view/actionbar/ActionBar';
|
||||
|
||||
export { ActionBarButton } from './src/main/ets/default/view/actionbar/ActionBarButton';
|
||||
|
||||
export { DetailMenuPanel } from './src/main/ets/default/view/actionbar/DetailMenuPanel';
|
||||
|
||||
export { DetailTitle } from './src/main/ets/default/view/actionbar/DetailTitle';
|
||||
|
||||
export { MenuPanel } from './src/main/ets/default/view/actionbar/MenuPanel';
|
||||
|
||||
export { SelectionActionBarBg } from './src/main/ets/default/view/actionbar/SelectionActionBarBg';
|
||||
|
||||
export { SelectionTitle } from './src/main/ets/default/view/actionbar/SelectionTitle';
|
||||
|
||||
export { SingleTitle } from './src/main/ets/default/view/actionbar/SingleTitle';
|
||||
|
||||
export { ToolBar } from './src/main/ets/default/view/actionbar/ToolBar';
|
||||
|
||||
export { ToolBarButton } from './src/main/ets/default/view/actionbar/ToolBarButton';
|
||||
|
||||
export { Action } from './src/main/ets/default/view/browserOperation/Action';
|
||||
|
||||
export {
|
||||
ActionBarMode,
|
||||
ActionBarSelectionMode,
|
||||
ActionBarColorMode
|
||||
} from './src/main/ets/default/view/browserOperation/ActionBarMode';
|
||||
|
||||
export { ActionBarProp } from './src/main/ets/default/view/browserOperation/ActionBarProp';
|
||||
|
||||
export { AlbumListCard } from './src/main/ets/default/view/browserOperation/AlbumListCard';
|
||||
|
||||
export { AlbumSetNewMenuOperation } from './src/main/ets/default/view/browserOperation/AlbumSetNewMenuOperation';
|
||||
|
||||
export { BatchDeleteMenuOperation } from './src/main/ets/default/view/browserOperation/BatchDeleteMenuOperation';
|
||||
|
||||
export { DeleteMenuOperation } from './src/main/ets/default/view/browserOperation/DeleteMenuOperation';
|
||||
|
||||
export { AddMenuOperation } from './src/main/ets/default/view/browserOperation/AddMenuOperation';
|
||||
|
||||
export { RemoveMenuOperation } from './src/main/ets/default/view/browserOperation/RemoveMenuOperation';
|
||||
|
||||
export { BatchRemoveMenuOperation } from './src/main/ets/default/view/browserOperation/BatchRemoveMenuOperation';
|
||||
|
||||
export { MoveOrCopyBroadCastProp } from './src/main/ets/default/view/browserOperation/MoveOrCopyBroadCastProp';
|
||||
|
||||
export { MediaOperationActionBar } from './src/main/ets/default/view/browserOperation/MediaOperationActionBar';
|
||||
|
||||
export { MenuContext } from './src/main/ets/default/view/browserOperation/MenuContext';
|
||||
|
||||
export type { MenuOperation } from './src/main/ets/default/view/browserOperation/MenuOperation';
|
||||
|
||||
export type { MenuOperationCallback } from './src/main/ets/default/view/browserOperation/MenuOperationCallback';
|
||||
|
||||
export { MoveMenuOperation } from './src/main/ets/default/view/browserOperation/MoveMenuOperation';
|
||||
|
||||
export { ProcessMenuOperation } from './src/main/ets/default/view/browserOperation/ProcessMenuOperation';
|
||||
|
||||
export { ShareMenuOperation } from './src/main/ets/default/view/browserOperation/ShareMenuOperation';
|
||||
|
||||
export { DetailsDialogComponent } from './src/main/ets/default/view/DetailsDialogComponent';
|
||||
|
||||
export { AddNotesDialog } from './src/main/ets/default/view/dialog/AddNotesDialog';
|
||||
|
||||
export { CancelOperationDialog } from './src/main/ets/default/view/dialog/CancelOperationDialog';
|
||||
|
||||
export { CopyOrMoveDialog } from './src/main/ets/default/view/dialog/CopyOrMoveDialog';
|
||||
|
||||
export { CustomDialogView } from './src/main/ets/default/view/dialog/CustomDialogView';
|
||||
|
||||
export { DeleteDialog } from './src/main/ets/default/view/dialog/DeleteDialog';
|
||||
|
||||
export { DeleteProgressDialog } from './src/main/ets/default/view/dialog/DeleteProgressDialog';
|
||||
|
||||
export { DetailsDialog } from './src/main/ets/default/view/dialog/DetailsDialog';
|
||||
|
||||
export { DownloadCancelOperationDialog } from './src/main/ets/default/view/dialog/DownloadCancelOperationDialog';
|
||||
|
||||
export { EditExitDialog } from './src/main/ets/default/view/dialog/EditExitDialog';
|
||||
|
||||
export { MultiSelectDialog } from './src/main/ets/default/view/dialog/MultiSelectDialog';
|
||||
|
||||
export { NewAlbumDialog } from './src/main/ets/default/view/dialog/NewAlbumDialog';
|
||||
|
||||
export { ProgressDialog } from './src/main/ets/default/view/dialog/ProgressDialog';
|
||||
|
||||
export { RenameDialog } from './src/main/ets/default/view/dialog/RenameDialog';
|
||||
|
||||
export { SaveDialog } from './src/main/ets/default/view/dialog/SaveDialog';
|
||||
|
||||
export { SaveImageDialog } from './src/main/ets/default/view/dialog/SaveImageDialog';
|
||||
|
||||
export { GridScrollBar } from './src/main/ets/default/view/GridScrollBar';
|
||||
|
||||
export { ImageGridItemComponent } from './src/main/ets/default/view/ImageGridItemComponent';
|
||||
|
||||
export { NoPhotoComponent } from './src/main/ets/default/view/NoPhotoComponent';
|
||||
|
||||
export { NoPhotoIndexComponent } from './src/main/ets/default/view/NoPhotoIndexComponent';
|
||||
|
||||
export { PhotoBrowserBg } from './src/main/ets/default/view/PhotoBrowserBg';
|
||||
|
||||
export { PhotoBrowserComponentBg } from './src/main/ets/default/view/PhotoBrowserComponentBg';
|
||||
|
||||
export { PhotoBrowserHolder } from './src/main/ets/default/view/PhotoBrowserHolder';
|
||||
|
||||
export { PhotoItem } from './src/main/ets/default/view/PhotoItem';
|
||||
|
||||
export { PhotoSwiper } from './src/main/ets/default/view/PhotoSwiper';
|
||||
|
||||
export { TabBar, TabBarForAlbumSet, DEVICE_TYPE } from './src/main/ets/default/view/TabBar';
|
||||
|
||||
export { ThirdSelectPhotoBrowserActionBar } from './src/main/ets/default/view/ThirdSelectPhotoBrowserActionBar';
|
||||
|
||||
export { MediaConstants } from './src/main/ets/default/model/common/MediaConstants';
|
||||
|
||||
export { BreakpointSystem, BreakPointType } from './src/main/ets/default/utils/BreakPointSystem';
|
||||
|
||||
export { MediaOperationBasePage } from './src/main/ets/default/view/browserOperation/MediaOperationBasePage';
|
||||
|
||||
export { BrowserController } from './src/main/ets/default/view/BrowserController';
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "@ohos/base",
|
||||
"name": "@ohos/common",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 1
|
||||
}
|
13
common/package.json
Normal file
13
common/package.json
Normal file
@ -0,0 +1,13 @@
|
||||
{
|
||||
"name": "@ohos/common",
|
||||
"version": "1.0.0",
|
||||
"description": "a npm package which contains common function",
|
||||
"ohos": {
|
||||
"org": "huawei",
|
||||
"buildTool": "hvigor",
|
||||
"directoryLevel": "module"
|
||||
},
|
||||
"main": "index.ts",
|
||||
"dependencies": {},
|
||||
"type": "module"
|
||||
}
|
987
common/src/main/ets/default/access/UserFileManagerAccess.ts
Normal file
987
common/src/main/ets/default/access/UserFileManagerAccess.ts
Normal file
@ -0,0 +1,987 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2023 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 { Log } from '../utils/Log';
|
||||
import userFileManager from '@ohos.filemanagement.userFileManager';
|
||||
import { Constants } from '../model/common/Constants';
|
||||
import { TraceControllerUtils } from '../utils/TraceControllerUtils';
|
||||
import dataSharePredicates from '@ohos.data.dataSharePredicates';
|
||||
import { UiUtil } from '../utils/UiUtil';
|
||||
import { AlbumDefine } from '../model/browser/AlbumDefine';
|
||||
|
||||
const TAG: string = 'common_UserFileManagerAccess';
|
||||
|
||||
export type UserFileManager = userFileManager.UserFileManager;
|
||||
|
||||
export type FileType = userFileManager.FileType;
|
||||
|
||||
export type FetchOptions = userFileManager.FetchOptions;
|
||||
|
||||
export type FileAsset = userFileManager.FileAsset;
|
||||
|
||||
export type MediaPeerInfo = userFileManager.PeerInfo;
|
||||
|
||||
export type Album = userFileManager.Album;
|
||||
|
||||
export type ImageVideoKey = userFileManager.ImageVideoKey;
|
||||
|
||||
export type AlbumKey = userFileManager.AlbumKey;
|
||||
|
||||
export type AlbumType = userFileManager.AlbumType;
|
||||
|
||||
export type AlbumSubType = userFileManager.AlbumSubType;
|
||||
|
||||
export type DefaultChangeUri = userFileManager.DefaultChangeUri;
|
||||
|
||||
export type ChangeData = userFileManager.ChangeData;
|
||||
|
||||
export type FileAssetEx = {
|
||||
count: number;
|
||||
obj: FileAsset;
|
||||
};
|
||||
|
||||
export class UserFileManagerAccess {
|
||||
static readonly REGISTER_TYPE_IMAGE_CHANGE = 'imageChange';
|
||||
static readonly REGISTER_TYPE_VIDEO_CHANGE = 'videoChange';
|
||||
static readonly REGISTER_TYPE_DEVICE_CHANGE = 'deviceChange';
|
||||
static readonly REGISTER_TYPE_ALBUM_CHANGE = 'albumChange';
|
||||
static readonly REGISTER_TYPE_REMOTE_FILE_CHANGE = 'remoteFileChange';
|
||||
static readonly MEDIA_TYPE_IMAGE = userFileManager.FileType.IMAGE;
|
||||
static readonly MEDIA_TYPE_VIDEO = userFileManager.FileType.VIDEO;
|
||||
static readonly FILE_KEY_MEDIA_TYPE = userFileManager.ImageVideoKey.FILE_TYPE;
|
||||
static readonly FILE_KEY_DISPLAY_NAME = userFileManager.ImageVideoKey.DISPLAY_NAME;
|
||||
static readonly FILE_KEY_DATE_TAKEN = userFileManager.ImageVideoKey.DATE_ADDED;
|
||||
static readonly FILE_KEY_DATE_TRASHED = userFileManager.ImageVideoKey.DATE_TRASHED;
|
||||
static readonly FILE_KEY_TITLE = userFileManager.ImageVideoKey.TITLE;
|
||||
|
||||
static readonly REGISTER_TYPE_ALL_PHOTOS = "file://media/Photo";
|
||||
static readonly REGISTER_TYPE_ALL_ALBUMS = "file://media/PhotoAlbum";
|
||||
static readonly NOTIFY_ADD = userFileManager.NotifyType.NOTIFY_ADD;
|
||||
static readonly NOTIFY_UPDATE = userFileManager.NotifyType.NOTIFY_UPDATE;
|
||||
static readonly NOTIFY_REMOVE = userFileManager.NotifyType.NOTIFY_REMOVE;
|
||||
static readonly NOTIFY_ALBUM_ADD_ASSET = userFileManager.NotifyType.NOTIFY_ALBUM_ADD_ASSET;
|
||||
static readonly NOTIFY_ALBUM_REMOVE_ASSET = userFileManager.NotifyType.NOTIFY_ALBUM_REMOVE_ASSET;
|
||||
|
||||
static readonly ALL_IMAGE_VIDEO_FETCH_COLUMNS: Array<string> = [
|
||||
userFileManager.ImageVideoKey.URI.toString(),
|
||||
userFileManager.ImageVideoKey.FILE_TYPE.toString(),
|
||||
userFileManager.ImageVideoKey.DISPLAY_NAME.toString(),
|
||||
userFileManager.ImageVideoKey.DATE_ADDED.toString(),
|
||||
userFileManager.ImageVideoKey.DATE_MODIFIED.toString(),
|
||||
userFileManager.ImageVideoKey.TITLE.toString(),
|
||||
userFileManager.ImageVideoKey.DURATION.toString(),
|
||||
userFileManager.ImageVideoKey.WIDTH.toString(),
|
||||
userFileManager.ImageVideoKey.HEIGHT.toString(),
|
||||
userFileManager.ImageVideoKey.DATE_TAKEN.toString(),
|
||||
userFileManager.ImageVideoKey.ORIENTATION.toString(),
|
||||
userFileManager.ImageVideoKey.FAVORITE.toString(),
|
||||
userFileManager.ImageVideoKey.POSITION.toString(),
|
||||
userFileManager.ImageVideoKey.DATE_TRASHED.toString(),
|
||||
userFileManager.ImageVideoKey.HIDDEN.toString(),
|
||||
"size" // TODO 等媒体库枚举字段上库
|
||||
]
|
||||
|
||||
static readonly GROUP_BY_KEY: string = 'count(*)';
|
||||
|
||||
static readonly IMAGE_ALBUM_SUB_TYPE: AlbumSubType = 1031; // TODO 等媒体库枚举字段上库
|
||||
static readonly CAMERA_ALBUM_SUB_TYPE: AlbumSubType = userFileManager.AlbumSubType.CAMERA;
|
||||
static readonly FAVORITE_ALBUM_SUB_TYPE: AlbumSubType = userFileManager.AlbumSubType.FAVORITE;
|
||||
static readonly VIDEO_ALBUM_SUB_TYPE: AlbumSubType = userFileManager.AlbumSubType.VIDEO;
|
||||
static readonly TRASH_ALBUM_SUB_TYPE: AlbumSubType = userFileManager.AlbumSubType.TRASH;
|
||||
static readonly SCREENSHOT_ALBUM_SUB_TYPE: AlbumSubType = userFileManager.AlbumSubType.SCREENSHOT;
|
||||
static readonly HIDDEN_ALBUM_SUB_TYPE: AlbumSubType = userFileManager.AlbumSubType.HIDDEN;
|
||||
|
||||
static readonly ALL_SYSTEM_ALBUM_LIST: Array<AlbumSubType> = [
|
||||
UserFileManagerAccess.IMAGE_ALBUM_SUB_TYPE,
|
||||
UserFileManagerAccess.VIDEO_ALBUM_SUB_TYPE,
|
||||
UserFileManagerAccess.SCREENSHOT_ALBUM_SUB_TYPE,
|
||||
UserFileManagerAccess.FAVORITE_ALBUM_SUB_TYPE,
|
||||
UserFileManagerAccess.TRASH_ALBUM_SUB_TYPE,
|
||||
UserFileManagerAccess.HIDDEN_ALBUM_SUB_TYPE,
|
||||
UserFileManagerAccess.FAVORITE_ALBUM_SUB_TYPE,
|
||||
]
|
||||
|
||||
static readonly SYSTEM_BEFORE_USER_ALBUM_LIST: Array<AlbumSubType> = [
|
||||
UserFileManagerAccess.IMAGE_ALBUM_SUB_TYPE,
|
||||
UserFileManagerAccess.VIDEO_ALBUM_SUB_TYPE,
|
||||
UserFileManagerAccess.SCREENSHOT_ALBUM_SUB_TYPE,
|
||||
UserFileManagerAccess.FAVORITE_ALBUM_SUB_TYPE
|
||||
]
|
||||
|
||||
static readonly SYSTEM_AFTER_USER_ALBUM_LIST: Array<AlbumSubType> = [
|
||||
UserFileManagerAccess.HIDDEN_ALBUM_SUB_TYPE,
|
||||
UserFileManagerAccess.TRASH_ALBUM_SUB_TYPE
|
||||
]
|
||||
|
||||
private media: userFileManager.UserFileManager = null;
|
||||
private requestTime: number;
|
||||
|
||||
private systemAlbumUriMap: Map<AlbumSubType, string> = new Map<AlbumSubType, string>();
|
||||
|
||||
constructor() {
|
||||
this.requestTime = Date.now();
|
||||
}
|
||||
|
||||
public static getInstance(): UserFileManagerAccess {
|
||||
if (AppStorage.Get(Constants.APP_KEY_INSTANCE_MEDIA_LIBRARY_ACCESS) == null) {
|
||||
AppStorage.SetOrCreate(Constants.APP_KEY_INSTANCE_MEDIA_LIBRARY_ACCESS, new UserFileManagerAccess());
|
||||
}
|
||||
return AppStorage.Get(Constants.APP_KEY_INSTANCE_MEDIA_LIBRARY_ACCESS);
|
||||
}
|
||||
|
||||
onCreate(context) {
|
||||
Log.debug(TAG, `Photos_UserFileManagerAccess onCreate ${context}`);
|
||||
if (this.media) {
|
||||
Log.debug(TAG, `Photos_UserFileManagerAccess onCreate already`);
|
||||
return;
|
||||
}
|
||||
this.media = userFileManager.getUserFileMgr(context);
|
||||
Log.debug(TAG, 'Photos_UserFileManagerAccess onCreate end');
|
||||
if (!this.media) {
|
||||
Log.error(TAG, 'get media library instance failed!');
|
||||
}
|
||||
Log.info(TAG, 'onCreate done');
|
||||
}
|
||||
|
||||
onDestroy() {
|
||||
try {
|
||||
this.media && this.media.release();
|
||||
this.media = null;
|
||||
Log.info(TAG, 'onDestroy done');
|
||||
} catch (err) {
|
||||
Log.error(TAG, `onDestroy error: ${err}`);
|
||||
}
|
||||
}
|
||||
|
||||
getMediaLibrary(): userFileManager.UserFileManager {
|
||||
return this.media;
|
||||
}
|
||||
|
||||
getSystemAlbumUriMap() {
|
||||
return this.systemAlbumUriMap;
|
||||
}
|
||||
|
||||
async getAllObject(fetchOpt: FetchOptions): Promise<Array<FileAsset>> {
|
||||
Log.info(TAG, `getAllObject: ${JSON.stringify(fetchOpt)}`);
|
||||
if (!this.media) {
|
||||
Log.error(TAG, '[getAllObject] media resource is null!');
|
||||
return [];
|
||||
}
|
||||
try {
|
||||
TraceControllerUtils.startTraceWithTaskId('getAllObject', this.requestTime);
|
||||
let dataList = await this.media.getPhotoAssets(fetchOpt);
|
||||
if (!dataList) {
|
||||
Log.warn(TAG, 'get all Object Data with empty dataList');
|
||||
return [];
|
||||
}
|
||||
Log.debug(TAG, `get all Object Data raw data size: ${dataList.getCount()}`);
|
||||
if (dataList.getCount() <= 0) {
|
||||
dataList.close();
|
||||
return [];
|
||||
}
|
||||
|
||||
let result = await dataList.getAllObject();
|
||||
dataList.close();
|
||||
TraceControllerUtils.finishTraceWithTaskId('getAllObject', this.requestTime);
|
||||
return result;
|
||||
} catch (error) {
|
||||
Log.error(TAG, `getAllObject error: ${error}`);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
async deleteAlbumByUri(uri: string): Promise<void> {
|
||||
if (!this.media) {
|
||||
Log.error(TAG, '[deleteAlbum] media resource is null!');
|
||||
return;
|
||||
}
|
||||
try {
|
||||
Log.debug(TAG, `deleteAlbumByUri uri is ` + uri);
|
||||
let album = await this.getAlbumByUri(uri);
|
||||
await this.media.deleteAlbums([album]); // TODO 接口支持批量删除,传参后续整改
|
||||
} catch (error) {
|
||||
Log.error(TAG, `deleteAlbumByUri error: ${error}`);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
async getCount(fetchOpt: FetchOptions): Promise<number> {
|
||||
Log.info(TAG, `getCount: ${JSON.stringify(fetchOpt)}`);
|
||||
if (!this.media) {
|
||||
Log.error(TAG, '[getCount] media resource is null!');
|
||||
return 0;
|
||||
}
|
||||
try {
|
||||
TraceControllerUtils.startTraceWithTaskId('getCount', this.requestTime);
|
||||
let dataList = await this.media.getPhotoAssets(fetchOpt);
|
||||
if (!dataList) {
|
||||
Log.warn(TAG, 'get count dataList is 0');
|
||||
return 0;
|
||||
}
|
||||
Log.debug(TAG, `get count raw data size: ${dataList.getCount()}`);
|
||||
let result = dataList.getCount();
|
||||
dataList.close();
|
||||
TraceControllerUtils.finishTraceWithTaskId('getCount', this.requestTime);
|
||||
return result;
|
||||
} catch (error) {
|
||||
Log.error(TAG, `get Count error: ${error}`);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
async getObject(fetchOpt: FetchOptions): Promise<FileAsset> {
|
||||
Log.info(TAG, `getObject: ${JSON.stringify(fetchOpt)}`);
|
||||
if (!this.media) {
|
||||
Log.error(TAG, '[getObject] media resource is null!');
|
||||
return undefined;
|
||||
}
|
||||
try {
|
||||
TraceControllerUtils.startTraceWithTaskId('getObject', this.requestTime);
|
||||
let fileResult = await this.media.getPhotoAssets(fetchOpt);
|
||||
if (fileResult) {
|
||||
Log.info(TAG, `getObject count is ${fileResult.getCount()}`);
|
||||
if (fileResult.getCount() <= 0) {
|
||||
fileResult.close();
|
||||
return undefined;
|
||||
}
|
||||
let file = await fileResult.getFirstObject();
|
||||
fileResult.close();
|
||||
if (file) {
|
||||
return file;
|
||||
} else {
|
||||
Log.error(TAG, 'Failed getObject');
|
||||
}
|
||||
}
|
||||
TraceControllerUtils.finishTraceWithTaskId('getObject', this.requestTime);
|
||||
return undefined;
|
||||
} catch (error) {
|
||||
Log.error(TAG, `getObject loadData error: ${error}`);
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
async getFirstObject(fetchOpt: FetchOptions): Promise<FileAssetEx> {
|
||||
let result = {
|
||||
count: 0,
|
||||
obj: null
|
||||
}
|
||||
Log.info(TAG, `getFirstObject: ${JSON.stringify(fetchOpt)}`);
|
||||
if (!this.media) {
|
||||
Log.error(TAG, '[getFirstObject] media resource is null!');
|
||||
return result;
|
||||
}
|
||||
try {
|
||||
TraceControllerUtils.startTraceWithTaskId('getFirstObject', this.requestTime);
|
||||
let fileResult = await this.media.getPhotoAssets(fetchOpt);
|
||||
if (fileResult) {
|
||||
result.count = fileResult.getCount();
|
||||
Log.info(TAG, `getFirstObject count is ${result.count}`);
|
||||
if (result.count <= 0) {
|
||||
fileResult.close();
|
||||
return result;
|
||||
}
|
||||
let file = await fileResult.getFirstObject();
|
||||
fileResult.close();
|
||||
if (file) {
|
||||
result.obj = file;
|
||||
return result;
|
||||
} else {
|
||||
Log.error(TAG, 'Failed getFirstObject');
|
||||
}
|
||||
}
|
||||
TraceControllerUtils.finishTraceWithTaskId('getFirstObject', this.requestTime);
|
||||
return result;
|
||||
} catch (error) {
|
||||
Log.error(TAG, `getFirstObject loadData error: ${error}`);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
async deleteAlbumPhotos(uri: String): Promise<void> {
|
||||
Log.debug(TAG, `deleteAsset uri: ${uri}`);
|
||||
if (!this.media) {
|
||||
Log.error(TAG, '[deleteAsset] media resource is null!');
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取回收站内的文件
|
||||
let predicates = new dataSharePredicates.DataSharePredicates();
|
||||
let fetchOptions = {
|
||||
fetchColumns: [],
|
||||
predicates: predicates
|
||||
};
|
||||
|
||||
try {
|
||||
const fetchResult = await this.media.getPhotoAssets(fetchOptions);
|
||||
var asset = await fetchResult.getFirstObject();
|
||||
} catch (err) {
|
||||
console.info('fetch failed, message =', err);
|
||||
}
|
||||
|
||||
if (asset == undefined) {
|
||||
console.error('asset not exist');
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await this.media.delete(asset.uri);
|
||||
console.info("delete successfully");
|
||||
} catch (err) {
|
||||
console.error("delete failed with error: " + err);
|
||||
}
|
||||
}
|
||||
|
||||
async createAsset(mediaType: FileType, displayName: string): Promise<FileAsset> {
|
||||
Log.debug(TAG, 'createAsset start');
|
||||
if (!this.media) {
|
||||
Log.error(TAG, '[createAsset] media resource is null!');
|
||||
return null;
|
||||
}
|
||||
Log.info(TAG, `createAsset ${mediaType} ${displayName} `);
|
||||
let fileAsset = await this.media.createPhotoAsset(displayName);
|
||||
Log.debug(TAG, `createAsset end. new fileAsset: ${fileAsset}`);
|
||||
if (!fileAsset) {
|
||||
Log.error(TAG, 'createAsset Fail');
|
||||
return null;
|
||||
}
|
||||
return fileAsset;
|
||||
}
|
||||
|
||||
async openAsset(mode: string, fileAsset: FileAsset): Promise<number> {
|
||||
Log.debug(TAG, 'openAsset start');
|
||||
if (!fileAsset) {
|
||||
Log.error(TAG, 'fileAsset is null');
|
||||
return;
|
||||
}
|
||||
let fd = await fileAsset.open(mode);
|
||||
Log.info(TAG, `openAsset end. fd: ${fd}`);
|
||||
if (fd <= 0) {
|
||||
Log.error(TAG, 'openAsset Fail');
|
||||
return;
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
async closeAsset(fd: number, fileAsset: FileAsset): Promise<void> {
|
||||
Log.debug(TAG, 'closeAsset start');
|
||||
if (!fileAsset) {
|
||||
Log.error(TAG, 'fileAsset is null');
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await fileAsset.close(fd);
|
||||
} catch (err) {
|
||||
Log.error(TAG, 'file asset close error: ' + JSON.stringify(err));
|
||||
}
|
||||
}
|
||||
|
||||
async deleteToTrash(uri: string): Promise<void> {
|
||||
Log.debug(TAG, 'trashAsset start');
|
||||
await this.media.delete(uri);
|
||||
}
|
||||
|
||||
async deleteFromTrash(assets: Array<FileAsset>): Promise<void> {
|
||||
let fetchResult = await this.media.getAlbums(userFileManager.AlbumType.SYSTEM, userFileManager.AlbumSubType.TRASH);
|
||||
let trashAlbum = await fetchResult.getFirstObject();
|
||||
await trashAlbum.deletePhotoAssets(assets);
|
||||
fetchResult.close();
|
||||
}
|
||||
|
||||
async recoverFromTrash(assets: Array<FileAsset>): Promise<void> {
|
||||
let fetchResult = await this.media.getAlbums(userFileManager.AlbumType.SYSTEM, userFileManager.AlbumSubType.TRASH);
|
||||
let trashAlbum = await fetchResult.getFirstObject();
|
||||
await trashAlbum.recoverPhotoAssets(assets);
|
||||
fetchResult.close();
|
||||
}
|
||||
|
||||
async getTrashAssetByUri(assetUri: string): Promise<FileAsset> {
|
||||
Log.info(TAG, "getTrashAssetByUri");
|
||||
let trashAlbumResult = await this.media.getAlbums(userFileManager.AlbumType.SYSTEM, userFileManager.AlbumSubType.TRASH);
|
||||
let trashAlbum = await trashAlbumResult.getFirstObject();
|
||||
let predicates = new dataSharePredicates.DataSharePredicates();
|
||||
predicates.equalTo(userFileManager.ImageVideoKey.URI.toString(), assetUri);
|
||||
let fetchOption: userFileManager.FetchOptions = {
|
||||
predicates: predicates,
|
||||
fetchColumns: []
|
||||
};
|
||||
fetchOption.fetchColumns = Array.prototype.slice.call(UserFileManagerAccess.ALL_IMAGE_VIDEO_FETCH_COLUMNS);
|
||||
let fetchResult = await trashAlbum.getPhotoAssets(fetchOption);
|
||||
let assets = await fetchResult.getFirstObject();
|
||||
fetchResult.close();
|
||||
trashAlbumResult.close();
|
||||
return assets;
|
||||
}
|
||||
|
||||
async getFavoriteObject(fetchOpt: FetchOptions): Promise<Array<FileAsset>> {
|
||||
if (!this.media) {
|
||||
Log.error(TAG, '[getFavoriteObject] media resource is null!');
|
||||
return [];
|
||||
}
|
||||
try {
|
||||
let fetchResult = await this.media.getAlbums(userFileManager.AlbumType.SYSTEM, userFileManager.AlbumSubType.FAVORITE);
|
||||
let favoriteAlbum = await fetchResult.getFirstObject();
|
||||
let fileFetchResult = await favoriteAlbum.getPhotoAssets(fetchOpt)
|
||||
Log.info(TAG, `[getFavoriteObject] get smart albums length:${fileFetchResult.getCount()} name:${favoriteAlbum.albumName}`);
|
||||
Log.debug(TAG, `[getFavoriteObject] object count :${fileFetchResult.getCount()}`);
|
||||
let objects = await fileFetchResult.getAllObject();
|
||||
Log.debug(TAG, `[getFavoriteObject] objects done`);
|
||||
fileFetchResult.close();
|
||||
fetchResult.close();
|
||||
return objects;
|
||||
} catch (err) {
|
||||
Log.error(TAG, `Get favorite object exception! msg: ${err}`);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
async getTrashObject(fetchOpt: FetchOptions): Promise<Array<FileAsset>> {
|
||||
Log.info(TAG, `Get trash object: ${JSON.stringify(fetchOpt)}`);
|
||||
if (!this.media) {
|
||||
Log.error(TAG, '[getTrashObject] media resource is null!');
|
||||
return [];
|
||||
}
|
||||
try {
|
||||
let fetchResult = await this.media.getAlbums(userFileManager.AlbumType.SYSTEM, userFileManager.AlbumSubType.TRASH);
|
||||
let trashAlbum = await fetchResult.getFirstObject();
|
||||
let fileFetchResult = await trashAlbum.getPhotoAssets(fetchOpt)
|
||||
Log.debug(TAG, `[getTrashObject] object count :${fileFetchResult.getCount()}`);
|
||||
let objects = await fileFetchResult.getAllObject();
|
||||
Log.debug(TAG, `[getTrashObject] get objects done`);
|
||||
fileFetchResult.close();
|
||||
fetchResult.close();
|
||||
return objects;
|
||||
} catch (err) {
|
||||
Log.error(TAG, `Get Trash Object exception! msg: ${err}`);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
async getUserAlbumObject(fetchOpt: FetchOptions, fileFetchOpt: FetchOptions): Promise<Array<FileAsset>> {
|
||||
Log.info(TAG, `getEntityAlbumObject opt${JSON.stringify(fetchOpt)} fileOpt${JSON.stringify(fileFetchOpt)}`);
|
||||
if (!this.media) {
|
||||
Log.error(TAG, '[getEntityAlbumObject] media resource is null!');
|
||||
return [];
|
||||
}
|
||||
try {
|
||||
// 按照fetchOpt获取用户指定的相册---游标
|
||||
let fetchResult = await this.media.getAlbums(userFileManager.AlbumType.USER, userFileManager.AlbumSubType.USER_GENERIC, fetchOpt);
|
||||
|
||||
//获取所有的相册的
|
||||
let albums = await fetchResult.getAllObject();
|
||||
if (albums.length === 0) {
|
||||
return [];
|
||||
}
|
||||
let objects = [];
|
||||
for (let i = 0; i < albums.length; i++) {
|
||||
let album = albums[i];
|
||||
Log.debug(TAG, `[getEntityAlbumObject]Albums name:${album.albumName} index: ${i}`);
|
||||
// 返回一个游标
|
||||
let fileResult = await album.getPhotoAssets(fileFetchOpt);
|
||||
Log.debug(TAG, `[getEntityAlbumObject]objects count :${fileResult.getCount()}`);
|
||||
if (fileResult.getCount() <= 0) {
|
||||
fileResult.close();
|
||||
continue;
|
||||
}
|
||||
//获取该album游标下的所有资源
|
||||
objects = await fileResult.getAllObject();
|
||||
Log.debug(TAG, `[getEntityAlbumObject]Get objects done`);
|
||||
fileResult.close();
|
||||
}
|
||||
fetchResult.close();
|
||||
return objects;
|
||||
} catch (err) {
|
||||
Log.error(TAG, `Get Entity Album Object exception! msg: ${err}`);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
async getFavoriteCount(favoriteFetchOpt: FetchOptions): Promise<number> {
|
||||
Log.info(TAG, `[getFavoriteCount] FetchOptions: ${JSON.stringify(favoriteFetchOpt)}`);
|
||||
return await this.getSystemAlbumCount(favoriteFetchOpt, userFileManager.AlbumSubType.FAVORITE);
|
||||
}
|
||||
|
||||
async getTrashCount(trashFetchOpt: FetchOptions): Promise<number> {
|
||||
Log.info(TAG, `[getTrashCount] FetchOptions: ${JSON.stringify(trashFetchOpt)}`);
|
||||
return await this.getSystemAlbumCount(trashFetchOpt, userFileManager.AlbumSubType.TRASH);
|
||||
}
|
||||
|
||||
async getSystemAlbumCount(fetchOpt: FetchOptions, albumSubType: userFileManager.AlbumSubType): Promise<number> {
|
||||
Log.info(TAG, `[getTrashCount] FetchOptions: ${JSON.stringify(fetchOpt)}`);
|
||||
if (!this.media) {
|
||||
Log.error(TAG, '[getTrashCount] media resource is null!');
|
||||
return 0;
|
||||
}
|
||||
try {
|
||||
let fetchResult = await this.media.getAlbums(userFileManager.AlbumType.SYSTEM, albumSubType);
|
||||
let systemAlbum = await fetchResult.getFirstObject();
|
||||
let fileFetchResult = await systemAlbum.getPhotoAssets(fetchOpt)
|
||||
let count = fileFetchResult.getCount();
|
||||
fileFetchResult.close();
|
||||
fetchResult.close();
|
||||
return count;
|
||||
} catch (err) {
|
||||
Log.error(TAG, `Get Trash count exception! msg: ${err}`);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
async getAlbumFirstObject(album: Album): Promise<FileAsset> {
|
||||
Log.info(TAG, `[getAlbumFirstObject]`);
|
||||
if (!this.media) {
|
||||
Log.error(TAG, '[getAlbumFirstObject] media resource is null!');
|
||||
return undefined;
|
||||
}
|
||||
try {
|
||||
let opt = AlbumDefine.getFileFetchOpt(0, 1);
|
||||
let fetchResult = await album.getPhotoAssets(opt);
|
||||
if (!fetchResult) {
|
||||
Log.error(TAG, 'fetchResult is null');
|
||||
}
|
||||
let fileAsset = await fetchResult.getFirstObject();
|
||||
fetchResult.close();
|
||||
Log.info(TAG, `cover uri ${fileAsset.uri}`);
|
||||
return fileAsset;
|
||||
} catch (err) {
|
||||
Log.error(TAG, `Get album first obj exception! msg: ${err}`);
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
async getUserAlbumCount(albumFetchOpt: FetchOptions, fileFetchOpt?: FetchOptions): Promise<number> {
|
||||
Log.info(TAG, `getUSerAlbumCount FetchOptions: ${JSON.stringify(albumFetchOpt)}`);
|
||||
if (!this.media) {
|
||||
Log.error(TAG, '[getTrashCount] media resource is null!');
|
||||
return 0;
|
||||
}
|
||||
try {
|
||||
let fetchResult = await this.media.getAlbums(userFileManager.AlbumType.USER, userFileManager.AlbumSubType.USER_GENERIC, albumFetchOpt);
|
||||
let userAlbum = await fetchResult.getFirstObject();
|
||||
let fileFetchResult = await userAlbum.getPhotoAssets(fileFetchOpt);
|
||||
let count = fileFetchResult.getCount();
|
||||
fileFetchResult.close();
|
||||
fetchResult.close();
|
||||
return count;
|
||||
} catch (err) {
|
||||
Log.error(TAG, `Get Trash count exception! msg: ${err}`);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
async getUserAlbums(fetchOpt?: FetchOptions): Promise<Array<Album>> {
|
||||
Log.info(TAG, `getUserAlbums start}`);
|
||||
if (!this.media) {
|
||||
Log.error(TAG, '[getUserAlbums] media resource is null!');
|
||||
return [];
|
||||
}
|
||||
try {
|
||||
let fetchResult;
|
||||
if (fetchOpt) {
|
||||
fetchResult = await this.media.getAlbums(userFileManager.AlbumType.USER, userFileManager.AlbumSubType.USER_GENERIC, fetchOpt);
|
||||
} else {
|
||||
fetchResult = await this.media.getAlbums(userFileManager.AlbumType.USER, userFileManager.AlbumSubType.USER_GENERIC);
|
||||
}
|
||||
let userAlbums = await fetchResult.getAllObject();
|
||||
Log.info(TAG, `[getUserAlbums]length :${userAlbums.length}`);
|
||||
fetchResult.close();
|
||||
return userAlbums;
|
||||
} catch (err) {
|
||||
Log.error(TAG, `Get User Album exception! msg: ${err}`);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
async prepareSystemAlbums(): Promise<void> {
|
||||
if (!this.media) {
|
||||
Log.error(TAG, 'prepareSystemAlbums media resource is null!');
|
||||
return;
|
||||
}
|
||||
try {
|
||||
for (let i = 0; i < UserFileManagerAccess.SYSTEM_BEFORE_USER_ALBUM_LIST.length; i++) {
|
||||
let albumSubType = UserFileManagerAccess.SYSTEM_BEFORE_USER_ALBUM_LIST[i];
|
||||
let fetchResult = await this.media.getAlbums(userFileManager.AlbumType.SYSTEM, albumSubType);
|
||||
let systemAlbum = await fetchResult.getFirstObject();
|
||||
this.systemAlbumUriMap.set(albumSubType, systemAlbum.albumUri);
|
||||
Log.info(TAG, `prepareSystemAlbums before :${systemAlbum.albumUri}, ${albumSubType}`);
|
||||
fetchResult.close();
|
||||
}
|
||||
for (let i = 0; i < UserFileManagerAccess.SYSTEM_AFTER_USER_ALBUM_LIST.length; i++) {
|
||||
let albumSubType = UserFileManagerAccess.SYSTEM_AFTER_USER_ALBUM_LIST[i];
|
||||
let fetchResult = await this.media.getAlbums(userFileManager.AlbumType.SYSTEM, albumSubType);
|
||||
let systemAlbum = await fetchResult.getFirstObject();
|
||||
this.systemAlbumUriMap.set(albumSubType, systemAlbum.albumUri);
|
||||
Log.info(TAG, `prepareSystemAlbums after :${systemAlbum.albumUri}, ${albumSubType}`);
|
||||
fetchResult.close();
|
||||
}
|
||||
return;
|
||||
} catch (err) {
|
||||
Log.error(TAG, `prepareSystemAlbums Get System Album exception! msg: ${err}`);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
async getSystemAlbums(): Promise<Array<Album>> {
|
||||
if (!this.media) {
|
||||
Log.error(TAG, 'getSystemAlbums media resource is null!');
|
||||
return undefined;
|
||||
}
|
||||
try {
|
||||
let systemAlbumList: Array<Album> = [];
|
||||
for (let i = 0; i < UserFileManagerAccess.SYSTEM_BEFORE_USER_ALBUM_LIST.length; i++) {
|
||||
let albumSubType = UserFileManagerAccess.SYSTEM_BEFORE_USER_ALBUM_LIST[i];
|
||||
let fetchResult = await this.media.getAlbums(userFileManager.AlbumType.SYSTEM, albumSubType);
|
||||
let systemAlbum = await fetchResult.getFirstObject();
|
||||
this.systemAlbumUriMap.set(albumSubType, systemAlbum.albumUri);
|
||||
systemAlbumList.push(systemAlbum);
|
||||
Log.info(TAG, `getSystemAlbums :${systemAlbum.albumUri}`);
|
||||
fetchResult.close();
|
||||
}
|
||||
return systemAlbumList;
|
||||
} catch (err) {
|
||||
Log.error(TAG, `getSystemAlbums Get System Album exception! msg: ${err}`);
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
async getTrashAlbum(): Promise<Album> {
|
||||
if (!this.media) {
|
||||
Log.error(TAG, 'getTrashAlbum media resource is null!');
|
||||
return undefined;
|
||||
}
|
||||
try {
|
||||
let fetchResult = await this.media.getAlbums(userFileManager.AlbumType.SYSTEM, userFileManager.AlbumSubType.TRASH);
|
||||
let trashAlbum: Album = await fetchResult.getFirstObject();
|
||||
this.systemAlbumUriMap.set(UserFileManagerAccess.TRASH_ALBUM_SUB_TYPE, trashAlbum.albumUri);
|
||||
Log.info(TAG, `getTrashAlbum : ${trashAlbum.albumUri}`);
|
||||
fetchResult.close();
|
||||
return trashAlbum;
|
||||
} catch (err) {
|
||||
Log.error(TAG, `getTrashAlbum Get Trash Album exception! msg: ${err}`);
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
async getHiddenAlbum(): Promise<Album> {
|
||||
if (!this.media) {
|
||||
Log.error(TAG, 'getHiddenAlbum media resource is null!');
|
||||
return undefined;
|
||||
}
|
||||
try {
|
||||
let fetchResult = await this.media.getAlbums(userFileManager.AlbumType.SYSTEM, userFileManager.AlbumSubType.HIDDEN);
|
||||
let hiddenAlbum: Album = await fetchResult.getFirstObject();
|
||||
Log.info(TAG, `getHiddenAlbum : ${hiddenAlbum.albumUri}`);
|
||||
fetchResult.close();
|
||||
return hiddenAlbum;
|
||||
} catch (err) {
|
||||
Log.error(TAG, `getHiddenAlbum Get Hidden Album exception! msg: ${err}`);
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
async addFileToAlbum(albumUri: string, sourceAsset: FileAsset) {
|
||||
if (!this.media) {
|
||||
Log.error(TAG, '[getHiddenAlbum] media resource is null!');
|
||||
return undefined;
|
||||
}
|
||||
Log.debug(TAG, `addFileToAlbum albumUri is ` + albumUri + ` sourceAsset is ` + sourceAsset);
|
||||
let album = await this.getAlbumByUri(albumUri);
|
||||
await album.addPhotoAssets([sourceAsset]); // TODO 媒体库支持批量添加,传参后续整改
|
||||
}
|
||||
|
||||
isImage(fileAsset: FileAsset): boolean {
|
||||
return fileAsset.fileType === userFileManager.FileType.IMAGE;
|
||||
}
|
||||
|
||||
isSystemAlbum(album: Album): boolean {
|
||||
return album.albumType === userFileManager.AlbumType.SYSTEM;
|
||||
}
|
||||
|
||||
isTrashAlbum(album: Album): boolean {
|
||||
return album.albumSubType === userFileManager.AlbumSubType.TRASH;
|
||||
}
|
||||
|
||||
isScreenShotAlbum(album: Album): boolean {
|
||||
return album.albumSubType === userFileManager.AlbumSubType.SCREENSHOT;
|
||||
}
|
||||
|
||||
isVideoAlbum(album: Album): boolean {
|
||||
return album.albumSubType === userFileManager.AlbumSubType.VIDEO;
|
||||
}
|
||||
|
||||
isFavorAlbum(album: Album): boolean {
|
||||
return album.albumSubType === userFileManager.AlbumSubType.FAVORITE;
|
||||
}
|
||||
|
||||
async getAlbumName(album: Album): Promise<string> {
|
||||
if (this.isSystemAlbum(album)) {
|
||||
// 系统相册,图库自己命名
|
||||
switch (album.albumSubType) {
|
||||
case UserFileManagerAccess.IMAGE_ALBUM_SUB_TYPE:
|
||||
return await UiUtil.getResourceString($r('app.string.album_photos'));
|
||||
case UserFileManagerAccess.FAVORITE_ALBUM_SUB_TYPE:
|
||||
return await UiUtil.getResourceString($r('app.string.album_favor'));
|
||||
case UserFileManagerAccess.VIDEO_ALBUM_SUB_TYPE:
|
||||
return await UiUtil.getResourceString($r('app.string.album_video'));
|
||||
case UserFileManagerAccess.TRASH_ALBUM_SUB_TYPE:
|
||||
return await UiUtil.getResourceString($r('app.string.album_recycle'));
|
||||
case UserFileManagerAccess.SCREENSHOT_ALBUM_SUB_TYPE:
|
||||
return await UiUtil.getResourceString($r('app.string.album_screen_shot'));
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
}
|
||||
// 用户相册,直接返回
|
||||
return album.albumName;
|
||||
}
|
||||
|
||||
getAlbumDateModified(album: Album): number {
|
||||
return album.dateModified;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据Uri获取相册,不区分系统相册和用户相册
|
||||
* @param albumUri 相册Uri
|
||||
* @returns 目标相册
|
||||
*/
|
||||
async getAlbumByUri(albumUri: string): Promise<Album> {
|
||||
Log.debug(TAG, 'getAlbumByUri albumUri is ' + albumUri);
|
||||
if (!this.media) {
|
||||
Log.error(TAG, 'getAlbumByUri media resource is null!');
|
||||
return undefined;
|
||||
}
|
||||
try {
|
||||
let albumFetchOpt = AlbumDefine.getAlbumFetchOptByUri(albumUri);
|
||||
// @ts-ignore // TODO 支持不传入type时删掉 ts-ignore
|
||||
let fetchResult = await this.media.getAlbums(albumFetchOpt);
|
||||
if (!fetchResult) {
|
||||
Log.warn(TAG, 'getAlbumByUri return null');
|
||||
return undefined;
|
||||
}
|
||||
Log.debug(TAG, `getAlbumByUri return raw data size: ${fetchResult.getCount()}`);
|
||||
if (fetchResult.getCount() <= 0) {
|
||||
fetchResult.close();
|
||||
return undefined;
|
||||
}
|
||||
let album = await fetchResult.getFirstObject();
|
||||
if (!album) {
|
||||
Log.warn(TAG, `getAlbumByUri result is null`);
|
||||
}
|
||||
fetchResult.close();
|
||||
return album;
|
||||
} catch (err) {
|
||||
Log.error(TAG, `getAlbumByUri Get Album by uri exception! msg: ${err}`);
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
async getAlbumByName(albumName: string): Promise<Album> {
|
||||
if (!this.media) {
|
||||
Log.error(TAG, 'getAlbumByName media resource is null!');
|
||||
return undefined;
|
||||
}
|
||||
try {
|
||||
Log.info(TAG, `getAlbumByName name: ${albumName}`);
|
||||
let albumFetchOpt = AlbumDefine.getAlbumFetchOptByName(albumName);
|
||||
// @ts-ignore // TODO 需要媒体库新开接口,支持仅传入fetchOpt
|
||||
let fetchResult = await this.media.getAlbums(albumFetchOpt);
|
||||
if (!fetchResult) {
|
||||
Log.error(TAG, 'getAlbumByName fetchResult undefined')
|
||||
return undefined;
|
||||
}
|
||||
if (fetchResult.getCount() <= 0) {
|
||||
fetchResult.close();
|
||||
return undefined;
|
||||
}
|
||||
let album = await fetchResult.getFirstObject();
|
||||
if (!album) {
|
||||
Log.error(TAG, 'getAlbumByName album undefined')
|
||||
return undefined;
|
||||
}
|
||||
Log.info(TAG, `getAlbumByName get album success ${JSON.stringify(album)}`)
|
||||
fetchResult.close();
|
||||
return album;
|
||||
} catch (err) {
|
||||
Log.error(TAG, `getAlbumByName exception! msg: ${err}`);
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
getSystemAlbumUri(subType: userFileManager.AlbumSubType): string {
|
||||
Log.debug(TAG, `getSystemAlbumUri subType: ${subType}`);
|
||||
let uri = this.systemAlbumUriMap.get(subType);
|
||||
Log.debug(TAG, `getSystemAlbumUri uri: ${uri}`);
|
||||
return uri;
|
||||
}
|
||||
|
||||
async createUserAlbum(albumName: string): Promise<Album> {
|
||||
let album: Album = undefined;
|
||||
try {
|
||||
album = await this.media.createAlbum(albumName);
|
||||
} catch (error) {
|
||||
Log.error(TAG, `deleteAlbumByUri error: ${error}`);
|
||||
}
|
||||
return album;
|
||||
}
|
||||
|
||||
async renameAlbum(album: Album, name: string): Promise<void> {
|
||||
if (!this.media) {
|
||||
Log.error(TAG, '[renameAlbum] media resource is null!');
|
||||
return;
|
||||
}
|
||||
try {
|
||||
album.albumName = name;
|
||||
album.commitModify();
|
||||
} catch (err) {
|
||||
Log.error(TAG, `Rename Album exception! msg: ${err}`);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 判断当前图库是否有相同名字的系统相册,跟随多语言变化
|
||||
async isAlbumNameExistInSystemAlbums(name: string): Promise<boolean> {
|
||||
for (let i = 0; i < UserFileManagerAccess.ALL_SYSTEM_ALBUM_LIST.length; i++) {
|
||||
let systemAlbumName: string;
|
||||
switch (UserFileManagerAccess.ALL_SYSTEM_ALBUM_LIST[i]) {
|
||||
case UserFileManagerAccess.IMAGE_ALBUM_SUB_TYPE:
|
||||
systemAlbumName = await UiUtil.getResourceString($r('app.string.album_photos'));
|
||||
break;
|
||||
case UserFileManagerAccess.FAVORITE_ALBUM_SUB_TYPE:
|
||||
systemAlbumName = await UiUtil.getResourceString($r('app.string.album_favor'));
|
||||
break;
|
||||
case UserFileManagerAccess.VIDEO_ALBUM_SUB_TYPE:
|
||||
systemAlbumName = await UiUtil.getResourceString($r('app.string.album_video'));
|
||||
break;
|
||||
case UserFileManagerAccess.TRASH_ALBUM_SUB_TYPE:
|
||||
systemAlbumName = await UiUtil.getResourceString($r('app.string.album_recycle'));
|
||||
break;
|
||||
case UserFileManagerAccess.SCREENSHOT_ALBUM_SUB_TYPE:
|
||||
systemAlbumName = await UiUtil.getResourceString($r('app.string.album_screen_shot'));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (systemAlbumName === name) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件fetchOption
|
||||
*/
|
||||
export class FileFetchOptionBuilder {
|
||||
private fetchOption: userFileManager.FetchOptions = {
|
||||
predicates: new dataSharePredicates.DataSharePredicates(),
|
||||
fetchColumns: []
|
||||
};
|
||||
|
||||
constructor(fetchOpt?) {
|
||||
if (fetchOpt) {
|
||||
this.fetchOption = fetchOpt;
|
||||
}
|
||||
this.fetchOption.fetchColumns = Array.prototype.slice.call(UserFileManagerAccess.ALL_IMAGE_VIDEO_FETCH_COLUMNS) // 暂时获取所有columns
|
||||
}
|
||||
|
||||
build(): FetchOptions {
|
||||
return this.fetchOption;
|
||||
}
|
||||
|
||||
// 用于timeline分组查询
|
||||
groupBy(): FileFetchOptionBuilder {
|
||||
this.fetchOption.fetchColumns.push(UserFileManagerAccess.GROUP_BY_KEY);
|
||||
return this;
|
||||
}
|
||||
|
||||
media(mediaType: string): FileFetchOptionBuilder {
|
||||
this.fetchOption.predicates.equalTo(userFileManager.ImageVideoKey.FILE_TYPE.toString(), mediaType)
|
||||
return this;
|
||||
}
|
||||
|
||||
uri(uri: string): FileFetchOptionBuilder {
|
||||
this.fetchOption.predicates.equalTo(userFileManager.ImageVideoKey.URI.toString(), uri)
|
||||
return this;
|
||||
}
|
||||
|
||||
order(key: string, isAsc = true): FileFetchOptionBuilder {
|
||||
if (isAsc) {
|
||||
//升序
|
||||
this.fetchOption.predicates.orderByAsc(key);
|
||||
} else {
|
||||
//降序
|
||||
this.fetchOption.predicates.orderByDesc(key);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
logicalAnd(): FileFetchOptionBuilder {
|
||||
this.fetchOption.predicates.and();
|
||||
return this;
|
||||
}
|
||||
|
||||
select(start: number, count: number): FileFetchOptionBuilder {
|
||||
this.fetchOption.predicates.limit(count, start);
|
||||
return this;
|
||||
}
|
||||
|
||||
displayName(name: string): FileFetchOptionBuilder {
|
||||
this.fetchOption.predicates.equalTo(userFileManager.ImageVideoKey.DISPLAY_NAME.toString(), name);
|
||||
return this;
|
||||
}
|
||||
|
||||
fetchColumns(columns: Array<string>): FileFetchOptionBuilder {
|
||||
this.fetchOption.fetchColumns = columns;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 相册fetchOption
|
||||
*/
|
||||
export class AlbumFetchOptionBuilder {
|
||||
private fetchOption: userFileManager.FetchOptions = {
|
||||
predicates: new dataSharePredicates.DataSharePredicates(),
|
||||
fetchColumns: []
|
||||
};
|
||||
|
||||
constructor(fetchOpt?) {
|
||||
if (fetchOpt) {
|
||||
this.fetchOption = fetchOpt;
|
||||
}
|
||||
}
|
||||
|
||||
build(): FetchOptions {
|
||||
return this.fetchOption;
|
||||
}
|
||||
|
||||
media(mediaType: string): AlbumFetchOptionBuilder {
|
||||
this.fetchOption.predicates.equalTo(userFileManager.AlbumKey.FILE_TYPE.toString(), mediaType)
|
||||
return this;
|
||||
}
|
||||
|
||||
logicalAnd(): AlbumFetchOptionBuilder {
|
||||
this.fetchOption.predicates.and();
|
||||
return this;
|
||||
}
|
||||
|
||||
albumName(name: string): AlbumFetchOptionBuilder {
|
||||
this.fetchOption.predicates.equalTo(userFileManager.AlbumKey.ALBUM_NAME.toString(), name);
|
||||
return this;
|
||||
}
|
||||
|
||||
albumUri(uri: string): AlbumFetchOptionBuilder {
|
||||
this.fetchOption.predicates.equalTo(userFileManager.AlbumKey.URI.toString(), uri);
|
||||
return this;
|
||||
}
|
||||
}
|
37
common/src/main/ets/default/interface/BrowserDataFactory.ts
Normal file
37
common/src/main/ets/default/interface/BrowserDataFactory.ts
Normal file
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* 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 { TimelineDataImpl } from '../model/browser/photo/TimelineDataImpl';
|
||||
import { PhotoDataImpl } from '../model/browser/photo/PhotoDataImpl';
|
||||
import { AlbumDataImpl } from '../model/browser/album/AlbumDataImpl';
|
||||
import type { BrowserDataInterface } from './BrowserDataInterface';
|
||||
|
||||
export class BrowserDataFactory {
|
||||
static readonly TYPE_PHOTO = 'photo';
|
||||
static readonly TYPE_ALBUM = 'album';
|
||||
static readonly TYPE_GROUP = 'group';
|
||||
static readonly TYPE_DISTRIBUTED = 'distributed';
|
||||
|
||||
static getFeature(type: string, param?: unknown): BrowserDataInterface {
|
||||
if (type == BrowserDataFactory.TYPE_ALBUM) {
|
||||
return new AlbumDataImpl(param);
|
||||
} else if (type == BrowserDataFactory.TYPE_PHOTO) {
|
||||
return new PhotoDataImpl();
|
||||
} else if (type == BrowserDataFactory.TYPE_GROUP) {
|
||||
return new TimelineDataImpl();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2023 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export interface BrowserDataInterface {
|
||||
getData(callback: any, param: any): void;
|
||||
|
||||
getDataCount(callback: any, param: any): void;
|
||||
|
||||
getDataByUri(uri: any, deviceId?: any): any;
|
||||
|
||||
getDataByName(name: string, albumInfo?: any): any;
|
||||
|
||||
getFileAssets?(id: any, param: any): any;
|
||||
|
||||
getDataIndexByUri(callback: unknown, param: unknown, uri: string): void;
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2023 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 '../model/browser/photo/OperationImpl';
|
||||
import { AlbumOperationImpl } from '../model/browser/album/AlbumOperationImpl';
|
||||
import type { BrowserOperationInterface } from './BrowserOperationInterface';
|
||||
|
||||
export class BrowserOperationFactory {
|
||||
static readonly TYPE_PHOTO = 'photo';
|
||||
static readonly TYPE_ALBUM = 'album';
|
||||
|
||||
static getFeature(type: string): BrowserOperationInterface {
|
||||
if (type == BrowserOperationFactory.TYPE_PHOTO) {
|
||||
return new OperationImpl();
|
||||
} else if (type == BrowserOperationFactory.TYPE_ALBUM) {
|
||||
return new AlbumOperationImpl();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2023 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 type { FileAsset, FileType } from '../access/UserFileManagerAccess';
|
||||
|
||||
export type CreateParam = {
|
||||
fileType: FileType,
|
||||
name: string,
|
||||
};
|
||||
|
||||
export interface BrowserOperationInterface {
|
||||
create(param: any): any;
|
||||
|
||||
delete(uri: string): any;
|
||||
|
||||
deleteTrash(assets: Array<FileAsset>): any;
|
||||
|
||||
recoverFromTrash(assets: Array<FileAsset>): any;
|
||||
|
||||
trash(uri: string, isTrash: boolean): any;
|
||||
|
||||
remove(uris: Array<string>, albumUri: string): any;
|
||||
|
||||
copy(source: any, target: any): any;
|
||||
|
||||
favor(uri: string, isFavor: boolean): void;
|
||||
|
||||
setName(source: any, name: string): void;
|
||||
|
||||
change(source: any): any;
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (c) 2022 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import type { MenuOperation } from '../view/browserOperation/MenuOperation';
|
||||
import { MenuContext } from '../view/browserOperation/MenuContext';
|
||||
import { Log } from '../utils/Log';
|
||||
import { Constants } from '../model/common/Constants';
|
||||
|
||||
const TAG: string = 'common_MenuOperationFactory';
|
||||
|
||||
export class MenuOperationFactory {
|
||||
private constructor() {
|
||||
Log.info(TAG, 'constructor');
|
||||
}
|
||||
|
||||
public static getInstance(): MenuOperationFactory {
|
||||
if (AppStorage.Get(Constants.APP_KEY_MENU_OPERATION_FACTORY) == null) {
|
||||
AppStorage.SetOrCreate(Constants.APP_KEY_MENU_OPERATION_FACTORY, new MenuOperationFactory());
|
||||
}
|
||||
return AppStorage.Get(Constants.APP_KEY_MENU_OPERATION_FACTORY);
|
||||
}
|
||||
|
||||
public createMenuOperation<T extends MenuOperation>
|
||||
(operation: { new(menuContext: MenuContext): T }, menuContext: MenuContext): T {
|
||||
Log.info(TAG, `createMenuOperation: ${operation.name}`);
|
||||
return new operation(menuContext);
|
||||
}
|
||||
}
|
223
common/src/main/ets/default/model/browser/AbsDataSource.ts
Normal file
223
common/src/main/ets/default/model/browser/AbsDataSource.ts
Normal file
@ -0,0 +1,223 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2023 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 { Log } from '../../utils/Log';
|
||||
import type { LoadingListener } from './LoadingListener';
|
||||
|
||||
const TAG: string = 'common_AbsDataSource';
|
||||
|
||||
// Abs DataSource
|
||||
export abstract class AbsDataSource implements IDataSource {
|
||||
// Last data change time
|
||||
lastChangeTime = 0;
|
||||
|
||||
// Last refresh time
|
||||
lastUpdateTime = 0;
|
||||
lastTotalCount = -1;
|
||||
|
||||
// Data change monitoring
|
||||
listeners: DataChangeListener[] = [];
|
||||
|
||||
// callbacks
|
||||
mCallbacks = new Map<string, Function>();
|
||||
|
||||
// Is data initialized
|
||||
isInitData: boolean;
|
||||
|
||||
// Are there any new data changes
|
||||
hasNewChange = false;
|
||||
|
||||
// Freeze data refresh
|
||||
isFreezeDataUpdate = false;
|
||||
|
||||
// Whether the page is in the foreground, and the data can be refreshed in the foreground
|
||||
isActive = true;
|
||||
|
||||
// Data loading listener
|
||||
private loadingListeners: Array<LoadingListener> = new Array<LoadingListener>();
|
||||
|
||||
constructor() {
|
||||
this.registerObserver();
|
||||
}
|
||||
|
||||
abstract initData(): void;
|
||||
|
||||
abstract loadData(): void;
|
||||
|
||||
abstract totalCount(): number;
|
||||
|
||||
abstract getData(index: number): any;
|
||||
|
||||
initialize(): void {
|
||||
if (!this.isInitData) {
|
||||
this.initData();
|
||||
this.isInitData = true;
|
||||
}
|
||||
}
|
||||
|
||||
registerDataChangeListener(listener: DataChangeListener): void {
|
||||
Log.info(TAG, 'registerDataChangeListener');
|
||||
if (this.listeners.indexOf(listener) < 0) {
|
||||
this.listeners.push(listener);
|
||||
Log.info(TAG, `registerDataChangeListener, add listener, length: ${this.listeners.length}`);
|
||||
}
|
||||
this.initialize();
|
||||
}
|
||||
|
||||
unregisterDataChangeListener(listener: DataChangeListener): void {
|
||||
Log.info(TAG, 'unregisterDataChangeListener');
|
||||
const pos = this.listeners.indexOf(listener);
|
||||
if (pos >= 0) {
|
||||
this.listeners.splice(pos, 1);
|
||||
Log.info(TAG, `registerDataChangeListener, remove listener, length: ${this.listeners.length}`);
|
||||
}
|
||||
this.unregisterObserver();
|
||||
}
|
||||
|
||||
/**
|
||||
* Overall refresh of notification framework
|
||||
*/
|
||||
onDataReloaded(): void {
|
||||
if (this.isFreezeDataUpdate) {
|
||||
return;
|
||||
}
|
||||
Log.info(TAG, `onDataReloaded listeners size ${this.listeners.length}`)
|
||||
this.listeners.forEach(listener => {
|
||||
listener.onDataReloaded();
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Notification frame refresh by index
|
||||
*
|
||||
* @param layoutIndex index
|
||||
*/
|
||||
onDataChanged(layoutIndex: number): void {
|
||||
if (this.isFreezeDataUpdate) {
|
||||
return;
|
||||
}
|
||||
this.listeners.forEach(listener => {
|
||||
listener.onDataChanged(layoutIndex);
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete frame refresh by index
|
||||
*
|
||||
* @param layoutIndex index
|
||||
*/
|
||||
onDataDeleted(layoutIndex: number): void {
|
||||
if (this.isFreezeDataUpdate) {
|
||||
return;
|
||||
}
|
||||
this.listeners.forEach(listener => {
|
||||
listener.onDataDeleted(layoutIndex);
|
||||
})
|
||||
}
|
||||
|
||||
public registerObserver(): void {
|
||||
}
|
||||
|
||||
public unregisterObserver(): void {
|
||||
}
|
||||
|
||||
registerCallback(name: string, cb: Function) {
|
||||
this.mCallbacks[name] = cb;
|
||||
}
|
||||
|
||||
unregisterCallback(name) {
|
||||
this.mCallbacks[name] = undefined;
|
||||
}
|
||||
|
||||
addLoadingListener(listener: LoadingListener): void {
|
||||
if (listener == null) {
|
||||
Log.error(TAG, 'listener is null');
|
||||
return;
|
||||
}
|
||||
if (this.loadingListeners.indexOf(listener) > -1) {
|
||||
return;
|
||||
}
|
||||
this.loadingListeners.push(listener);
|
||||
}
|
||||
|
||||
removeLoadingListener(listener: LoadingListener): void {
|
||||
if (listener == null) {
|
||||
Log.error(TAG, 'listener is null');
|
||||
return;
|
||||
}
|
||||
let index = this.loadingListeners.indexOf(listener);
|
||||
if (index > -1) {
|
||||
this.loadingListeners.splice(index, 1);
|
||||
}
|
||||
}
|
||||
|
||||
notifyDataChanged(dataIndex: number): void {
|
||||
Log.debug(TAG, `notifyDataChanged,loadingListeners size:${this.loadingListeners.length},index:${dataIndex}`);
|
||||
for (let listener of this.loadingListeners) {
|
||||
listener.onDataChanged(dataIndex);
|
||||
}
|
||||
}
|
||||
|
||||
notifyDataLoadingFinished(): void {
|
||||
Log.info(TAG, `notifyDataLoadingFinished, loadingListeners size:${this.loadingListeners.length}`);
|
||||
for (let listener of this.loadingListeners) {
|
||||
listener.onDataLoadingFinished();
|
||||
}
|
||||
}
|
||||
|
||||
notifySizeLoadingFinished(size: number): void {
|
||||
Log.info(TAG, `notifySizeLoadingFinished, loadingListeners size: ${this.loadingListeners.length}`);
|
||||
for (let listener of this.loadingListeners) {
|
||||
listener.onSizeLoadingFinished(size);
|
||||
}
|
||||
}
|
||||
|
||||
onActive(): void {
|
||||
Log.info(TAG, `onActive, lastUpdateTime=${this.lastUpdateTime}, lastChangeTime=${this.lastChangeTime}`);
|
||||
if (this.isActive === false) {
|
||||
this.isActive = true;
|
||||
if (this.lastUpdateTime < this.lastChangeTime) {
|
||||
// Page back to the foreground, if there is a refresh media library reload refresh.
|
||||
this.loadData();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onInActive(): void {
|
||||
Log.info(TAG, 'onInActive');
|
||||
this.isActive = false;
|
||||
}
|
||||
|
||||
freeze(): void {
|
||||
Log.info(TAG, 'freeze')
|
||||
this.isFreezeDataUpdate = true;
|
||||
}
|
||||
|
||||
unfreeze(): void {
|
||||
Log.info(TAG, 'unfreeze')
|
||||
this.isFreezeDataUpdate = false;
|
||||
}
|
||||
|
||||
onChange(mediaType) {
|
||||
this.lastChangeTime = Date.now();
|
||||
Log.debug(TAG, `onChange mediaType: ${mediaType} ${this.hasNewChange} ${this.isActive}`);
|
||||
if (!this.hasNewChange) {
|
||||
this.hasNewChange = true;
|
||||
if (this.isActive) {
|
||||
this.loadData();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
102
common/src/main/ets/default/model/browser/AlbumDefine.ts
Normal file
102
common/src/main/ets/default/model/browser/AlbumDefine.ts
Normal file
@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2023 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 type { FetchOptions } from '../../access/UserFileManagerAccess';
|
||||
import {
|
||||
AlbumFetchOptionBuilder,
|
||||
FileFetchOptionBuilder,
|
||||
UserFileManagerAccess
|
||||
} from '../../access/UserFileManagerAccess';
|
||||
import { Log } from '../../utils/Log';
|
||||
|
||||
const TAG: string = 'AlbumDefine';
|
||||
|
||||
export class AlbumDefine {
|
||||
static readonly ALBUM_ID_ALL: string = 'default_all';
|
||||
static readonly ALBUM_ID_CAMERA: string = 'default_camera';
|
||||
static readonly ALBUM_ID_VIDEO: string = 'default_video';
|
||||
static readonly ALBUM_ID_RECYCLE: string = 'default_recycle';
|
||||
static readonly ALBUM_ID_FAVOR: string = 'default_favor';
|
||||
static readonly ALBUM_ID_SNAPSHOT: string = 'default_snapshot';
|
||||
static readonly ALBUM_ID_REMOTE: string = 'default_remote';
|
||||
|
||||
// 需要过滤的媒体文件类型
|
||||
static readonly FILTER_MEDIA_TYPE_ALL: string = 'FILTER_MEDIA_TYPE_ALL';
|
||||
static readonly FILTER_MEDIA_TYPE_IMAGE: string = 'FILTER_MEDIA_TYPE_IMAGE';
|
||||
static readonly FILTER_MEDIA_TYPE_VIDEO: string = 'FILTER_MEDIA_TYPE_VIDEO';
|
||||
|
||||
static getFileFetchOpt(startIndex?: number, count?: number, filterMediaType?: string): FetchOptions {
|
||||
let builder = new FileFetchOptionBuilder();
|
||||
builder
|
||||
.order(UserFileManagerAccess.FILE_KEY_DATE_TAKEN.toString(), false)
|
||||
if (filterMediaType) {
|
||||
AlbumDefine.setFilterMediaType(builder, filterMediaType)
|
||||
}
|
||||
if (startIndex != undefined && count != undefined && startIndex >= 0 && count >= 0) {
|
||||
builder.select(startIndex, count);
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
static getFavoriteFetchOpt(filterMediaType?: string) {
|
||||
let builder = new FileFetchOptionBuilder();
|
||||
if (filterMediaType == undefined) {
|
||||
filterMediaType = AlbumDefine.FILTER_MEDIA_TYPE_ALL;
|
||||
}
|
||||
AlbumDefine.setFilterMediaType(builder, filterMediaType)
|
||||
.order(UserFileManagerAccess.FILE_KEY_DATE_TAKEN.toString(), false);
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
static getTimelineGroupFetchOpt() {
|
||||
let builder = new FileFetchOptionBuilder();
|
||||
builder.groupBy();
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
static getFileFetchOptByUri(uri: string) {
|
||||
let builder = new FileFetchOptionBuilder().uri(uri);
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
static getFileFetchOptByName(displayName: string) {
|
||||
let builder = new FileFetchOptionBuilder().displayName(displayName);
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
static getAlbumFetchOptByName(name: string) {
|
||||
let builder = new AlbumFetchOptionBuilder()
|
||||
builder.albumName(name);
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
static getAlbumFetchOptByUri(albumUri: string) {
|
||||
let builder = new AlbumFetchOptionBuilder();
|
||||
if (albumUri) {
|
||||
builder.albumUri(albumUri);
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
static setFilterMediaType(builder: FileFetchOptionBuilder, filterMediaType: string): FileFetchOptionBuilder {
|
||||
if (filterMediaType == AlbumDefine.FILTER_MEDIA_TYPE_IMAGE) {
|
||||
builder.media(UserFileManagerAccess.MEDIA_TYPE_IMAGE.toString())
|
||||
} else if (filterMediaType == AlbumDefine.FILTER_MEDIA_TYPE_VIDEO) {
|
||||
builder.media(UserFileManagerAccess.MEDIA_TYPE_VIDEO.toString())
|
||||
}
|
||||
return builder;
|
||||
}
|
||||
}
|
163
common/src/main/ets/default/model/browser/BrowserDataImpl.ts
Normal file
163
common/src/main/ets/default/model/browser/BrowserDataImpl.ts
Normal file
@ -0,0 +1,163 @@
|
||||
/*
|
||||
* Copyright (c) 2023 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 type { BrowserDataInterface } from '../../interface/BrowserDataInterface';
|
||||
import { AlbumDefine } from './AlbumDefine';
|
||||
import { Log } from '../../utils/Log';
|
||||
import type { FileAsset, FileAssetEx } from '../../access/UserFileManagerAccess';
|
||||
import { Album, UserFileManagerAccess } from '../../access/UserFileManagerAccess';
|
||||
import type { AsyncCallback } from '../common/AsyncCallback';
|
||||
import { Constants } from '../common/Constants';
|
||||
|
||||
const TAG: string = 'BrowserDataImpl';
|
||||
|
||||
export type QueryParam = {
|
||||
albumUri: string,
|
||||
start: number,
|
||||
count: number,
|
||||
filterMediaType?: string
|
||||
};
|
||||
|
||||
export abstract class BrowserDataImpl implements BrowserDataInterface {
|
||||
static readonly THUMBNAIL_WIDTH = 256;
|
||||
|
||||
abstract getData(callback: AsyncCallback<unknown> | Function, param: QueryParam): void;
|
||||
|
||||
abstract getDataCount(callback: AsyncCallback<unknown> | Function, param: unknown): void;
|
||||
|
||||
abstract getDataByUri(uri: unknown): unknown;
|
||||
|
||||
abstract getDataByName(name: string, albumUri: string): unknown;
|
||||
|
||||
abstract getDataIndexByUri(callback: AsyncCallback<unknown> | Function, param: QueryParam, uri: string): void;
|
||||
|
||||
async getAllObject(fetchOpt): Promise<Array<FileAsset>> {
|
||||
Log.debug(TAG, `getAllObject ${fetchOpt}`);
|
||||
let allObject = await UserFileManagerAccess.getInstance().getAllObject(fetchOpt);
|
||||
return allObject;
|
||||
}
|
||||
|
||||
async getCount(fetchOpt): Promise<number> {
|
||||
let count = await UserFileManagerAccess.getInstance().getCount(fetchOpt);
|
||||
return count;
|
||||
}
|
||||
|
||||
async getFirstObject(fetchOpt): Promise<FileAssetEx> {
|
||||
Log.debug(TAG, 'getFirstObject');
|
||||
let firstObject: FileAssetEx = await UserFileManagerAccess.getInstance().getFirstObject(fetchOpt);
|
||||
return firstObject;
|
||||
}
|
||||
|
||||
async getObject(fetchOpt): Promise<FileAsset> {
|
||||
Log.debug(TAG, 'getFirstObject');
|
||||
let object: FileAsset = await UserFileManagerAccess.getInstance().getObject(fetchOpt);
|
||||
return object;
|
||||
}
|
||||
|
||||
async getItems(albumUri?: string, startIndex?: number, count?: number, filterMediaType?: string): Promise<Array<FileAsset>> {
|
||||
let result: Array<FileAsset> = null;
|
||||
|
||||
// albumUri不为空,则从目标相册中获取;否则默认从所有媒体资源中获取
|
||||
if (albumUri) {
|
||||
let album: Album = await UserFileManagerAccess.getInstance().getAlbumByUri(albumUri);
|
||||
let fetchOpt = AlbumDefine.getFileFetchOpt(startIndex, count, filterMediaType);
|
||||
if (album) {
|
||||
let fetchResult = await album.getPhotoAssets(fetchOpt);
|
||||
result = await fetchResult.getAllObject();
|
||||
fetchResult.close();
|
||||
}
|
||||
} else {
|
||||
let fetchOpt = AlbumDefine.getFileFetchOpt(startIndex, count, filterMediaType);
|
||||
Log.debug(TAG, `getMediaItem start ${JSON.stringify(fetchOpt)}`);
|
||||
result = await UserFileManagerAccess.getInstance().getAllObject(fetchOpt);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
async getItemsCount(albumUri?: string, filterMediaType?: string): Promise<number> {
|
||||
let count = 0;
|
||||
if (albumUri) {
|
||||
let album: Album = await UserFileManagerAccess.getInstance().getAlbumByUri(albumUri);
|
||||
// 当前相册count始终为0,先通过查全部图片获取count
|
||||
let fetchOpt = AlbumDefine.getFileFetchOpt(Constants.INVALID, Constants.INVALID, filterMediaType);
|
||||
let fetchResult = await album.getPhotoAssets(fetchOpt);
|
||||
count = fetchResult.getCount();
|
||||
fetchResult.close();
|
||||
} else {
|
||||
let fetchOpt = AlbumDefine.getFileFetchOpt(undefined, undefined, filterMediaType);
|
||||
count = await this.getCount(fetchOpt);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
async getItemIndexByUri(uri: string, albumUri?: string): Promise<number> {
|
||||
let index: number = Constants.INVALID;
|
||||
let realUri: string = uri;
|
||||
let realAlbumUri: string = albumUri;
|
||||
let allObject: Array<FileAsset> = null;
|
||||
Log.debug(TAG, `getItemIndexByUri uri: ${uri}, albumUri: ${albumUri}`);
|
||||
if (!uri.startsWith(UserFileManagerAccess.REGISTER_TYPE_ALL_PHOTOS)) {
|
||||
let targetObject: FileAsset = await this.getItemByUri(uri);
|
||||
if (targetObject) {
|
||||
Log.debug(TAG, `find photo for uri: ${realUri}=>${targetObject.uri}`);
|
||||
realUri = targetObject.uri;
|
||||
}
|
||||
}
|
||||
Log.debug(TAG, `getItemIndexByUri real uri: ${realUri}`);
|
||||
if (albumUri && albumUri.length > 0) {
|
||||
if (!albumUri.startsWith(UserFileManagerAccess.REGISTER_TYPE_ALL_ALBUMS)) {
|
||||
let targetAlbum: Album = await UserFileManagerAccess.getInstance().getAlbumByUri(albumUri);
|
||||
if (targetAlbum) {
|
||||
Log.debug(TAG, `find album for uri: ${realAlbumUri}=>${targetAlbum.albumUri}`);
|
||||
realAlbumUri = targetAlbum.albumUri;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
realAlbumUri = "";
|
||||
}
|
||||
Log.debug(TAG, `getItemIndexByUri real album uri: ${realAlbumUri}`);
|
||||
allObject = await this.getItems(realAlbumUri);
|
||||
if (allObject) {
|
||||
Log.debug(TAG, `getItemIndexByUri count: ${allObject.length}`);
|
||||
index = allObject.findIndex((item: FileAsset) => item.uri == realUri);
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
async getItemByUri(uri: string): Promise<FileAsset> {
|
||||
let object: FileAsset = null;
|
||||
let fetchOpt = AlbumDefine.getFileFetchOptByUri(uri);
|
||||
object = await this.getObject(fetchOpt);
|
||||
return object;
|
||||
}
|
||||
|
||||
getThumbnailSafe(sourceUri: string, size?): string {
|
||||
try {
|
||||
if (size) {
|
||||
if (size.width != 0 && size.height != 0) {
|
||||
return `${sourceUri}/thumbnail/${size.width}/${size.height}`;
|
||||
} else {
|
||||
Log.warn(TAG, 'getThumbnailSafe with width==0 and height==0, so do not use thumbnail' + JSON.stringify(size));
|
||||
return `${sourceUri}`;
|
||||
}
|
||||
} else {
|
||||
return `${sourceUri}/thumbnail/${BrowserDataImpl.THUMBNAIL_WIDTH}/${BrowserDataImpl.THUMBNAIL_WIDTH}`;
|
||||
}
|
||||
} catch (err) {
|
||||
Log.warn(TAG, `get Thumbnail Failed! msg:${err}`);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -13,17 +13,20 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { MediaObserverCallback } from '../interface/MediaObserverCallback';
|
||||
import { MediaLibDataChangeCallback } from '../interface/MediaLibDataChangeCallback';
|
||||
import type { MediaObserverCallback } from './dataObserver/MediaObserverCallback';
|
||||
|
||||
interface MediaCallback {
|
||||
onMediaLibDataChange(mediaType: string): void;
|
||||
}
|
||||
|
||||
export class CommonObserverCallback implements MediaObserverCallback {
|
||||
private source: MediaLibDataChangeCallback;
|
||||
source: MediaCallback;
|
||||
|
||||
constructor(source: MediaLibDataChangeCallback) {
|
||||
constructor(source: MediaCallback) {
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
onChange(mediaType: string): void {
|
||||
onChange(mediaType: string) {
|
||||
this.source.onMediaLibDataChange(mediaType);
|
||||
}
|
||||
}
|
@ -13,15 +13,24 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Log } from '../utils/Log';
|
||||
export interface LoadingListener {
|
||||
|
||||
const TAG = "StringUtil"
|
||||
/**
|
||||
* Quantity change notice
|
||||
*
|
||||
* @param size Total number of media
|
||||
*/
|
||||
onSizeLoadingFinished(size: number): void;
|
||||
|
||||
export function getIdFromUri(uri: string): number {
|
||||
let srcIndex = uri.lastIndexOf('/');
|
||||
let srcEnd = uri.length;
|
||||
let srcId = uri.substring(srcIndex + 1, srcEnd);
|
||||
let fileId = new Number(srcId);
|
||||
Log.info(TAG, "getIdByUri fileId: " + fileId);
|
||||
return fileId.valueOf();
|
||||
/**
|
||||
* Data loading completion notification
|
||||
*/
|
||||
onDataLoadingFinished(): void;
|
||||
|
||||
/**
|
||||
* Data change notification
|
||||
*
|
||||
* @param dataIndex dataIndex
|
||||
*/
|
||||
onDataChanged(dataIndex: number): void;
|
||||
}
|
883
common/src/main/ets/default/model/browser/SelectManager.ts
Normal file
883
common/src/main/ets/default/model/browser/SelectManager.ts
Normal file
@ -0,0 +1,883 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2023 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 { TimelineData } from './photo/TimelineData';
|
||||
import { Log } from '../../utils/Log';
|
||||
import { MediaItem } from './photo/MediaItem';
|
||||
import type { AsyncCallback } from '../common/AsyncCallback';
|
||||
import { BrowserDataFactory } from '../../interface/BrowserDataFactory';
|
||||
import type { BrowserDataInterface } from '../../interface/BrowserDataInterface';
|
||||
import { Constants } from '../common/Constants';
|
||||
|
||||
const TAG: string = 'common_SelectManager';
|
||||
|
||||
export class BucketSelectionEntry {
|
||||
private groupId = -1;
|
||||
private clickedSet: Set<string> = new Set();
|
||||
private totalCount = 0;
|
||||
private inverseSelection = false;
|
||||
private groupSelect = false;
|
||||
|
||||
public setGroupId(groupId: number): void {
|
||||
this.groupId = groupId;
|
||||
}
|
||||
|
||||
public getGroupId(): number {
|
||||
return this.groupId;
|
||||
}
|
||||
|
||||
public setTotalCount(totalCount: number): void {
|
||||
this.totalCount = totalCount;
|
||||
}
|
||||
|
||||
public getTotalCount(): number {
|
||||
return this.totalCount;
|
||||
}
|
||||
|
||||
public setGroupSelect(selectMode: boolean): void {
|
||||
this.groupSelect = selectMode;
|
||||
}
|
||||
|
||||
public getGroupSelect(): boolean {
|
||||
return this.groupSelect;
|
||||
}
|
||||
|
||||
public getClickSet(): Set<string> {
|
||||
return this.clickedSet;
|
||||
}
|
||||
|
||||
public getSelectedCount(): number {
|
||||
if (this.inverseSelection) {
|
||||
return this.totalCount - this.clickedSet.size;
|
||||
}
|
||||
return this.clickedSet.size;
|
||||
}
|
||||
|
||||
public selectAll(): void {
|
||||
this.inverseSelection = true;
|
||||
this.groupSelect = true;
|
||||
this.clickedSet.clear();
|
||||
}
|
||||
|
||||
public deSelectAll(): void {
|
||||
this.inverseSelection = false;
|
||||
this.groupSelect = false;
|
||||
this.clickedSet.clear();
|
||||
}
|
||||
|
||||
public isItemSelected(targetId: string): boolean {
|
||||
return (this.inverseSelection != this.clickedSet.has(targetId));
|
||||
}
|
||||
|
||||
public inSelectAllMode(): boolean {
|
||||
return this.inverseSelection && (this.clickedSet.size == 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the select all status of the entry, depending on the total deselection status of the timeline
|
||||
*
|
||||
* @param isInverseMode The total inverse selection status of the timeline. If it is true,
|
||||
* it is global inverse selection and requires reverse operation
|
||||
*/
|
||||
public changeSelectMode(isInverseMode: boolean): void {
|
||||
isInverseMode
|
||||
? (this.getSelectedCount() == 0 ? this.selectAll() : this.deSelectAll())
|
||||
: (this.inSelectAllMode() ? this.deSelectAll() : this.selectAll())
|
||||
}
|
||||
|
||||
public getInverseSelection(): boolean {
|
||||
return this.inverseSelection;
|
||||
}
|
||||
}
|
||||
|
||||
export class ItemCoordinate {
|
||||
groupId = -1;
|
||||
subIndex = -1;
|
||||
|
||||
constructor() {
|
||||
}
|
||||
|
||||
public setGroupId(id: number): ItemCoordinate {
|
||||
this.groupId = id;
|
||||
return this;
|
||||
}
|
||||
|
||||
public getGroupId(): number {
|
||||
return this.groupId;
|
||||
}
|
||||
|
||||
public setIndex(index: number): ItemCoordinate {
|
||||
this.subIndex = index;
|
||||
return this;
|
||||
}
|
||||
|
||||
public getIndex(): number {
|
||||
return this.subIndex;
|
||||
}
|
||||
}
|
||||
|
||||
export class SelectManager {
|
||||
mIsSelectedMode = false;
|
||||
clickedSet: Set<string> = new Set();
|
||||
totalCount = 0;
|
||||
inverseSelection = false;
|
||||
inSingleMode = false;
|
||||
isAllSelected = false;
|
||||
mCallbacks = new Map<string, Function>();
|
||||
photoDataImpl: BrowserDataInterface;
|
||||
selectManagerCallback: SelectManagerCallback;
|
||||
albumUri = undefined;
|
||||
deviceId = undefined;
|
||||
|
||||
constructor() {
|
||||
this.selectManagerCallback = new SelectManagerCallback(this);
|
||||
}
|
||||
|
||||
public setTotalCount(count: number): void {
|
||||
this.totalCount = count;
|
||||
this.mCallbacks.has('updateCount') && this.mCallbacks.get('updateCount')(this.getSelectedCount());
|
||||
|
||||
if (this.isAllSelected) {
|
||||
this.isAllSelected = false;
|
||||
this.mCallbacks.has('allSelect') && this.mCallbacks.get('allSelect')(false);
|
||||
}
|
||||
if (this.totalCount == this.getSelectedCount()) {
|
||||
this.isAllSelected = true;
|
||||
this.mCallbacks.has('allSelect') && this.mCallbacks.get('allSelect')(true);
|
||||
}
|
||||
}
|
||||
|
||||
public setPhotoDataImpl(): void {
|
||||
this.photoDataImpl = BrowserDataFactory.getFeature(BrowserDataFactory.TYPE_PHOTO);
|
||||
}
|
||||
|
||||
public setAlbumUri(albumUri): void {
|
||||
this.albumUri = albumUri;
|
||||
}
|
||||
|
||||
public setDeviceId(deviceId: string): void {
|
||||
this.deviceId = deviceId;
|
||||
}
|
||||
|
||||
public registerCallback(name: string, cb: Function): void {
|
||||
this.mCallbacks.set(name, cb);
|
||||
}
|
||||
|
||||
public unregisterCallback(name: string): void {
|
||||
this.mCallbacks.delete(name);
|
||||
}
|
||||
|
||||
public emitCallback(name: string, argument: unknown[]): void {
|
||||
this.mCallbacks.has(name) && this.mCallbacks.get(name).apply(this, argument);
|
||||
}
|
||||
|
||||
public toggle(targetId: string, isSelected: boolean, targetIndex?: number): boolean {
|
||||
Log.info(TAG, `toggle ${targetId} ${isSelected} ${targetIndex}`);
|
||||
if (targetId == undefined) {
|
||||
return true;
|
||||
}
|
||||
if (isSelected == (!this.inverseSelection)) {
|
||||
this.clickedSet.add(targetId);
|
||||
Log.info(TAG, `add targetID ${targetId}`);
|
||||
} else {
|
||||
this.clickedSet.delete(targetId);
|
||||
}
|
||||
if (this.totalCount == this.getSelectedCount()) {
|
||||
this.isAllSelected = true;
|
||||
this.mCallbacks.has('allSelect') && this.mCallbacks.get('allSelect')(true);
|
||||
} else {
|
||||
this.isAllSelected = false;
|
||||
this.mCallbacks.has('allSelect') && this.mCallbacks.get('allSelect')(false);
|
||||
}
|
||||
this.mCallbacks.has('updateCount') && this.mCallbacks.get('updateCount')(this.getSelectedCount());
|
||||
if (targetIndex !== undefined) {
|
||||
this.mCallbacks.has('select') && this.mCallbacks.get('select')(targetIndex);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public selectAllWithoutNotify(reverseSelection: boolean, shouldCallSelectALl: boolean): void {
|
||||
if (reverseSelection) {
|
||||
this.inverseSelection = true;
|
||||
this.clickedSet.clear();
|
||||
this.isAllSelected = true;
|
||||
} else {
|
||||
this.isAllSelected = true;
|
||||
}
|
||||
AppStorage.SetOrCreate('focusUpdate', true);
|
||||
if (shouldCallSelectALl) {
|
||||
this.mCallbacks.has('allSelect') && this.mCallbacks.get('allSelect')(true);
|
||||
}
|
||||
this.mCallbacks.has('updateCount') && this.mCallbacks.get('updateCount')(this.getSelectedCount());
|
||||
}
|
||||
|
||||
public selectAll(reverseSelection: boolean): void {
|
||||
this.selectAllWithoutNotify(reverseSelection, true);
|
||||
}
|
||||
|
||||
public deSelectAll(): void {
|
||||
this.inverseSelection = false;
|
||||
this.isAllSelected = false;
|
||||
this.clickedSet.clear();
|
||||
AppStorage.SetOrCreate('focusUpdate', true);
|
||||
this.mCallbacks.has('allSelect') && this.mCallbacks.get('allSelect')(false);
|
||||
this.mCallbacks.has('updateCount') && this.mCallbacks.get('updateCount')(this.getSelectedCount());
|
||||
}
|
||||
|
||||
public isItemSelected(targetId: string, index?: number): boolean {
|
||||
Log.info(TAG, `isItemSelected ${targetId}, ${index}`);
|
||||
return (this.inverseSelection != this.clickedSet.has(targetId));
|
||||
}
|
||||
|
||||
public getSelectedCount(): number {
|
||||
return (this.inverseSelection) ? this.totalCount - this.clickedSet.size : this.clickedSet.size;
|
||||
}
|
||||
|
||||
public onModeChange(newMode: boolean): void {
|
||||
if (newMode) {
|
||||
this.mIsSelectedMode = true;
|
||||
} else {
|
||||
this.mIsSelectedMode = false;
|
||||
this.inverseSelection = false;
|
||||
this.isAllSelected = false;
|
||||
this.clickedSet.clear();
|
||||
AppStorage.SetOrCreate('focusUpdate', true);
|
||||
this.mCallbacks.has('allSelect') && this.mCallbacks.get('allSelect')(false);
|
||||
this.mCallbacks.has('updateCount') && this.mCallbacks.get('updateCount')(this.getSelectedCount());
|
||||
}
|
||||
}
|
||||
|
||||
public getSelection(callback: AsyncCallback<string[]>): void {
|
||||
if (this.inverseSelection) {
|
||||
this.selectManagerCallback.setSubCallback(callback);
|
||||
this.photoDataImpl.getData(this.selectManagerCallback, {
|
||||
albumUri: this.albumUri
|
||||
});
|
||||
} else {
|
||||
let result = [];
|
||||
result = Array.from(this.clickedSet);
|
||||
callback.callback(result);
|
||||
}
|
||||
}
|
||||
|
||||
public getDeleteSelection(callback: AsyncCallback<string[]>): void {
|
||||
if (this.inverseSelection) {
|
||||
this.selectManagerCallback.setSubCallback(callback);
|
||||
this.photoDataImpl.getData(this.selectManagerCallback, {
|
||||
albumUri: this.albumUri
|
||||
});
|
||||
} else {
|
||||
let result = [];
|
||||
result = Array.from(this.clickedSet);
|
||||
callback.callback(result);
|
||||
}
|
||||
}
|
||||
|
||||
public async getSelectedItems(callback: Function): Promise<void> {
|
||||
let result = new Array<MediaItem>();
|
||||
Log.info(TAG, 'getSelectedItems');
|
||||
await this.getItems(this.photoDataImpl, 0, this.totalCount, (temp: MediaItem[]) => {
|
||||
temp.forEach((item) => {
|
||||
if (this.inverseSelection) {
|
||||
Log.info(TAG, 'getSelectedItems inverseSelection');
|
||||
if (item && !this.clickedSet.has(item.uri)) {
|
||||
result.push(item);
|
||||
}
|
||||
} else {
|
||||
if (this.clickedSet.has(item.uri)) {
|
||||
result.push(item);
|
||||
}
|
||||
}
|
||||
})
|
||||
Log.info(TAG, `enter callback result ${result.length}`);
|
||||
callback(result);
|
||||
})
|
||||
}
|
||||
|
||||
public handleSelection(mediaItems: MediaItem[], callback: AsyncCallback<string[]>): void {
|
||||
let result = [];
|
||||
mediaItems.forEach((mediaItem) => {
|
||||
if (mediaItem && !this.clickedSet.has(mediaItem.uri)) {
|
||||
result.push(mediaItem.uri);
|
||||
}
|
||||
})
|
||||
callback.callback(result);
|
||||
}
|
||||
|
||||
public async getItems(photoDataImpl: BrowserDataInterface,
|
||||
start: number, count: number, callbackFunc: Function): Promise<void> {
|
||||
Log.info(TAG, `getItems start: ${start} count: ${count}`);
|
||||
let cb: AsyncCallback<MediaItem[]> = {
|
||||
callback: (t: MediaItem[]) => {
|
||||
//注意命名不要冲突
|
||||
callbackFunc(t);
|
||||
}
|
||||
}
|
||||
photoDataImpl.getData(cb, { albumUri: this.albumUri, start: start, count: count });
|
||||
}
|
||||
|
||||
public getClassName(): string {
|
||||
return 'SelectManager';
|
||||
}
|
||||
}
|
||||
|
||||
class SelectManagerCallback implements AsyncCallback<MediaItem[]> {
|
||||
source: SelectManager;
|
||||
subCallback: AsyncCallback<string[]>;
|
||||
|
||||
constructor(source: SelectManager) {
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
public setSubCallback(cb: AsyncCallback<string[]>): void {
|
||||
this.subCallback = cb;
|
||||
}
|
||||
|
||||
public callback(mediaSetList: MediaItem[]): void {
|
||||
this.source.handleSelection(mediaSetList, this.subCallback);
|
||||
}
|
||||
}
|
||||
|
||||
export class ThirdSelectManager extends SelectManager {
|
||||
type: string;
|
||||
isMultiPick: boolean;
|
||||
selectedMap: Map<string, MediaItem> = new Map();
|
||||
getMediaItemFunc: Function;
|
||||
indexMap: Map<MediaItem, number> = new Map();
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
public setGetMediaItemFunc(func: Function): void {
|
||||
this.getMediaItemFunc = func;
|
||||
}
|
||||
|
||||
public setType(type: string): void {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public getType(): string {
|
||||
return this.type;
|
||||
}
|
||||
|
||||
public setIsMultiPick(isMultiPick: boolean): void {
|
||||
this.isMultiPick = isMultiPick;
|
||||
}
|
||||
|
||||
public getIsMultiPick(): boolean {
|
||||
return this.isMultiPick;
|
||||
}
|
||||
|
||||
public getSelectedSet(): Set<string> {
|
||||
return super.clickedSet;
|
||||
}
|
||||
|
||||
public toggle(targetId: string, isSelected: boolean, targetIndex?: number): boolean {
|
||||
if (this.getMediaItemFunc) {
|
||||
let containsUri = this.selectedMap.has(targetId);
|
||||
if (isSelected && !containsUri) {
|
||||
this.selectedMap.set(targetId, this.getMediaItemFunc(targetId));
|
||||
this.indexMap.set(this.getMediaItemFunc(targetId), targetIndex);
|
||||
}
|
||||
if (!isSelected && containsUri) {
|
||||
this.selectedMap.delete(targetId);
|
||||
this.indexMap.delete(this.getMediaItemFunc(targetId));
|
||||
}
|
||||
}
|
||||
return super.toggle(targetId, isSelected, targetIndex);
|
||||
}
|
||||
|
||||
public deSelectAll(): void {
|
||||
this.selectedMap.clear();
|
||||
this.indexMap.clear();
|
||||
super.deSelectAll();
|
||||
}
|
||||
|
||||
public getSelectItemIndex(item: MediaItem): number {
|
||||
let index = 0;
|
||||
for (let selectItem of this.selectedMap.values()) {
|
||||
if (item === selectItem) {
|
||||
return index;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
return Constants.INVALID;
|
||||
}
|
||||
|
||||
public getSelectItemDataSourceIndex(item: MediaItem): number {
|
||||
return this.indexMap.get(item) ? this.indexMap.get(item) : Constants.INVALID;
|
||||
}
|
||||
|
||||
public getSelectItems(): Array<MediaItem> {
|
||||
let itemArray = new Array<MediaItem>();
|
||||
if (this.selectedMap.size === 0) {
|
||||
return itemArray;
|
||||
}
|
||||
for (let item of this.selectedMap.values()) {
|
||||
itemArray.push(item);
|
||||
}
|
||||
return itemArray;
|
||||
}
|
||||
|
||||
public getClassName(): string {
|
||||
return 'ThirdSelectManager';
|
||||
}
|
||||
}
|
||||
|
||||
export class TimelineSelectManager extends SelectManager {
|
||||
mGroupData: TimelineData[] = [];
|
||||
mSelectionEntryArray: BucketSelectionEntry[] = [];
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
public selectAll(reverseSelection: boolean): void {
|
||||
Log.info(TAG, `selectAll ${reverseSelection}`);
|
||||
if (reverseSelection) {
|
||||
this.inverseSelection = true;
|
||||
this.clearEntryArray();
|
||||
this.isAllSelected = true;
|
||||
} else {
|
||||
this.isAllSelected = true;
|
||||
}
|
||||
AppStorage.SetOrCreate('focusUpdate', true);
|
||||
this.mCallbacks.has('updateGroupCount') && this.mCallbacks.get('updateGroupCount')();
|
||||
this.mCallbacks.has('allSelect') && this.mCallbacks.get('allSelect')(true);
|
||||
this.mCallbacks.has('updateCount') && this.mCallbacks.get('updateCount')(this.getSelectedCount());
|
||||
}
|
||||
|
||||
public deSelectAll(): void {
|
||||
this.inverseSelection = false;
|
||||
this.isAllSelected = false;
|
||||
this.clearEntryArray();
|
||||
AppStorage.SetOrCreate('focusUpdate', true);
|
||||
this.mCallbacks.has('updateGroupCount') && this.mCallbacks.get('updateGroupCount')();
|
||||
this.mCallbacks.has('allSelect') && this.mCallbacks.get('allSelect')(false);
|
||||
this.mCallbacks.has('updateCount') && this.mCallbacks.get('updateCount')(this.getSelectedCount());
|
||||
}
|
||||
|
||||
public toggle(targetId: string, isSelected: boolean, targetIndex: number): boolean {
|
||||
Log.info(TAG, `toggleTimeline ${targetIndex} id: ${targetId} ${isSelected}`);
|
||||
let itemCoordinate = this.getCoordinateFromPosition(targetIndex);
|
||||
let entry = this.getGroupEntry(itemCoordinate);
|
||||
this.toggleClickSet(entry, targetId, isSelected);
|
||||
let entrySelectedCount = entry.getSelectedCount();
|
||||
Log.info(TAG, `check all selected ${entrySelectedCount} ${entry.getTotalCount()}`);
|
||||
|
||||
if (entrySelectedCount == entry.getTotalCount()) {
|
||||
Log.info(TAG, 'group selectAll');
|
||||
entry.selectAll();
|
||||
}
|
||||
|
||||
this.mCallbacks.has('updateGroupCount') && this.mCallbacks.get('updateGroupCount')();
|
||||
|
||||
if (this.isAllSelected && (entrySelectedCount < entry.getTotalCount())) {
|
||||
this.isAllSelected = false;
|
||||
this.mCallbacks.has('updateCount') && this.mCallbacks.get('updateCount')(this.getSelectedCount());
|
||||
}
|
||||
|
||||
if (this.getSelectedCount() == this.totalCount) {
|
||||
this.isAllSelected = true;
|
||||
this.mCallbacks.has('allSelect') && this.mCallbacks.get('allSelect')(true);
|
||||
this.mCallbacks.has('updateCount') && this.mCallbacks.get('updateCount')(this.getSelectedCount());
|
||||
} else {
|
||||
this.isAllSelected = false;
|
||||
this.mCallbacks.has('allSelect') && this.mCallbacks.get('allSelect')(false);
|
||||
this.mCallbacks.has('updateCount') && this.mCallbacks.get('updateCount')(this.getSelectedCount());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public toggleGroup(itemCoordinate: ItemCoordinate): boolean {
|
||||
Log.info(TAG, `check toggleGroup: ${itemCoordinate.getGroupId()}`);
|
||||
if (this.inverseSelection) {
|
||||
let entry = this.mSelectionEntryArray[itemCoordinate.getGroupId()];
|
||||
if (entry == undefined) {
|
||||
entry = this.getGroupEntry(itemCoordinate);
|
||||
entry.selectAll();
|
||||
} else {
|
||||
entry.changeSelectMode(true);
|
||||
}
|
||||
} else {
|
||||
let entry = this.getGroupEntry(itemCoordinate);
|
||||
entry.changeSelectMode(false);
|
||||
}
|
||||
|
||||
let count = this.getSelectedCount();
|
||||
if (count == this.totalCount) {
|
||||
this.selectAll(false);
|
||||
}
|
||||
this.mCallbacks.has('updateGroupCount') && this.mCallbacks.get('updateGroupCount')();
|
||||
this.mCallbacks.has('updateCount') && this.mCallbacks.get('updateCount')(this.getSelectedCount());
|
||||
if (this.getSelectedCount() == this.totalCount) {
|
||||
this.isAllSelected = true;
|
||||
this.mCallbacks.has('allSelect') && this.mCallbacks.get('allSelect')(true);
|
||||
} else {
|
||||
this.isAllSelected = false;
|
||||
this.mCallbacks.has('allSelect') && this.mCallbacks.get('allSelect')(false);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public getTitleCoordinate(position: number): ItemCoordinate {
|
||||
return new ItemCoordinate().setGroupId(position).setIndex(-1);
|
||||
}
|
||||
|
||||
public getSelectedCount(): number {
|
||||
let count = 0;
|
||||
this.mSelectionEntryArray.forEach((item) => {
|
||||
count += item ? item.getSelectedCount() : 0;
|
||||
})
|
||||
if (this.inverseSelection) {
|
||||
Log.info(TAG, `inverseSelection totalCount: ${this.totalCount - count}`);
|
||||
return this.totalCount - count;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
public onModeChange(newMode: boolean): void {
|
||||
if (newMode) {
|
||||
this.mIsSelectedMode = true;
|
||||
} else {
|
||||
this.mIsSelectedMode = false;
|
||||
this.inverseSelection = false;
|
||||
this.isAllSelected = false;
|
||||
this.clearEntryArray();
|
||||
AppStorage.SetOrCreate('focusUpdate', true);
|
||||
this.mCallbacks.has('updateGroupCount') && this.mCallbacks.get('updateGroupCount')();
|
||||
this.mCallbacks.has('allSelect') && this.mCallbacks.get('allSelect')(false);
|
||||
this.mCallbacks.has('updateCount') && this.mCallbacks.get('updateCount')(this.getSelectedCount());
|
||||
}
|
||||
}
|
||||
|
||||
public isItemSelected(targetId: string, index: number): boolean {
|
||||
let itemCoordinate = this.getCoordinateFromPosition(index);
|
||||
let entry = this.mSelectionEntryArray[itemCoordinate.getGroupId()];
|
||||
if (this.inverseSelection) {
|
||||
return (entry == undefined) || (!entry.isItemSelected(targetId));
|
||||
} else {
|
||||
return (entry != undefined) && (entry.isItemSelected(targetId));
|
||||
}
|
||||
}
|
||||
|
||||
public isGroupSelected(index: number): boolean {
|
||||
let entry = this.mSelectionEntryArray[index];
|
||||
if (this.inverseSelection) {
|
||||
return entry == null || entry.getSelectedCount() == 0;
|
||||
} else {
|
||||
return (entry != null) && (entry.inSelectAllMode());
|
||||
}
|
||||
}
|
||||
|
||||
public setGroupData(groupData: TimelineData[]): void {
|
||||
if (groupData == undefined) {
|
||||
return;
|
||||
}
|
||||
this.mGroupData = groupData;
|
||||
}
|
||||
|
||||
public updateGroupData(groupData: TimelineData[]): void {
|
||||
if (groupData == undefined) {
|
||||
return;
|
||||
}
|
||||
this.mGroupData = groupData;
|
||||
this.mSelectionEntryArray.forEach((entry: BucketSelectionEntry) => {
|
||||
if (entry != undefined && (entry.getGroupId() < this.mGroupData.length)) {
|
||||
entry.setTotalCount(this.mGroupData[entry.getGroupId()].count);
|
||||
}
|
||||
})
|
||||
this.mCallbacks.has('updateCount') && this.mCallbacks.get('updateCount')(this.getSelectedCount());
|
||||
}
|
||||
|
||||
public async getSelection(callback: AsyncCallback<string[]>): Promise<void> {
|
||||
let result = new Array<string>();
|
||||
let start = 0;
|
||||
let doneCount = 0;
|
||||
if (this.inverseSelection) {
|
||||
for (let i = 0; i < this.mGroupData.length; i++) {
|
||||
if (this.mSelectionEntryArray[i]) {
|
||||
//全选模式下用户操作过的日期下的items根据用户选择反选
|
||||
await this.getInverseSelectedFromEntry(this.mSelectionEntryArray[i],
|
||||
start, this.mGroupData[i].count, (temp: string[]) => {
|
||||
result = result.concat(temp);
|
||||
Log.info(TAG, `getInverseSelectedFromEntry result ${result.length}`);
|
||||
doneCount++;
|
||||
this.checkIsGetSelectionFinish(doneCount, result, callback);
|
||||
});
|
||||
} else {
|
||||
//全选模式下用户未操作过的日期下的items全量选中
|
||||
await this.getItems(this.photoDataImpl, start, this.mGroupData[i].count, (temp: MediaItem[]) => {
|
||||
temp.forEach((item) => {
|
||||
result.push(item.uri);
|
||||
});
|
||||
Log.info(TAG, `getInverseGroupItems result ${result.length}`);
|
||||
doneCount++;
|
||||
this.checkIsGetSelectionFinish(doneCount, result, callback);
|
||||
});
|
||||
}
|
||||
start += this.mGroupData[i].count;
|
||||
}
|
||||
} else {
|
||||
for (let i = 0; i < this.mGroupData.length; i++) {
|
||||
if (this.mSelectionEntryArray[i]) {
|
||||
//正选模式下根据遍历日期分组用户选择正常取item
|
||||
await this.getSelectedFromEntry(this.mSelectionEntryArray[i],
|
||||
start, this.mGroupData[i].count, (temp: string[]) => {
|
||||
Log.info(TAG, `getSelectedFromEntry result ${result.length}`);
|
||||
result = result.concat(temp);
|
||||
doneCount++;
|
||||
this.checkIsGetSelectionFinish(doneCount, result, callback);
|
||||
});
|
||||
} else {
|
||||
//正选模式下未操作过的分组直接跳过
|
||||
doneCount++;
|
||||
this.checkIsGetSelectionFinish(doneCount, result, callback);
|
||||
}
|
||||
start += this.mGroupData[i].count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async getSelectedItems(callback: Function): Promise<void> {
|
||||
Log.info(TAG, 'getSelectedItems');
|
||||
let result = new Array<MediaItem>();
|
||||
let start = 0;
|
||||
let doneCount = 0;
|
||||
if (this.inverseSelection) {
|
||||
Log.info(TAG, 'getSelectedItems: mode is inverseSelection');
|
||||
for (let i = 0; i < this.mGroupData.length; i++) {
|
||||
if (this.mSelectionEntryArray[i]) {
|
||||
if (this.mSelectionEntryArray[i].getInverseSelection()) {
|
||||
await this.getItems(this.photoDataImpl, start, this.mGroupData[i].count, (temp: MediaItem[]) => {
|
||||
temp.forEach((item) => {
|
||||
if (this.mSelectionEntryArray[i].getClickSet().has(item.uri)) {
|
||||
Log.debug(TAG, 'push one item');
|
||||
result.push(item);
|
||||
}
|
||||
});
|
||||
doneCount++;
|
||||
this.checkIsGetSelectionItemFinish(doneCount, result, callback);
|
||||
});
|
||||
} else {
|
||||
await this.getItems(this.photoDataImpl, start, this.mGroupData[i].count, (temp: MediaItem[]) => {
|
||||
temp.forEach((item) => {
|
||||
if (!this.mSelectionEntryArray[i].getClickSet().has(item.uri)) {
|
||||
Log.debug(TAG, 'push one inverse item');
|
||||
result.push(item);
|
||||
}
|
||||
});
|
||||
doneCount++;
|
||||
this.checkIsGetSelectionItemFinish(doneCount, result, callback);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
await this.getItems(this.photoDataImpl, start, this.mGroupData[i].count, (temp: MediaItem[]) => {
|
||||
temp.forEach((item) => {
|
||||
result.push(item);
|
||||
});
|
||||
doneCount++;
|
||||
this.checkIsGetSelectionItemFinish(doneCount, result, callback);
|
||||
});
|
||||
}
|
||||
start += this.mGroupData[i].count;
|
||||
}
|
||||
} else {
|
||||
Log.info(TAG, 'getSelectedItems: mode is not inverseSelection');
|
||||
for (let i = 0; i < this.mGroupData.length; i++) {
|
||||
if (this.mSelectionEntryArray[i]) {
|
||||
await this.getItems(this.photoDataImpl, start, this.mGroupData[i].count, (temp: MediaItem[]) => {
|
||||
const entry = this.mSelectionEntryArray[i];
|
||||
temp.forEach((item) => {
|
||||
if (!entry.getInverseSelection()) {
|
||||
if (entry.getClickSet().has(item.uri)) {
|
||||
Log.debug(TAG, 'push one item');
|
||||
result.push(item);
|
||||
}
|
||||
} else if (!entry.getClickSet().has(item.uri)) {
|
||||
Log.debug(TAG, 'push one inverse item');
|
||||
result.push(item);
|
||||
}
|
||||
});
|
||||
doneCount++;
|
||||
this.checkIsGetSelectionItemFinish(doneCount, result, callback);
|
||||
});
|
||||
} else {
|
||||
doneCount++;
|
||||
this.checkIsGetSelectionItemFinish(doneCount, result, callback);
|
||||
}
|
||||
start += this.mGroupData[i].count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private toggleClickSet(entry: BucketSelectionEntry, targetId: string, isSelected: boolean): void {
|
||||
Log.info(TAG, `toggleClickSet: ${targetId} + ${isSelected}`);
|
||||
if (isSelected == (!this.inverseSelection)) {
|
||||
this.toggleEntryItem(entry, targetId, true);
|
||||
} else {
|
||||
this.toggleEntryItem(entry, targetId, false);
|
||||
}
|
||||
}
|
||||
|
||||
private toggleEntryItem(entry: BucketSelectionEntry, targetId: string, isSelected: boolean): void {
|
||||
Log.info(TAG, `toggleEntryItem ${targetId} ${isSelected}`);
|
||||
let clickSet = entry.getClickSet();
|
||||
if (isSelected != entry.getInverseSelection()) {
|
||||
clickSet.add(targetId);
|
||||
} else {
|
||||
clickSet.delete(targetId);
|
||||
}
|
||||
}
|
||||
|
||||
private getCoordinateFromPosition(position: number): ItemCoordinate {
|
||||
let index = 0;
|
||||
let group = 0;
|
||||
let totalSize = this.mGroupData.length;
|
||||
for (; group < totalSize; group++) {
|
||||
let count = this.mGroupData[group].count;
|
||||
index += (count + 1);
|
||||
if (index > position) {
|
||||
index -= count;
|
||||
group = Math.max(0, group);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return new ItemCoordinate().setGroupId(group).setIndex(position - index);
|
||||
}
|
||||
|
||||
private getGroupEntry(itemCoordinate: ItemCoordinate): BucketSelectionEntry {
|
||||
let entry = this.mSelectionEntryArray[itemCoordinate.groupId];
|
||||
if (entry == undefined) {
|
||||
entry = new BucketSelectionEntry();
|
||||
entry.setGroupId(itemCoordinate.groupId);
|
||||
if (itemCoordinate.groupId >= 0 && itemCoordinate.groupId < this.mGroupData.length) {
|
||||
Log.info(TAG, `entry.setTotalCount ${this.mGroupData[itemCoordinate.groupId].count}`);
|
||||
entry.setTotalCount(this.mGroupData[itemCoordinate.groupId].count);
|
||||
}
|
||||
Log.info(TAG, `getGroupEntry mSelectionEntryArray ${itemCoordinate.groupId} entry: ${entry}`);
|
||||
this.mSelectionEntryArray[itemCoordinate.groupId] = entry;
|
||||
}
|
||||
return entry;
|
||||
}
|
||||
|
||||
private clearEntryArray(): void {
|
||||
Log.info(TAG, 'clearEntryArray');
|
||||
this.mSelectionEntryArray.length = 0;
|
||||
}
|
||||
|
||||
private checkIsGetSelectionFinish(doneCount: number, result: string[], callback: AsyncCallback<string[]>): void {
|
||||
if (this.mGroupData.length == doneCount) {
|
||||
Log.info(TAG, `getSelection result ${result.length}`);
|
||||
callback.callback(result);
|
||||
}
|
||||
}
|
||||
|
||||
private checkIsGetSelectionItemFinish(doneCount: number, result: MediaItem[], callback: Function): void {
|
||||
if (this.mGroupData.length == doneCount) {
|
||||
Log.info(TAG, `getSelection result ${result.length}`);
|
||||
callback(result);
|
||||
}
|
||||
}
|
||||
|
||||
private async getSelectedFromEntry(entry: BucketSelectionEntry,
|
||||
start: number, count: number, callback: Function): Promise<void> {
|
||||
Log.info(TAG, `getSelectedFromEntry start: ${start}, count: ${count}`);
|
||||
let result = new Array<string>();
|
||||
if (entry.getInverseSelection()) {
|
||||
await this.getItems(this.photoDataImpl, start, count, (temp: MediaItem[]) => {
|
||||
temp.forEach((item) => {
|
||||
if (!entry.getClickSet().has(item.uri)) {
|
||||
result.push(item.uri);
|
||||
}
|
||||
});
|
||||
callback(result);
|
||||
});
|
||||
} else {
|
||||
Log.info(TAG, 'getSelectedFromEntry not inverse');
|
||||
result = Array.from(entry.getClickSet());
|
||||
callback(result);
|
||||
}
|
||||
}
|
||||
|
||||
private async getInverseSelectedFromEntry(entry: BucketSelectionEntry,
|
||||
start: number, count: number, callback: Function): Promise<void> {
|
||||
Log.info(TAG, `getInverseSelectedFromEntry start: ${start}, count: ${count}`);
|
||||
let result = new Array<string>();
|
||||
if (entry.getInverseSelection()) {
|
||||
result = Array.from(entry.getClickSet());
|
||||
callback(result);
|
||||
} else {
|
||||
Log.info(TAG, 'getInverseSelectedFromEntry not inverse');
|
||||
await this.getItems(this.photoDataImpl, start, count, (temp: MediaItem[]) => {
|
||||
Log.info(TAG, `enter callback temp: ${entry.getClickSet().size}`);
|
||||
temp.forEach((item) => {
|
||||
if (!entry.getClickSet().has(item.uri)) {
|
||||
result.push(item.uri);
|
||||
}
|
||||
});
|
||||
Log.info(TAG, `enter callback result ${result.length}`);
|
||||
callback(result);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class AlbumSetSelectManager extends SelectManager {
|
||||
isDisableRenameClickedSet: Set<string> = new Set();
|
||||
isDisableDeleteClickedSet: Set<string> = new Set();
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
public toolBarStateToggle(targetId: string, isSelected: boolean,
|
||||
isDisableRename: boolean, isDisableDelete: boolean): void {
|
||||
Log.info(TAG, `toolBarStateToggle${targetId}/${isSelected}/${isDisableRename}/${isDisableDelete}`);
|
||||
if (isSelected == (!this.inverseSelection)) {
|
||||
if (isDisableRename) {
|
||||
Log.info(TAG, `add isDisableRename targetID ${targetId}`);
|
||||
this.isDisableRenameClickedSet.add(targetId);
|
||||
}
|
||||
if (isDisableDelete) {
|
||||
Log.info(TAG, `add isDisableDelete targetID ${targetId}`);
|
||||
this.isDisableDeleteClickedSet.add(targetId);
|
||||
}
|
||||
} else {
|
||||
if (isDisableRename) {
|
||||
Log.info(TAG, `delete isDisableRename targetID ${targetId}`);
|
||||
this.isDisableRenameClickedSet.delete(targetId);
|
||||
}
|
||||
if (isDisableDelete) {
|
||||
Log.info(TAG, `delete isDisableDelete targetID ${targetId}`);
|
||||
this.isDisableDeleteClickedSet.delete(targetId);
|
||||
}
|
||||
}
|
||||
|
||||
let isDisableRenameFlag = !(this.isDisableRenameClickedSet.size == 0);
|
||||
let isDisableDeleteFlag = !(this.isDisableDeleteClickedSet.size == 0);
|
||||
this.mCallbacks.has('updateToolBarState') &&
|
||||
this.mCallbacks.get('updateToolBarState')(isDisableRenameFlag, isDisableDeleteFlag);
|
||||
}
|
||||
|
||||
public onModeChange(newMode: boolean): void {
|
||||
super.onModeChange(newMode);
|
||||
if (!newMode) {
|
||||
this.isDisableRenameClickedSet.clear();
|
||||
this.isDisableDeleteClickedSet.clear();
|
||||
}
|
||||
}
|
||||
}
|
@ -12,4 +12,9 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
import {MainPage} from './src/main/ets/components/MainPage/MainPage'
|
||||
|
||||
export enum SelectionState {
|
||||
NONE,
|
||||
SELECTED,
|
||||
NOT_SELECTED,
|
||||
}
|
243
common/src/main/ets/default/model/browser/album/AlbumDataImpl.ts
Normal file
243
common/src/main/ets/default/model/browser/album/AlbumDataImpl.ts
Normal file
@ -0,0 +1,243 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2023 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 { AlbumDefine } from '../AlbumDefine';
|
||||
import { AlbumInfo } from './AlbumInfo';
|
||||
import type { AsyncCallback } from '../../common/AsyncCallback';
|
||||
import { BrowserDataImpl } from '../BrowserDataImpl';
|
||||
import type { Album, FetchOptions } from '../../../access/UserFileManagerAccess';
|
||||
import { UserFileManagerAccess } from '../../../access/UserFileManagerAccess';
|
||||
import { Log } from '../../../utils/Log';
|
||||
import { Constants } from '../../common/Constants';
|
||||
import { MediaItem } from '../photo/MediaItem';
|
||||
|
||||
const TAG: string = 'common_AlbumDataImpl';
|
||||
|
||||
type AlbumInfoEx = {
|
||||
relativePath?: string
|
||||
};
|
||||
|
||||
type QueryAlbumParam = {
|
||||
filterMediaType?: string;
|
||||
uris?: string[]
|
||||
};
|
||||
|
||||
export type InitAlbumParam = {
|
||||
deviceId?: string,
|
||||
deviceName?: string,
|
||||
moreInfo?: boolean
|
||||
};
|
||||
|
||||
export type AlbumSimpleInfo = {
|
||||
uris: string[],
|
||||
count: number,
|
||||
videoCount: number,
|
||||
};
|
||||
|
||||
export class AlbumDataImpl extends BrowserDataImpl {
|
||||
private moreInfo: boolean = false;
|
||||
|
||||
constructor(param: InitAlbumParam) {
|
||||
super();
|
||||
|
||||
if (param && param.moreInfo) {
|
||||
this.moreInfo = param.moreInfo
|
||||
}
|
||||
}
|
||||
|
||||
getDataByUri(uri: unknown) {
|
||||
}
|
||||
|
||||
getData(callback: AsyncCallback<unknown>, param: QueryAlbumParam): void {
|
||||
Log.info(TAG, 'load data getData start : ' + param);
|
||||
if (param == null) {
|
||||
this.buildAlbums(callback);
|
||||
} else if (param?.filterMediaType != undefined) {
|
||||
this.buildAlbums(callback, param.filterMediaType);
|
||||
} else {
|
||||
// 删除相册时,计算图片视频数量
|
||||
this.genAlbumsInfo(callback, param.uris);
|
||||
}
|
||||
}
|
||||
|
||||
async getDataByName(name: string, albumUri?: string): Promise<Album> {
|
||||
let albums = await UserFileManagerAccess.getInstance().getUserAlbums(AlbumDefine.getAlbumFetchOptByName(name));
|
||||
if (albums && albums.length > 0) {
|
||||
let opt: FetchOptions = AlbumDefine.getFileFetchOpt();
|
||||
let fileResult = await albums[0].getPhotoAssets(opt);
|
||||
if (fileResult == null || fileResult == undefined) {
|
||||
Log.warn(TAG, `not valid fileResult`);
|
||||
return null;
|
||||
}
|
||||
let count = fileResult.getCount();
|
||||
fileResult.close();
|
||||
if (count <= 0) {
|
||||
Log.warn(TAG, `Not valid album Name: ${albums[0].albumName}, URI: ${albums[0].albumUri}`);
|
||||
return null;
|
||||
}
|
||||
return albums[0];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
getDataCount(callback: AsyncCallback<unknown>, albumInfo: AlbumInfo): void {
|
||||
}
|
||||
|
||||
getDataIndexByUri(callback: AsyncCallback<unknown>, param: QueryAlbumParam, uri: string): void {
|
||||
}
|
||||
|
||||
getDataIndexById(callback: AsyncCallback<unknown>, param: QueryAlbumParam, id: number): void {
|
||||
}
|
||||
|
||||
private async genAlbumsInfo(cb: AsyncCallback<AlbumSimpleInfo>, uris: string[]): Promise<void> {
|
||||
Log.info(TAG, `genAlbumsInfo uris: ${JSON.stringify(uris)}`);
|
||||
Log.info(TAG, 'load data genAlbumsInfo start');
|
||||
|
||||
let res = {
|
||||
uris: [],
|
||||
count: 0,
|
||||
videoCount: 0,
|
||||
};
|
||||
|
||||
for (let uri of uris) {
|
||||
let objects = await super.getItems(uri, Constants.INVALID, Constants.INVALID);
|
||||
Log.info(TAG, `get album objects: uri: ${uri} length: ${objects.length}`);
|
||||
|
||||
res.count += objects.length;
|
||||
for (let item of objects) {
|
||||
if (item.fileType === UserFileManagerAccess.MEDIA_TYPE_VIDEO) {
|
||||
res.videoCount++;
|
||||
}
|
||||
res.uris.push(item.uri);
|
||||
}
|
||||
}
|
||||
|
||||
Log.info(TAG, `genAlbumsInfo done`);
|
||||
cb.callback(res);
|
||||
}
|
||||
|
||||
private async buildAlbums(callback: AsyncCallback<AlbumInfo[]>, filterMediaType?: string) {
|
||||
Log.debug(TAG, `buildAlbums`);
|
||||
let sourceData = new Array<AlbumInfo>();
|
||||
await this.getSystemAlbumsInfo(sourceData, filterMediaType);
|
||||
await this.getUserAlbumsInfo(sourceData, filterMediaType);
|
||||
await this.getTrashAlbumInfo(sourceData, filterMediaType);
|
||||
callback.callback(sourceData);
|
||||
}
|
||||
|
||||
private async getUserAlbumsInfo(albumArray: Array<AlbumInfo>, filterMediaType?: string): Promise<void> {
|
||||
Log.debug(TAG, 'getUserAlbumsInfo');
|
||||
|
||||
let albums: Album[] = await UserFileManagerAccess.getInstance().getUserAlbums();
|
||||
Log.debug(TAG, `getUserAlbumsInfo albums is : ${albums}`);
|
||||
if (albums) {
|
||||
for (let album of albums) {
|
||||
let albumInfo: AlbumInfo = new AlbumInfo(album);
|
||||
let albumName: string = await UserFileManagerAccess.getInstance().getAlbumName(album);
|
||||
albumInfo.setAlbumName(albumName);
|
||||
albumInfo.setFilterMediaType(filterMediaType);
|
||||
// 没有相册,设置为第一张
|
||||
if (!album.coverUri) {
|
||||
await UserFileManagerAccess.getInstance().getAlbumFirstObject(album).then((obj) => {
|
||||
if (obj) {
|
||||
let mediaItem = new MediaItem(obj);
|
||||
mediaItem.setThumbnail(this.getThumbnailSafe(obj.uri));
|
||||
albumInfo.setMediaItem(mediaItem);
|
||||
albumInfo.setCoverUri(this.getThumbnailSafe(obj.uri));
|
||||
}
|
||||
});
|
||||
}
|
||||
let count = await this.getItemsCount(album.albumUri);
|
||||
albumInfo.setCount(count); // TODO album.count不为0时,在构造函数里直接获取
|
||||
// 相册的视频数量
|
||||
let videoCount = await this.getItemsCount(album.albumUri, AlbumDefine.FILTER_MEDIA_TYPE_VIDEO);
|
||||
albumInfo.setVideoCount(videoCount);
|
||||
Log.debug(TAG, `getUserAlbumsInfo albumInfo is : ${albumInfo}`);
|
||||
albumArray.push(albumInfo);
|
||||
Log.debug(TAG, `getUserAlbumsInfo albumArray length is : ${albumArray.length}`);
|
||||
}
|
||||
} else {
|
||||
Log.error(TAG, 'Failed getUserAlbumsInfo');
|
||||
}
|
||||
|
||||
Log.debug(TAG, 'getUserAlbumsInfo done');
|
||||
}
|
||||
|
||||
|
||||
private async getSystemAlbumsInfo(albumArray: Array<AlbumInfo>, filterMediaType?: string): Promise<void> {
|
||||
Log.debug(TAG, 'getSystemAlbumsInfo');
|
||||
|
||||
let albums: Album[] = await UserFileManagerAccess.getInstance().getSystemAlbums();
|
||||
Log.debug(TAG, `getSystemAlbumsInfo albums is : ${albums}`);
|
||||
|
||||
if (albums) {
|
||||
for (let album of albums) {
|
||||
Log.info(TAG, `album ${JSON.stringify(album)}`)
|
||||
let albumInfo: AlbumInfo = new AlbumInfo(album);
|
||||
let count = await this.getItemsCount(album.albumUri);
|
||||
// 系统相册为空时不展示
|
||||
if (count === 0) {
|
||||
continue;
|
||||
}
|
||||
albumInfo.setCount(count); // TODO album.count不为0时,在构造函数里直接获取
|
||||
// 相册的视频数量
|
||||
let videoCount = await this.getItemsCount(album.albumUri, AlbumDefine.FILTER_MEDIA_TYPE_VIDEO);
|
||||
albumInfo.setVideoCount(videoCount);
|
||||
let albumName: string = await UserFileManagerAccess.getInstance().getAlbumName(album);
|
||||
albumInfo.setAlbumName(albumName);
|
||||
albumInfo.setFilterMediaType(filterMediaType);
|
||||
if (!album.coverUri) {
|
||||
await UserFileManagerAccess.getInstance().getAlbumFirstObject(album).then((obj) => {
|
||||
if (obj) {
|
||||
let mediaItem = new MediaItem(obj);
|
||||
mediaItem.setThumbnail(this.getThumbnailSafe(obj.uri));
|
||||
albumInfo.setMediaItem(mediaItem);
|
||||
albumInfo.setCoverUri(this.getThumbnailSafe(obj.uri));
|
||||
}
|
||||
});
|
||||
}
|
||||
Log.debug(TAG, `getSystemAlbumsInfo albumInfo is : ${albumInfo}`);
|
||||
albumArray.push(albumInfo);
|
||||
Log.debug(TAG, `getSystemAlbumsInfo albumArray length is : ${albumArray.length}`);
|
||||
}
|
||||
} else {
|
||||
Log.error(TAG, 'Failed getSystemAlbumsInfo');
|
||||
}
|
||||
|
||||
Log.debug(TAG, 'getSystemAlbumsInfo done');
|
||||
}
|
||||
|
||||
private async getTrashAlbumInfo(albumArray: Array<AlbumInfo>, filterMediaType?: string): Promise<void> {
|
||||
Log.debug(TAG, 'getTrashAlbumInfo');
|
||||
let album: Album = await UserFileManagerAccess.getInstance().getTrashAlbum();
|
||||
Log.debug(TAG, `getTrashAlbumInfo albums is : ${album}`);
|
||||
let albumInfo: AlbumInfo = new AlbumInfo(album);
|
||||
let count = await this.getItemsCount(album.albumUri);
|
||||
// 系统相册为空时不展示
|
||||
if (count === 0) {
|
||||
Log.warn(TAG, 'getTrashAlbumInfo count is 0');
|
||||
return;
|
||||
}
|
||||
albumInfo.setCount(count);
|
||||
let albumName: string = await UserFileManagerAccess.getInstance().getAlbumName(album);
|
||||
albumInfo.setAlbumName(albumName);
|
||||
albumInfo.setFilterMediaType(filterMediaType);
|
||||
Log.debug(TAG, `getTrashAlbumInfo albumArray albumInfo is : ${albumInfo}`);
|
||||
albumArray.push(albumInfo);
|
||||
Log.debug(TAG, `getTrashAlbumInfo albumArray length is : ${albumArray.length}`);
|
||||
Log.debug(TAG, 'getSystemAlbumsInfo done');
|
||||
}
|
||||
}
|
76
common/src/main/ets/default/model/browser/album/AlbumInfo.ts
Normal file
76
common/src/main/ets/default/model/browser/album/AlbumInfo.ts
Normal file
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2023 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 image from '@ohos.multimedia.image';
|
||||
import media from '@ohos.multimedia.media';
|
||||
import { Album, UserFileManagerAccess } from '../../../access/UserFileManagerAccess';
|
||||
|
||||
import type { MediaItem } from '../photo/MediaItem';
|
||||
|
||||
export class AlbumInfo {
|
||||
uri: string;
|
||||
coverUri: string;
|
||||
albumName: string;
|
||||
count: number;
|
||||
isSystemAlbum: boolean;
|
||||
isTrashAlbum: boolean;
|
||||
isFavorAlbum: boolean;
|
||||
isVideoAlbum: boolean;
|
||||
isScreenShotAlbum: boolean;
|
||||
filterMediaType: string;
|
||||
dateModified: number;
|
||||
videoCount: number;
|
||||
mediaItem: MediaItem;
|
||||
|
||||
constructor(album: Album) {
|
||||
if (album) {
|
||||
this.uri = album.albumUri;
|
||||
this.coverUri = album.coverUri;
|
||||
this.isSystemAlbum = UserFileManagerAccess.getInstance().isSystemAlbum(album);
|
||||
this.isTrashAlbum = UserFileManagerAccess.getInstance().isTrashAlbum(album);
|
||||
this.isFavorAlbum = UserFileManagerAccess.getInstance().isFavorAlbum(album);
|
||||
this.isVideoAlbum = UserFileManagerAccess.getInstance().isVideoAlbum(album);
|
||||
this.count = album.count; // TODO 相册count都是0
|
||||
this.dateModified = album.dateModified;
|
||||
}
|
||||
}
|
||||
|
||||
setMediaItem(mediaItem: MediaItem) {
|
||||
this.mediaItem = mediaItem;
|
||||
}
|
||||
|
||||
setAlbumName(albumName: string): void {
|
||||
this.albumName = albumName;
|
||||
}
|
||||
|
||||
setCount(count: number): void {
|
||||
this.count = count;
|
||||
}
|
||||
|
||||
setVideoCount(count: number): void {
|
||||
this.videoCount = count;
|
||||
}
|
||||
|
||||
setFilterMediaType(filterMediaType: string): void {
|
||||
this.filterMediaType = filterMediaType;
|
||||
}
|
||||
|
||||
setCoverUri(coverUri: string): void {
|
||||
this.coverUri = coverUri;
|
||||
}
|
||||
|
||||
getHashCode(): string {
|
||||
return `${this.uri}_${this.coverUri}_${this.count}_${this.albumName}`;
|
||||
}
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2023 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 type { BrowserOperationInterface } from '../../../interface/BrowserOperationInterface';
|
||||
import { Log } from '../../../utils/Log';
|
||||
import type { Album, FileAsset } from '../../../access/UserFileManagerAccess';
|
||||
|
||||
const TAG: string = 'common_AlbumOperationImpl';
|
||||
|
||||
export class AlbumOperationImpl implements BrowserOperationInterface {
|
||||
setName(album: Album, name: string): void {
|
||||
album.albumName = name;
|
||||
}
|
||||
|
||||
async change(album: Album): Promise<void> {
|
||||
await album.commitModify();
|
||||
}
|
||||
|
||||
favor(uri: string, isFavor: boolean): void {
|
||||
}
|
||||
|
||||
delete(uri: string): void {
|
||||
}
|
||||
|
||||
deleteTrash(assets: Array<FileAsset>): void {
|
||||
|
||||
}
|
||||
|
||||
recoverFromTrash(assets: Array<FileAsset>): void {
|
||||
|
||||
}
|
||||
|
||||
copy(source: unknown, target: unknown): void {
|
||||
}
|
||||
|
||||
trash(uri: string, isTrash: boolean): void {
|
||||
}
|
||||
|
||||
remove(uris: Array<string>, albumUri: string): void {
|
||||
}
|
||||
|
||||
create(param: unknown): void {
|
||||
}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* 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 { AlbumSetDataSource } from './AlbumSetDataSource';
|
||||
import type { AsyncCallback } from '../../common/AsyncCallback';
|
||||
import { TraceControllerUtils } from '../../../utils/TraceControllerUtils';
|
||||
import { AlbumInfo } from './AlbumInfo';
|
||||
|
||||
export class AlbumSetCallback implements AsyncCallback<AlbumInfo[]> {
|
||||
source: AlbumSetDataSource;
|
||||
requestTime: number;
|
||||
|
||||
constructor(source: AlbumSetDataSource) {
|
||||
this.source = source;
|
||||
this.requestTime = Date.now();
|
||||
TraceControllerUtils.startTraceWithTaskId('getAlbumSetData', this.requestTime);
|
||||
}
|
||||
|
||||
callback(mediaSetList: AlbumInfo[]) {
|
||||
TraceControllerUtils.finishTraceWithTaskId('getAlbumSetData', this.requestTime);
|
||||
this.source.updateAlbumSetData(this.requestTime, mediaSetList);
|
||||
}
|
||||
}
|
@ -0,0 +1,157 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2023 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 { AlbumSetCallback } from './AlbumSetCallback';
|
||||
import { TraceControllerUtils } from '../../../utils/TraceControllerUtils';
|
||||
import { BrowserDataFactory } from '../../../interface/BrowserDataFactory';
|
||||
import type { BrowserDataInterface } from '../../../interface/BrowserDataInterface';
|
||||
import { BroadCast } from '../../../utils/BroadCast';
|
||||
import { Log } from '../../../utils/Log';
|
||||
import { AlbumInfo } from './AlbumInfo';
|
||||
import { AbsDataSource } from '../AbsDataSource';
|
||||
import { Constants } from '../../common/Constants';
|
||||
import { AlbumSetDataInfo } from '../../common/AlbumSetDataInfo';
|
||||
import type { InitAlbumParam } from './AlbumDataImpl';
|
||||
|
||||
const TAG: string = 'common_AlbumSetDataSource';
|
||||
|
||||
export class AlbumSetDataSource extends AbsDataSource {
|
||||
mediaSetList: AlbumInfo[] = [];
|
||||
albumDataImpl: BrowserDataInterface;
|
||||
isMultiParameter: boolean;
|
||||
private broadCast_: BroadCast;
|
||||
private filterMediaType: string = undefined;
|
||||
private blackListAlbum: Array<string> = [];
|
||||
private deviceId = '';
|
||||
private filterAlbumsFunction: Function = (mediaSetList: AlbumInfo[]): AlbumInfo[] => {
|
||||
return mediaSetList;
|
||||
};
|
||||
|
||||
constructor(broadCast: BroadCast, param?: InitAlbumParam) {
|
||||
super();
|
||||
|
||||
Log.debug(TAG, `constructor ${JSON.stringify(param)}`);
|
||||
this.broadCast_ = broadCast;
|
||||
this.albumDataImpl = BrowserDataFactory.getFeature(BrowserDataFactory.TYPE_ALBUM, param);
|
||||
|
||||
if (param && param.deviceId) {
|
||||
this.deviceId = param.deviceId;
|
||||
}
|
||||
}
|
||||
|
||||
initData(): void {
|
||||
TraceControllerUtils.startTrace('AlbumSetPageInitData');
|
||||
Log.debug(TAG, 'initData');
|
||||
this.loadData();
|
||||
}
|
||||
|
||||
loadData(): void {
|
||||
Log.info(TAG, 'load data');
|
||||
if (this.albumDataImpl != null) {
|
||||
let callback: AlbumSetCallback = new AlbumSetCallback(this);
|
||||
this.albumDataImpl.getData(callback,
|
||||
(this.filterMediaType == undefined) ? null : { filterMediaType: this.filterMediaType });
|
||||
}
|
||||
}
|
||||
|
||||
totalCount(): number {
|
||||
let newTotalCount = this.mediaSetList.length;
|
||||
if (this.lastTotalCount != newTotalCount) {
|
||||
Log.info(TAG, `totalCount: ${newTotalCount}`);
|
||||
this.lastTotalCount = newTotalCount;
|
||||
}
|
||||
return newTotalCount;
|
||||
}
|
||||
|
||||
setMultiParameter(isMultiParameter: boolean): void {
|
||||
this.isMultiParameter = isMultiParameter;
|
||||
}
|
||||
|
||||
getData(index: number): AlbumSetDataInfo {
|
||||
Log.info(TAG, `getData index: ${index}, item: ${JSON.stringify(this.mediaSetList[index])}`);
|
||||
if (index < 0 || index >= this.mediaSetList.length) {
|
||||
Log.error(TAG, `index out of the total size, index: ${index} total size: ${this.mediaSetList.length}`);
|
||||
return undefined;
|
||||
}
|
||||
return new AlbumSetDataInfo(this.mediaSetList[index], index);
|
||||
}
|
||||
|
||||
updateAlbumSetData(requestTime: number, mediaSetList: AlbumInfo[]): void {
|
||||
TraceControllerUtils.startTraceWithTaskId('updateAlbumSetData', requestTime);
|
||||
Log.info(TAG, `updateMediaItems size: ${mediaSetList.length}`);
|
||||
this.lastUpdateTime = requestTime;
|
||||
if (this.lastUpdateTime < this.lastChangeTime && this.isActive) {
|
||||
// If there is a new media library change callback,
|
||||
// the query continues and the current data is updated without return.
|
||||
Log.debug(TAG, 'request data expired, request again!');
|
||||
this.loadData();
|
||||
} else {
|
||||
this.hasNewChange = false;
|
||||
}
|
||||
this.mediaSetList = this.excludeBlackList(mediaSetList);
|
||||
this.onDataReloaded();
|
||||
TraceControllerUtils.finishTraceWithTaskId('updateAlbumSetData', requestTime);
|
||||
this.broadCast_.emit(Constants.ON_LOADING_FINISHED, [this.totalCount()]);
|
||||
TraceControllerUtils.finishTrace('AlbumSetPageInitData');
|
||||
}
|
||||
|
||||
excludeBlackList(mediaSetList: AlbumInfo[]): Array<AlbumInfo> {
|
||||
let res: AlbumInfo[];
|
||||
if (0 == this.blackListAlbum.length) {
|
||||
Log.debug(TAG, 'BlackListAlbum: no black list.');
|
||||
res = mediaSetList;
|
||||
} else {
|
||||
Log.debug(TAG, `BlackListAlbum: albums name ${JSON.stringify(this.blackListAlbum)}.`);
|
||||
res = mediaSetList.filter((item) => {
|
||||
return this.blackListAlbum.indexOf(item.uri) < 0; // id 修改为了 uri,保证编译通过,可能发生错误
|
||||
});
|
||||
}
|
||||
res = this.filterAlbumsFunction(res);
|
||||
Log.debug(TAG, `BlackListAlbum: old albums length ${mediaSetList.length}, new albums length ${res.length}.`);
|
||||
return res;
|
||||
}
|
||||
|
||||
onChange(mediaType: string): void {
|
||||
if (this.deviceId == '' || this.deviceId == undefined) {
|
||||
if (mediaType == 'image' || mediaType == 'video' || mediaType == 'album') {
|
||||
super.onChange(mediaType);
|
||||
}
|
||||
} else {
|
||||
if (mediaType == 'remote') {
|
||||
super.onChange(mediaType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
updateAlbumMediaCount(): void {
|
||||
for (let album of this.mediaSetList) {
|
||||
this.albumDataImpl.getDataCount(null, album);
|
||||
}
|
||||
}
|
||||
|
||||
setFilterMediaType(filterMediaType: string): void {
|
||||
Log.info(TAG, `set filterMediaType: ${filterMediaType}`)
|
||||
this.filterMediaType = filterMediaType;
|
||||
}
|
||||
|
||||
setBlackList(albums: Array<string>): void {
|
||||
this.blackListAlbum = albums;
|
||||
Log.debug(TAG, `BlackListAlbum: set blacklistAlbum ${JSON.stringify(this.blackListAlbum)}.`);
|
||||
}
|
||||
|
||||
setFilterAlbumsFunction(filterAlbumsFunction: Function): void {
|
||||
this.filterAlbumsFunction = filterAlbumsFunction;
|
||||
}
|
||||
}
|
@ -0,0 +1,136 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2023 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 type { MediaObserverCallback } from './MediaObserverCallback';
|
||||
import { Log } from '../../../utils/Log';
|
||||
import { Constants } from '../../common/Constants';
|
||||
import type { ChangeData, UserFileManager } from '../../../access/UserFileManagerAccess';
|
||||
import { UserFileManagerAccess } from '../../../access/UserFileManagerAccess';
|
||||
|
||||
const TAG: string = 'common_MediaObserver';
|
||||
|
||||
export class MediaObserver {
|
||||
callbacks: Set<MediaObserverCallback> = new Set<MediaObserverCallback>();
|
||||
|
||||
static getInstance(): MediaObserver {
|
||||
if (AppStorage.Get(Constants.APP_KEY_MENU_USER_FILE_MANAGER_OBSERVER) == null) {
|
||||
AppStorage.SetOrCreate(Constants.APP_KEY_MENU_USER_FILE_MANAGER_OBSERVER, new MediaObserver());
|
||||
}
|
||||
return AppStorage.Get(Constants.APP_KEY_MENU_USER_FILE_MANAGER_OBSERVER);
|
||||
}
|
||||
|
||||
registerObserver(callback: MediaObserverCallback) {
|
||||
Log.info(TAG, 'registerObserver');
|
||||
if (!callback) {
|
||||
Log.warn(TAG, 'registerObserver with empty callback');
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.callbacks.has(callback)) {
|
||||
Log.warn(TAG, 'registerObserver already exist');
|
||||
return;
|
||||
}
|
||||
this.callbacks.add(callback);
|
||||
}
|
||||
|
||||
unregisterObserver(callback: MediaObserverCallback) {
|
||||
Log.info(TAG, 'unregisterObserver');
|
||||
if (!callback) {
|
||||
Log.warn(TAG, 'unregisterObserver with empty callback');
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.callbacks.has(callback)) {
|
||||
this.callbacks.delete(callback);
|
||||
} else {
|
||||
Log.warn(TAG, 'unregisterObserver not exist');
|
||||
}
|
||||
}
|
||||
|
||||
sendNotify(mediaType: string) {
|
||||
Log.info(TAG, `sendNotify size: ${this.callbacks.size}`);
|
||||
for (let callback of this.callbacks) {
|
||||
callback.onChange(mediaType);
|
||||
}
|
||||
}
|
||||
|
||||
registerForAllPhotos() {
|
||||
Log.info(TAG, 'registerForAllPhotos');
|
||||
let userFileManager: UserFileManager = UserFileManagerAccess.getInstance().getMediaLibrary();
|
||||
if (userFileManager) {
|
||||
userFileManager.on(UserFileManagerAccess.REGISTER_TYPE_ALL_PHOTOS, true, (changeData: ChangeData) => {
|
||||
Log.info(TAG, `userFileManager.on for REGISTER_TYPE_ALL_PHOTOS, ${JSON.stringify(changeData)}`);
|
||||
this.sendNotify('image');
|
||||
});
|
||||
} else {
|
||||
Log.error(TAG, 'register is null!');
|
||||
}
|
||||
}
|
||||
|
||||
unregisterForAllPhotos() {
|
||||
Log.info(TAG, 'unregisterForAllPhotos');
|
||||
let userFileManager: UserFileManager = UserFileManagerAccess.getInstance().getMediaLibrary();
|
||||
if (userFileManager) {
|
||||
userFileManager.off(UserFileManagerAccess.REGISTER_TYPE_ALL_PHOTOS);
|
||||
} else {
|
||||
Log.error(TAG, 'unregister is null!');
|
||||
}
|
||||
}
|
||||
|
||||
registerForAllAlbums() {
|
||||
Log.info(TAG, 'registerForAllAlbums');
|
||||
let userFileManager: UserFileManager = UserFileManagerAccess.getInstance().getMediaLibrary();
|
||||
if (userFileManager) {
|
||||
userFileManager.on(UserFileManagerAccess.REGISTER_TYPE_ALL_ALBUMS, true, (changeData: ChangeData) => {
|
||||
Log.info(TAG, `userFileManager.on for REGISTER_TYPE_ALL_ALBUMS, ${JSON.stringify(changeData)}`);
|
||||
this.sendNotify('image');
|
||||
});
|
||||
} else {
|
||||
Log.error(TAG, 'register is null!');
|
||||
}
|
||||
}
|
||||
|
||||
unregisterForAllAlbums() {
|
||||
Log.info(TAG, 'unregisterForAllAlbums');
|
||||
let userFileManager: UserFileManager = UserFileManagerAccess.getInstance().getMediaLibrary();
|
||||
if (userFileManager) {
|
||||
userFileManager.off(UserFileManagerAccess.REGISTER_TYPE_ALL_ALBUMS);
|
||||
} else {
|
||||
Log.error(TAG, 'unregister is null!');
|
||||
}
|
||||
}
|
||||
|
||||
registerForAlbum(albumUri: string) {
|
||||
Log.info(TAG, 'registerForAllAlbums');
|
||||
let userFileManager: UserFileManager = UserFileManagerAccess.getInstance().getMediaLibrary();
|
||||
if (userFileManager) {
|
||||
userFileManager.on(albumUri, false, (changeData: ChangeData) => {
|
||||
Log.info(TAG, 'userFileManager.on for REGISTER_TYPE_ALL_ALBUMS');
|
||||
this.sendNotify('album');
|
||||
});
|
||||
} else {
|
||||
Log.error(TAG, 'register is null!');
|
||||
}
|
||||
}
|
||||
|
||||
unregisterForAlbum(albumUri: string) {
|
||||
Log.info(TAG, 'unregisterForAllAlbums');
|
||||
let userFileManager: UserFileManager = UserFileManagerAccess.getInstance().getMediaLibrary();
|
||||
if (userFileManager) {
|
||||
userFileManager.off(albumUri);
|
||||
} else {
|
||||
Log.error(TAG, 'unregister is null!');
|
||||
}
|
||||
}
|
||||
}
|
199
common/src/main/ets/default/model/browser/photo/Constants.ts
Normal file
199
common/src/main/ets/default/model/browser/photo/Constants.ts
Normal file
@ -0,0 +1,199 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2023 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 Curves from '@ohos.curves';
|
||||
|
||||
export class Constants {
|
||||
// Immersive animation duration
|
||||
static readonly IMMERSE_ANIM_DURATION = 200;
|
||||
static readonly IMMERSE_ANIM_DELAY = 50;
|
||||
|
||||
// click event
|
||||
static readonly TOGGLE_BAR: string = 'single_photo_toggle_bar';
|
||||
|
||||
// hide bars
|
||||
static readonly HIDE_BARS: string = 'single_photo_hide_bars';
|
||||
|
||||
// show bars
|
||||
static readonly SHOW_BARS: string = 'single_photo_show_bars';
|
||||
|
||||
// pull down to return start
|
||||
static readonly PULL_DOWN_START: string = 'single_photo_pull_down_start';
|
||||
|
||||
// pull down to return end
|
||||
static readonly PULL_DOWN_END: string = 'single_photo_pull_down_end';
|
||||
|
||||
// pull down to return cancel
|
||||
static readonly PULL_DOWN_CANCEL: string = 'single_photo_pull_down_cancel';
|
||||
|
||||
// pull down to return threshold
|
||||
static readonly PULL_DOWN_THRESHOLD: number = 200;
|
||||
|
||||
// data quantity change
|
||||
static readonly DATA_SIZE_CHANGED: string = 'photo_data_size_changed';
|
||||
|
||||
// current data change
|
||||
static readonly DATA_CONTENT_CHANGED: string = 'photo_data_content_changed';
|
||||
|
||||
// video play
|
||||
static readonly VIDEO_PLAY: string = 'single_photo_video_play';
|
||||
|
||||
// video pause
|
||||
static readonly VIDEO_PAUSE: string = 'single_photo_video_pause';
|
||||
|
||||
// popup show
|
||||
static readonly POP_APPEAR: string = 'single_photo_popup_appear';
|
||||
|
||||
// popup disappear
|
||||
static readonly POP_DISAPPEAR: string = 'single_photo_popup_disappear';
|
||||
|
||||
// set favor photo
|
||||
static readonly SET_FAVOR: string = 'single_photo_set_favor';
|
||||
|
||||
// rename photo
|
||||
static readonly RENAME: string = 'single_photo_rename';
|
||||
|
||||
// rotate photo
|
||||
static readonly ROTATE: string = 'single_photo_rotate';
|
||||
|
||||
// delete photo
|
||||
static readonly DELETE: string = 'single_photo_delete';
|
||||
|
||||
// remove photo
|
||||
static readonly Remove: string = 'single_photo_remove';
|
||||
|
||||
// photo show state
|
||||
static readonly PHOTO_SHOW_STATE: string = 'single_photo_show_state';
|
||||
|
||||
// set swiper can swipe
|
||||
static readonly SET_DISABLE_SWIPE: string = 'set_disable_swipe';
|
||||
|
||||
// update photo name
|
||||
static readonly UPDATE_PHOTO_NAME: string = 'update_photo_name';
|
||||
|
||||
// reset default scale
|
||||
static readonly RESET_DEFAULT_SCALE: string = 'reset_default_scale';
|
||||
|
||||
// save scale
|
||||
static readonly SAVE_SCALE: string = 'save_scale';
|
||||
|
||||
// matrix
|
||||
static readonly MATRIX: string = 'matrix';
|
||||
|
||||
// photo browser delete confirm
|
||||
static readonly PHOTO_BROWSER_DELETE_CONFIRM: string = 'photo_browser_delete_confirm';
|
||||
|
||||
// photo browser remove confirm
|
||||
static readonly PHOTO_BROWSER_REMOVE_CONFIRM: string = 'photo_browser_remove_confirm';
|
||||
|
||||
// Scale lower limit
|
||||
static readonly COMPONENT_SCALE_FLOOR: number = 0.5;
|
||||
|
||||
// scale upper limit
|
||||
static readonly COMPONENT_SCALE_CEIL: number = 2.0;
|
||||
|
||||
// when the double-click scale is larger than maxScale, the maxScale is adjusted to 1.2 times the double-click scale
|
||||
static readonly MAX_SCALE_EXTRA_FACTOR: number = 1.2;
|
||||
|
||||
// After reaching max scale, you can also scale an additional 0.2x max scale, and rebound after letting go
|
||||
static readonly OVER_SCALE_EXTRA_FACTOR: number = 1.5;
|
||||
|
||||
// If the aspect ratio of the picture is the same as the display area,
|
||||
// double-click to adjust the zoom factor to 4 / 3
|
||||
static readonly RATIO_SCALE_WIDTH: number = 4;
|
||||
static readonly RATIO_SCALE_HEIGHT: number = 3;
|
||||
static readonly SAME_RATIO_SCALE_FACTOR: number = Constants.RATIO_SCALE_WIDTH / Constants.RATIO_SCALE_HEIGHT;
|
||||
|
||||
static readonly CURVE_X1: number = 0.2;
|
||||
static readonly CURVE_Y1: number = 0.0;
|
||||
static readonly CURVE_X2: number = 0.2;
|
||||
static readonly CURVE_Y2: number = 1.0;
|
||||
static readonly PHOTO_TRANSITION_CURVE: string =
|
||||
Curves.cubicBezier(Constants.CURVE_X1, Constants.CURVE_Y1, Constants.CURVE_X2, Constants.CURVE_Y2);
|
||||
|
||||
// GeometryTransition constants
|
||||
static readonly CAN_PULL_DOWN_DRAG_THRESHOLD: number = 10;
|
||||
static readonly SPRING_MOTION_RESPONSE: number = 0.347;
|
||||
static readonly SPRING_MOTION_DAMPING_FRACTION: number = 0.99;
|
||||
static readonly SPRING_MOTION_CURVE: Curves.ICurve =
|
||||
Curves.springMotion(Constants.SPRING_MOTION_RESPONSE, Constants.SPRING_MOTION_DAMPING_FRACTION);
|
||||
|
||||
// Drag image curve constants
|
||||
static readonly DRAG_SCALE: number = 0.0013;
|
||||
static readonly MIN_DRAG_SCALE: number = 0.5;
|
||||
static readonly DRAG_OPACITY: number = 0.0026;
|
||||
|
||||
static readonly RESPONSIVE_SPRING_MOTION_RESPONSE: number = 0.15;
|
||||
static readonly RESPONSIVE_SPRING_MOTION_DAMPING_FRACTION: number = 0.86;
|
||||
static readonly RESPONSIVE_SPRING_MOTION_OVERLAP_DURATION: number = 0.25;
|
||||
static readonly RESPONSIVE_SPRING_MOTION_CURVE: Curves.ICurve =
|
||||
Curves.responsiveSpringMotion(Constants.RESPONSIVE_SPRING_MOTION_RESPONSE,
|
||||
Constants.RESPONSIVE_SPRING_MOTION_DAMPING_FRACTION, Constants.RESPONSIVE_SPRING_MOTION_OVERLAP_DURATION);
|
||||
|
||||
// overScale animation duration
|
||||
static readonly OVER_SCALE_ANIME_DURATION: number = 500;
|
||||
static readonly ROTATE_ONCE: number = 90;
|
||||
static readonly ROTATE_TWICE: number = 180;
|
||||
static readonly ROTATE_THRICE: number = 270;
|
||||
static readonly ROTATE_QUARTIC: number = 360;
|
||||
static readonly DEFAULT_SIZE: number = 256;
|
||||
static readonly OPERATION_EXIT_ANIMATION_DURATION: number = 100;
|
||||
static readonly SHARE_TRANSITION_DURATION: number = 200;
|
||||
static readonly PAGE_SHOW_ANIMATION_DURATION: number = 200;
|
||||
static readonly PHOTO_GRID_ANIMATION_DURATION: number = 300;
|
||||
static readonly PHOTO_SWIPE_DURATION: number = 300;
|
||||
static readonly RESERVED_DIGITS: number = 6;
|
||||
static readonly CENTER_DEFAULT: number = 0.5;
|
||||
static readonly NUMBER_2: number = 2;
|
||||
static readonly NUMBER_3: number = 3;
|
||||
static readonly NUMBER_12: number = 12;
|
||||
static readonly NUMBER_13: number = 13;
|
||||
|
||||
static readonly PHOTO_GRID_Scale: number = 0.8
|
||||
static readonly Album_Scale: number = 1.2
|
||||
static readonly LINK_IN_PHOTO_GRID_DELAY: number = 100;
|
||||
static readonly PC_LINK_IN_PHOTO_GRID_ACTIONBAR_DURATION: number = 150;
|
||||
static readonly PC_LINK_OUT_PHOTO_GRID_ACTIONBAR_DURATION: number = 200;
|
||||
static readonly PC_LINK_ALBUM_DURATION: number = 200;
|
||||
static readonly PC_LINK_OUT_PHOTO_GRID_DURATION: number = 150;
|
||||
static readonly PC_LINK_IN_PHOTO_GRID_DURATION: number = 200;
|
||||
static readonly PC_LINK_IN_ALBUM_ACTIONBAR_DURATION: number = 150;
|
||||
static readonly PC_LINK_OUT_ALBUM_ACTIONBAR_DURATION: number = 200;
|
||||
static readonly PC_LINK_IN_SIDEBAR_DURATION: number = 150;
|
||||
static readonly PC_LINK_OUT_SIDEBAR_DURATION: number = 200;
|
||||
static readonly PC_LINK_OUT_SIDEBAR_DELAY: number = 0;
|
||||
static readonly PC_LINK_IN_ALBUM_DURATION: number = 200;
|
||||
static readonly PC_LINK_IN_ALBUM_DELAY: number = 50;
|
||||
static readonly PC_LINK_OUT_SIDEBAR_BOUNDARY_LINE_DURATION: number = 150;
|
||||
static readonly PC_LINK_OUT_SIDEBAR_BOUNDARY_LINE_DELAY: number = 250;
|
||||
static readonly PC_LINK_ALBUM_TO_PHOTO_GRID_DURATION: number = 400;
|
||||
static readonly PC_LINK_ALBUM_TO_PHOTO_GRID_SCALE_DURATION: number = 400;
|
||||
static readonly PC_LINK_PHOTO_GRID_TO_ALBUM_DURATION: number = 400;
|
||||
static readonly PC_LINK_PHOTO_GRID_TO_ALBUM_SCALE_DURATION: number = 400;
|
||||
static readonly PC_LINK_OUT_ALBUM_ACTIONBAR_DELAY: number = 50;
|
||||
static readonly PC_LINK_PHOTO_GRID_ACTIONBAR_DELAY: number = 100;
|
||||
|
||||
static readonly PHONE_LINK_IN_PHOTO_GRID_ACTIONBAR_DURATION: number = 250;
|
||||
static readonly PHONE_LINK_OUT_PHOTO_GRID_ACTIONBAR_DURATION: number = 175;
|
||||
static readonly PHONE_LINK_PHOTO_GRID_ACTIONBAR_DELAY: number = 250;
|
||||
static readonly PHONE_LINK_ALBUM_ACTIONBAR_DURATION: number = 250;
|
||||
static readonly PHONE_LINK_ALBUM_ACTIONBAR_DELAY: number = 100;
|
||||
static readonly PHONE_LINK_IN_TAB_BAR_DURATION: number = 250;
|
||||
static readonly PHONE_LINK_OUT_TAB_BAR_DURATION: number = 175;
|
||||
static readonly PHONE_LINK_ALBUM_TO_PHOTO_GRID_DURATION: number = 500;
|
||||
static readonly PHONE_LINK_ALBUM_TO_PHOTO_GRID_SCALE_DURATION: number = 500;
|
||||
static readonly PHONE_LINK_PHOTO_GRID_TO_ALBUM_DURATION: number = 350;
|
||||
static readonly PHONE_LINK_PHOTO_GRID_TO_ALBUM_SCALE_DURATION: number = 350;
|
||||
}
|
731
common/src/main/ets/default/model/browser/photo/EventPipeline.ts
Normal file
731
common/src/main/ets/default/model/browser/photo/EventPipeline.ts
Normal file
@ -0,0 +1,731 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2023 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 Matrix4 from '@ohos.matrix4';
|
||||
import { MediaItem } from './MediaItem';
|
||||
import { Log } from '../../../utils/Log';
|
||||
import { BroadCast } from '../../../utils/BroadCast';
|
||||
import { MathUtil } from '../../../utils/MathUtil';
|
||||
import { Constants as PhotoConstants } from './Constants';
|
||||
import { ScreenManager } from '../../common/ScreenManager';
|
||||
import { PhotoItemGestureCallback } from '../../browser/photo/PhotoItemGestureCallback';
|
||||
import { BigDataConstants, ReportToBigDataUtil } from '../../../utils/ReportToBigDataUtil';
|
||||
import { UiUtil } from '../../../utils/UiUtil';
|
||||
|
||||
const TAG: string = 'common_EventPipeline';
|
||||
|
||||
export type AnimationParam = {
|
||||
duration: number,
|
||||
curve: Curve
|
||||
};
|
||||
|
||||
export class EventPipeline {
|
||||
// 上次平移
|
||||
private lastOffset: [number, number] = [0, 0];
|
||||
|
||||
// 当前平移
|
||||
private offset: [number, number] = [0, 0];
|
||||
|
||||
// 上次缩放值
|
||||
private lastScale: number = 1.0;
|
||||
|
||||
// 默认缩放值
|
||||
private defaultScale: number = 1.0;
|
||||
|
||||
// 当前缩放值
|
||||
private scale: number = 1.0;
|
||||
|
||||
// 缩放中心点,是相对于控件的百分比位置,非绝对位置
|
||||
private center: [number, number] = [0.5, 0.5];
|
||||
|
||||
// 最左缩放中心,(1 - leftMost)即为最右缩放中心
|
||||
private leftMost: number = 0.0;
|
||||
|
||||
// 最上缩放中心,(1 - topMost)即为最下缩放中心
|
||||
private topMost: number = 0.0;
|
||||
|
||||
// 双击缩放比例
|
||||
private doubleTapScale: number = 1.0;
|
||||
|
||||
// 最大缩放比例
|
||||
private maxScale: number = 1.0;
|
||||
|
||||
// 是否已经到达最左边
|
||||
private hasReachLeft: boolean = true;
|
||||
|
||||
// 是否已经到达最右边
|
||||
private hasReachRight: boolean = true;
|
||||
|
||||
// 事件总线
|
||||
private broadCast: BroadCast;
|
||||
|
||||
// 数据单个条目项
|
||||
private item: MediaItem;
|
||||
|
||||
// 事件总线
|
||||
private gestureCallback: PhotoItemGestureCallback;
|
||||
|
||||
// 宽度
|
||||
private width: number;
|
||||
|
||||
// 高度
|
||||
private height: number;
|
||||
|
||||
// 大图显示控件宽度
|
||||
private componentWidth: number = vp2px(ScreenManager.getInstance().getWinLayoutWidth());
|
||||
|
||||
// 大图显示控件高度
|
||||
private componentHeight: number = vp2px(ScreenManager.getInstance().getWinLayoutHeight());
|
||||
|
||||
// 是否在做动画
|
||||
private isInAnimation: boolean = false;
|
||||
|
||||
// 下拉返回flag,防止触发多次
|
||||
private isExiting: boolean = false;
|
||||
|
||||
private touchEventStartX: number = 0;
|
||||
|
||||
private touchEventStartY: number = 0;
|
||||
|
||||
private touchEventStartId: number = 0;
|
||||
|
||||
private isPullDownAndDragPhoto: boolean = false;
|
||||
|
||||
constructor(broadCastParam: BroadCast, item: MediaItem, gestureCallback: PhotoItemGestureCallback) {
|
||||
this.broadCast = broadCastParam;
|
||||
this.item = item;
|
||||
this.gestureCallback = gestureCallback;
|
||||
this.width = this.item.imgWidth == 0 ? PhotoConstants.DEFAULT_SIZE : this.item.imgWidth;
|
||||
this.height = this.item.imgHeight == 0 ? PhotoConstants.DEFAULT_SIZE : this.item.imgHeight;
|
||||
this.evaluateScales();
|
||||
}
|
||||
|
||||
onDataChanged(item: MediaItem) {
|
||||
this.item = item;
|
||||
this.width = this.item.imgWidth == 0 ? PhotoConstants.DEFAULT_SIZE : this.item.imgWidth;
|
||||
this.height = this.item.imgHeight == 0 ? PhotoConstants.DEFAULT_SIZE : this.item.imgHeight;
|
||||
this.evaluateScales();
|
||||
}
|
||||
|
||||
setDefaultScale(scale) {
|
||||
this.defaultScale = scale;
|
||||
this.lastScale = scale;
|
||||
}
|
||||
|
||||
onComponentSizeChanged(componentWidth: number, componentHeight: number) {
|
||||
Log.info(TAG, `onComponentSizeChanged componentWidth ${componentWidth} componentHeight ${componentHeight}`)
|
||||
this.componentWidth = componentWidth;
|
||||
this.componentHeight = componentHeight;
|
||||
this.evaluateScales();
|
||||
let animationEndMatrix: Matrix4.Matrix4Transit = this.evaluateAnimeMatrix(this.lastScale, this.center);
|
||||
this.startAnimation(animationEndMatrix);
|
||||
}
|
||||
|
||||
public canTouch(): Boolean {
|
||||
return !(this.isInAnimation || this.isExiting);
|
||||
}
|
||||
|
||||
onTouch(event: TouchEvent) {
|
||||
Log.debug(TAG, `onTouch trigger: ${event.type}, ${[this.isInAnimation, this.isExiting]}`);
|
||||
if (!this.canTouch()) {
|
||||
return;
|
||||
}
|
||||
if (event.type == TouchType.Down || event.type == TouchType.Up) {
|
||||
this.emitDirectionChange();
|
||||
}
|
||||
this.verifyPullDownAndDragPhotoStatus(event);
|
||||
|
||||
// 普通场景up时记录scale及offset,动画场景动画结束时记录
|
||||
if (event.type == TouchType.Up) {
|
||||
this.lastOffset = this.evaluateOffset();
|
||||
this.lastScale = this.lastScale * this.scale;
|
||||
// 必须重置scale及offset,否则多次操作间会串,但是center不用清,因为this.scale为1时center不起作用
|
||||
this.scale = 1;
|
||||
this.offset = [0, 0];
|
||||
}
|
||||
}
|
||||
|
||||
verifyPullDownAndDragPhotoStatus(event: TouchEvent): void {
|
||||
let scale = this.lastScale * this.scale;
|
||||
let isEnlarged = Number(scale.toFixed(PhotoConstants.RESERVED_DIGITS)) > Number(this.defaultScale.toFixed(PhotoConstants.RESERVED_DIGITS));
|
||||
let touchList = event.touches;
|
||||
|
||||
if (touchList.length > 1) {
|
||||
return;
|
||||
}
|
||||
if (event.type === TouchType.Down) {
|
||||
// 重置拖动图片场景参数
|
||||
if (this.canPullDownAndDragPhoto()) {
|
||||
this.touchEventStartX = 0;
|
||||
this.touchEventStartY = 0;
|
||||
this.isPullDownAndDragPhoto = false;
|
||||
}
|
||||
|
||||
this.touchEventStartX = touchList[0].screenX;
|
||||
this.touchEventStartY = touchList[0].screenY;
|
||||
this.touchEventStartId = touchList[0].id;
|
||||
} else if (event.type === TouchType.Move && this.touchEventStartId === touchList[0].id) {
|
||||
let touchX = touchList[0].screenX;
|
||||
let touchY = touchList[0].screenY;
|
||||
let deltaX = Math.abs(touchX - this.touchEventStartX);
|
||||
let deltaY = touchY - this.touchEventStartY;
|
||||
if (deltaY - deltaX > PhotoConstants.CAN_PULL_DOWN_DRAG_THRESHOLD && !isEnlarged) {
|
||||
this.isPullDownAndDragPhoto = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.isPullDownAndDragPhoto) {
|
||||
this.gestureCallback.onDirectionChangeRespond(PanDirection.All);
|
||||
}
|
||||
Log.debug(TAG, 'canPullDownAndDragPhoto ' + this.isPullDownAndDragPhoto);
|
||||
}
|
||||
|
||||
canPullDownAndDragPhoto(): boolean {
|
||||
return this.isPullDownAndDragPhoto;
|
||||
}
|
||||
|
||||
onMoveStart(offsetX: number, offsetY: number) {
|
||||
if (this.isInAnimation || this.isExiting) {
|
||||
return;
|
||||
}
|
||||
// 拖动开始时重置offset,防止跳变
|
||||
this.offset = [0, 0];
|
||||
this.evaluateBounds();
|
||||
let scale = this.lastScale * this.scale;
|
||||
if (Number(scale.toFixed(PhotoConstants.RESERVED_DIGITS)) > Number(this.defaultScale.toFixed(PhotoConstants.RESERVED_DIGITS))) {
|
||||
// 有缩放拖动时隐藏bars
|
||||
this.broadCast.emit(PhotoConstants.HIDE_BARS, [null]);
|
||||
}
|
||||
if (scale.toFixed(PhotoConstants.RESERVED_DIGITS) === this.defaultScale.toFixed(PhotoConstants.RESERVED_DIGITS) && offsetY > 0) {
|
||||
// 下拉返回开始先隐藏详情
|
||||
this.broadCast.emit(PhotoConstants.PULL_DOWN_START, [null]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 每次回调回来的是相对于此次手势开始点的位移
|
||||
*
|
||||
* @param offsetX offsetX
|
||||
* @param offsetY offsetY
|
||||
*/
|
||||
onMove(offsetX: number, offsetY: number) {
|
||||
if (this.isInAnimation || this.isExiting) {
|
||||
return;
|
||||
}
|
||||
let scale = this.lastScale * this.scale;
|
||||
let limits = this.evaluateOffsetRange(scale);
|
||||
let measureX = this.lastOffset[0] + (this.center[0] - 0.5) * this.componentWidth * (this.defaultScale - this.scale) * this.lastScale;
|
||||
let measureY = this.lastOffset[1] + (this.center[1] - 0.5) * this.componentHeight * ((this.defaultScale - this.scale)) * this.lastScale;
|
||||
let moveX = offsetX;
|
||||
let moveY = offsetY;
|
||||
let offX = measureX + moveX;
|
||||
let offY = measureY + moveY;
|
||||
|
||||
if (Number(scale.toFixed(PhotoConstants.RESERVED_DIGITS)) > Number(this.defaultScale.toFixed(PhotoConstants.RESERVED_DIGITS))) {
|
||||
// 非缩小场景,始终限制x方向上的offset
|
||||
offX = MathUtil.clamp(offX, limits[0], limits[1]);
|
||||
if (Number(scale.toFixed(PhotoConstants.RESERVED_DIGITS)) > Number(this.defaultScale.toFixed(PhotoConstants.RESERVED_DIGITS))) {
|
||||
// 不可下拉返回场景,限制y
|
||||
offY = MathUtil.clamp(offY, limits[PhotoConstants.NUMBER_2], limits[PhotoConstants.NUMBER_3]);
|
||||
} else {
|
||||
// 可下拉返回场景,只限制y向上拖动,即限制下界
|
||||
offY = Math.max(limits[PhotoConstants.NUMBER_2], offY);
|
||||
}
|
||||
}
|
||||
let tmpX = offX - measureX;
|
||||
let tmpY = offY - measureY;
|
||||
this.offset = [tmpX, tmpY];
|
||||
this.emitTouchEvent();
|
||||
}
|
||||
|
||||
onMoveEnd(offsetX: number, offsetY: number) {
|
||||
if (this.isInAnimation || this.isExiting) {
|
||||
return;
|
||||
}
|
||||
|
||||
let isStartPullDown = false;
|
||||
let scale = this.lastScale * this.scale;
|
||||
if (scale.toFixed(PhotoConstants.RESERVED_DIGITS) === this.defaultScale.toFixed(PhotoConstants.RESERVED_DIGITS) &&
|
||||
offsetY > PhotoConstants.PULL_DOWN_THRESHOLD) {
|
||||
// 触发下拉返回
|
||||
this.emitPullDownToBackEvent();
|
||||
isStartPullDown = true;
|
||||
} else if (scale.toFixed(PhotoConstants.RESERVED_DIGITS) === this.defaultScale.toFixed(PhotoConstants.RESERVED_DIGITS) &&
|
||||
offsetY < -PhotoConstants.PULL_DOWN_THRESHOLD && !this.canPullDownAndDragPhoto()) {
|
||||
// 触发上划,但当已处于下拉拖动图片状态时,不触发上滑
|
||||
this.emitPullUpToDisplayEvent();
|
||||
} else if (scale.toFixed(PhotoConstants.RESERVED_DIGITS) === this.defaultScale.toFixed(PhotoConstants.RESERVED_DIGITS)) {
|
||||
// 未到阈值,触发重置动画
|
||||
this.startAnimation(Matrix4.identity().scale({
|
||||
x: this.defaultScale,
|
||||
y: this.defaultScale
|
||||
}).copy());
|
||||
this.emitPullDownCancelEvent()
|
||||
} else {
|
||||
this.emitDirectionChange();
|
||||
}
|
||||
|
||||
// 非下拉返回场景,重置拖动相关参数
|
||||
if (!isStartPullDown) {
|
||||
UiUtil.resetGeometryTransitionParams();
|
||||
this.touchEventStartX = 0;
|
||||
this.touchEventStartY = 0;
|
||||
this.isPullDownAndDragPhoto = false;
|
||||
}
|
||||
}
|
||||
|
||||
onScaleStart(scale: number, centerX: number, centerY: number) {
|
||||
Log.info(TAG, `onScaleStart: ${[this.isInAnimation, this.isExiting]}`);
|
||||
if (this.isInAnimation || this.isExiting) {
|
||||
return;
|
||||
}
|
||||
// scale开始时重置this.scale为1
|
||||
this.scale = 1;
|
||||
this.evaluateBounds();
|
||||
// Adjust action bar status
|
||||
this.broadCast.emit(PhotoConstants.HIDE_BARS, []);
|
||||
this.center = this.evaluateCenter(centerX, centerY);
|
||||
}
|
||||
|
||||
onScale(scale: number) {
|
||||
Log.info(TAG, `onScale: ${[this.isInAnimation, this.isExiting]}, scale: ${scale}`);
|
||||
if (this.isInAnimation || this.isExiting) {
|
||||
return;
|
||||
}
|
||||
this.evaluateBounds();
|
||||
this.scale = scale;
|
||||
if (this.lastScale * scale <= PhotoConstants.COMPONENT_SCALE_FLOOR) {
|
||||
this.scale = PhotoConstants.COMPONENT_SCALE_FLOOR / this.lastScale;
|
||||
}
|
||||
if (this.lastScale * scale >= this.maxScale * PhotoConstants.OVER_SCALE_EXTRA_FACTOR) {
|
||||
this.scale = this.maxScale * PhotoConstants.OVER_SCALE_EXTRA_FACTOR / this.lastScale;
|
||||
}
|
||||
this.emitTouchEvent();
|
||||
}
|
||||
|
||||
onScaleEnd() {
|
||||
Log.info(TAG, `onScaleEnd: ${[this.isInAnimation, this.isExiting]}`);
|
||||
if (this.isInAnimation || this.isExiting) {
|
||||
return;
|
||||
}
|
||||
this.evaluateBounds();
|
||||
let scale = this.lastScale * this.scale;
|
||||
if (Number(scale.toFixed(PhotoConstants.RESERVED_DIGITS)) >= Number(this.defaultScale.toFixed(PhotoConstants.RESERVED_DIGITS)) && scale <= this.maxScale) {
|
||||
Log.info(TAG, `does not need to do animation: ${scale}`);
|
||||
this.emitDirectionChange();
|
||||
return;
|
||||
}
|
||||
let animationEndMatrix: Matrix4.Matrix4Transit = null;
|
||||
if (Number(scale.toFixed(PhotoConstants.RESERVED_DIGITS)) <= Number(this.defaultScale.toFixed(PhotoConstants.RESERVED_DIGITS))) {
|
||||
// 缩小过小,触发恢复的动画
|
||||
animationEndMatrix = Matrix4.identity().scale({
|
||||
x: this.defaultScale,
|
||||
y: this.defaultScale
|
||||
}).copy();
|
||||
} else {
|
||||
// 放大时做缩回maxScale的动画
|
||||
animationEndMatrix = this.evaluateAnimeMatrix(this.maxScale, this.center);
|
||||
}
|
||||
this.startAnimation(animationEndMatrix);
|
||||
}
|
||||
|
||||
/**
|
||||
* 双击触发缩放,如果当前scale小于等于1,缩放到doubleTapScale;如果当前scale大于1,缩放到1;
|
||||
*
|
||||
* @param centerX 双击位置
|
||||
* @param centerY 双击位置
|
||||
*/
|
||||
onDoubleTap(centerX: number, centerY: number) {
|
||||
if (this.isInAnimation || this.isExiting) {
|
||||
Log.debug(TAG, `[onDoubleTap] not avaliable: ${[this.isInAnimation, this.isExiting]}`);
|
||||
return;
|
||||
}
|
||||
// Adjust action bar status
|
||||
this.broadCast.emit(PhotoConstants.HIDE_BARS, []);
|
||||
let matrix: Matrix4.Matrix4Transit = undefined;
|
||||
if (Number(this.lastScale.toFixed(PhotoConstants.RESERVED_DIGITS)) * this.scale > Number(this.defaultScale.toFixed(PhotoConstants.RESERVED_DIGITS))) {
|
||||
// scale大于1时缩放到原始状态
|
||||
matrix = Matrix4.identity().scale({
|
||||
x: this.defaultScale,
|
||||
y: this.defaultScale
|
||||
}).copy();
|
||||
Log.debug(TAG, '[onDoubleTap] matrix scale 1');
|
||||
} else {
|
||||
// 放大状态根据点击位置计算放大中心
|
||||
this.center = this.evaluateCenter(centerX, centerY);
|
||||
// 图片宽高比小于控件宽高比时,centerX置为0.5,反之centerY置为0.5,保证双击放大后短边靠边
|
||||
if (this.width / this.height < this.componentWidth / this.componentHeight) {
|
||||
this.center[0] = PhotoConstants.COMPONENT_SCALE_FLOOR;
|
||||
} else {
|
||||
this.center[1] = PhotoConstants.COMPONENT_SCALE_FLOOR;
|
||||
}
|
||||
matrix = this.evaluateAnimeMatrix(this.doubleTapScale * this.defaultScale, this.center);
|
||||
Log.debug(TAG, '[onDoubleTap] matrix scale center');
|
||||
}
|
||||
this.startAnimation(matrix);
|
||||
}
|
||||
|
||||
reset() {
|
||||
this.lastOffset = [0, 0];
|
||||
this.offset = [0, 0];
|
||||
this.lastScale = 1.0;
|
||||
this.scale = 1;
|
||||
this.hasReachLeft = true;
|
||||
this.hasReachRight = true;
|
||||
this.isInAnimation = false;
|
||||
this.isExiting = false;
|
||||
this.emitDirectionChange();
|
||||
}
|
||||
|
||||
onDisAppear() {
|
||||
Log.info(TAG, 'onDisAppear');
|
||||
this.reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* 动画结束,根据结束的变换矩阵刷新当前的各个参数值,保证连续性,防止下次手势操作时发生跳变
|
||||
*
|
||||
* @param animationEndMatrix 结束时的变换矩阵
|
||||
*/
|
||||
onAnimationEnd(animationEndMatrix: Matrix4.Matrix4Transit): void {
|
||||
if (animationEndMatrix) {
|
||||
// @ts-ignore
|
||||
let matrix = animationEndMatrix.matrix4x4;
|
||||
Log.info(TAG, `onAnimationEnd: ${matrix}`);
|
||||
this.lastScale = matrix[0];
|
||||
this.scale = 1;
|
||||
this.lastOffset = [matrix[PhotoConstants.NUMBER_12], matrix[PhotoConstants.NUMBER_13]];
|
||||
this.offset = [0, 0];
|
||||
this.evaluateBounds();
|
||||
this.isInAnimation = false;
|
||||
this.emitDirectionChange();
|
||||
}
|
||||
}
|
||||
|
||||
public setSwipeStatus(disable: Boolean): void {
|
||||
this.broadCast.emit(PhotoConstants.SET_DISABLE_SWIPE, [disable]);
|
||||
}
|
||||
|
||||
startAnimation(animationEndMatrix: Matrix4.Matrix4Transit): void {
|
||||
this.isInAnimation = true;
|
||||
let animationOption: AnimationParam = {
|
||||
duration: PhotoConstants.OVER_SCALE_ANIME_DURATION,
|
||||
curve: Curve.Ease
|
||||
};
|
||||
this.gestureCallback.onAnimationEventRespond(animationOption, animationEndMatrix);
|
||||
this.setSwipeStatus(true);
|
||||
}
|
||||
|
||||
isDefaultScale(): boolean {
|
||||
return Number(this.lastScale.toFixed(PhotoConstants.RESERVED_DIGITS)) ===
|
||||
Number(this.defaultScale.toFixed(PhotoConstants.RESERVED_DIGITS));
|
||||
}
|
||||
|
||||
private emitDirectionChange(): void {
|
||||
/**
|
||||
* reachLeft reachRight scale>1这三个变量,只可能有下面五种情况(scale<=1下reachLeft、reachRight必然为true):
|
||||
* T T T:Vertical
|
||||
* T T F:Vertical(大图初始状态)
|
||||
* T F T:Vertical | Left
|
||||
* F T T:Vertical | Right
|
||||
* F F T:All
|
||||
*/
|
||||
let direction: any = undefined;
|
||||
let scale = this.lastScale * this.scale;
|
||||
let isEnlarged = Number(scale.toFixed(PhotoConstants.RESERVED_DIGITS)) > Number(this.defaultScale.toFixed(PhotoConstants.RESERVED_DIGITS));
|
||||
if (!this.hasReachLeft && !this.hasReachRight && isEnlarged) {
|
||||
direction = PanDirection.All;
|
||||
} else if (!this.hasReachLeft && this.hasReachRight && isEnlarged) {
|
||||
direction = PanDirection.Vertical | PanDirection.Right;
|
||||
} else if (this.hasReachLeft && !this.hasReachRight && isEnlarged) {
|
||||
direction = PanDirection.Vertical | PanDirection.Left;
|
||||
} else {
|
||||
direction = PanDirection.Vertical;
|
||||
}
|
||||
|
||||
if (this.isExiting) {
|
||||
return;
|
||||
}
|
||||
if (direction == PanDirection.Vertical || direction == (PanDirection.Vertical | PanDirection.Left) ||
|
||||
direction == (PanDirection.Vertical | PanDirection.Right)) {
|
||||
this.setSwipeStatus(false);
|
||||
} else {
|
||||
this.setSwipeStatus(true);
|
||||
}
|
||||
Log.debug(TAG, `emitDirectionChange reaches: ${[this.hasReachLeft, this.hasReachRight]}, scale ${scale}, direction: ${direction}`);
|
||||
this.gestureCallback.onDirectionChangeRespond(direction);
|
||||
}
|
||||
|
||||
private evaluateOffset(): [number, number] {
|
||||
Log.info(TAG, `evaluateOffset lastOffset: ${this.lastOffset}, offset: ${this.offset}`);
|
||||
let centerX = (this.center[0] - 0.5) * this.componentWidth * (this.defaultScale - this.scale) * this.lastScale;
|
||||
let centerY = (this.center[1] - 0.5) * this.componentHeight * (this.defaultScale - this.scale) * this.lastScale;
|
||||
let offsetX = this.lastOffset[0] + this.offset[0] + centerX;
|
||||
let offsetY = this.lastOffset[1] + this.offset[1] + centerY;
|
||||
Log.info(TAG, `evaluateOffset offsetX: ${offsetX}, offsetY: ${offsetY}`);
|
||||
return [offsetX, offsetY];
|
||||
}
|
||||
|
||||
private emitTouchEvent(): void {
|
||||
let offset: [number, number];
|
||||
let scale = this.lastScale * this.scale;
|
||||
if (Number(scale.toFixed(PhotoConstants.RESERVED_DIGITS)) > Number(this.defaultScale.toFixed(PhotoConstants.RESERVED_DIGITS))) {
|
||||
let limits = this.evaluateOffsetRange(scale);
|
||||
offset = this.evaluateOffset();
|
||||
// 非缩小场景,始终限制x方向上的offset
|
||||
offset[0] = MathUtil.clamp(offset[0], limits[0], limits[1]);
|
||||
if (Number(scale.toFixed(PhotoConstants.RESERVED_DIGITS)) > Number(this.defaultScale.toFixed(PhotoConstants.RESERVED_DIGITS))) {
|
||||
// 不可下拉返回场景,限制y
|
||||
offset[1] = MathUtil.clamp(offset[1], limits[PhotoConstants.NUMBER_2], limits[PhotoConstants.NUMBER_3]);
|
||||
} else {
|
||||
// 可下拉返回场景,只限制y向上拖动,即限制下界
|
||||
offset[1] = Math.max(limits[PhotoConstants.NUMBER_2], offset[1]);
|
||||
}
|
||||
} else {
|
||||
// 缩小时调整缩放中心为显示中心点
|
||||
offset = [0, 0];
|
||||
}
|
||||
let moveX = offset[0];
|
||||
let moveY = offset[1];
|
||||
let matrix = Matrix4.identity().scale({
|
||||
x: scale,
|
||||
y: scale,
|
||||
}).translate({
|
||||
x: moveX,
|
||||
y: moveY
|
||||
}).copy();
|
||||
Log.info(TAG, `emitTouchEvent lastOffset: ${this.lastOffset}, offset: ${this.offset}, center: ${this.center}, scale: ${[this.lastScale, this.scale]}`);
|
||||
this.gestureCallback.onTouchEventRespond(matrix);
|
||||
this.evaluateBounds();
|
||||
}
|
||||
|
||||
/**
|
||||
* 大图放大倍率计算,主要包含:
|
||||
* 1. 最大放大倍率maxScale
|
||||
* 最大可放大到 maxScale * PhotoConstants.OVER_SCALE_EXTRA_FACTOR,然后回弹至maxScale;
|
||||
* 如果小于doubleTapScale * PhotoConstants.MAX_SCALE_EXTRA_FACTOR,取该值作为放大倍率;
|
||||
* 2. 双击放大倍率doubleTapScale
|
||||
* 默认使图片长边对齐屏幕边缘,如果小于PhotoConstants.SAME_RATIO_SCALE_FACTOR(4/3)取该值
|
||||
*/
|
||||
private evaluateScales(): void {
|
||||
if (this.width * this.componentHeight < this.componentWidth * this.height) {
|
||||
// 宽高比小于控件显示宽高比,控件高度与图片高度相等
|
||||
this.maxScale = this.height / this.componentHeight;
|
||||
// 双击放大的scale保证左右充满边界
|
||||
this.doubleTapScale = this.componentWidth * this.height / this.width / this.componentHeight;
|
||||
// leftMost = (1 - dspW / compW) / 2 = (1 - compH * imgW / imgH / compW) / 2
|
||||
this.leftMost = (1 - this.componentHeight * this.width / this.height / this.componentWidth) / 2;
|
||||
this.topMost = 0.0;
|
||||
} else if (this.width * this.componentHeight == this.componentWidth * this.height) {
|
||||
// 宽高比等于控件显示宽高比
|
||||
this.doubleTapScale = PhotoConstants.SAME_RATIO_SCALE_FACTOR;
|
||||
this.maxScale = this.doubleTapScale * PhotoConstants.MAX_SCALE_EXTRA_FACTOR;
|
||||
this.leftMost = 0;
|
||||
this.topMost = 0;
|
||||
} else {
|
||||
// 宽高比大于控件显示宽高比,控件宽度与图片宽度相等
|
||||
this.maxScale = this.width / this.componentWidth;
|
||||
// 双击放大的scale保证上下充满边界
|
||||
this.doubleTapScale = this.componentHeight * this.width / this.height / this.componentWidth;
|
||||
this.leftMost = 0.0;
|
||||
// topMost = (1 - dspH / compH) / 2 = (1 - compW * imgH / imgW / compH) / 2
|
||||
this.topMost = (1 - this.componentWidth * this.height / this.width / this.componentHeight) / 2;
|
||||
}
|
||||
|
||||
this.maxScale = Math.max(this.maxScale, PhotoConstants.COMPONENT_SCALE_CEIL);
|
||||
if (this.doubleTapScale > this.maxScale) {
|
||||
this.maxScale = this.doubleTapScale * PhotoConstants.MAX_SCALE_EXTRA_FACTOR;
|
||||
}
|
||||
Log.debug(TAG, `evaluateScales: ${this.width}*${this.height} & ${this.componentWidth}*${this.componentHeight}, max: ${this.maxScale}, most: [${this.leftMost},${this.topMost}], double: ${this.doubleTapScale}`);
|
||||
}
|
||||
|
||||
private evaluateCompBounds(): [number, number] {
|
||||
let scale = this.lastScale * this.scale;
|
||||
let offset = this.evaluateOffset();
|
||||
// 组件左上角坐标,因放大带来的偏移是-compW*(scale-1)/2,再加上偏移,得到控件左边界,上边界同理
|
||||
let result: [number, number] = [
|
||||
offset[0] - this.componentWidth * (Number(scale.toFixed(PhotoConstants.RESERVED_DIGITS)) - Number(this.defaultScale.toFixed(PhotoConstants.RESERVED_DIGITS))) / 2,
|
||||
offset[1] - this.componentHeight * (Number(scale.toFixed(PhotoConstants.RESERVED_DIGITS)) - Number(this.defaultScale.toFixed(PhotoConstants.RESERVED_DIGITS))) / 2
|
||||
];
|
||||
Log.debug(TAG, `evaluateCompBounds: ${result}`);
|
||||
return result;
|
||||
}
|
||||
|
||||
private evaluateImgDisplaySize(): [number, number] {
|
||||
let screenScale = 1;
|
||||
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;
|
||||
let imgDisplayWidth = 0;
|
||||
let imgDisplayHeight = 0;
|
||||
imgDisplayWidth = this.width * scale;
|
||||
imgDisplayHeight = this.height * scale;
|
||||
return [imgDisplayWidth, imgDisplayHeight];
|
||||
}
|
||||
|
||||
private evaluateImgDisplayBounds(): [number, number] {
|
||||
// 组件左边界,因放大带来的偏移是-compW*(scale-1)/2,再加上手势的偏移,得到控件左边界,上边界同理
|
||||
let scale = this.lastScale * this.scale;
|
||||
let leftTop = this.evaluateCompBounds();
|
||||
let imgDisplaySize: [number, number] = this.evaluateImgDisplaySize();
|
||||
let imgDisplayWidth = imgDisplaySize[0];
|
||||
let imgDisplayHeight = imgDisplaySize[1];
|
||||
let imgLeftBound = 0;
|
||||
let imgTopBound = 0;
|
||||
if (this.width / this.height > this.componentWidth / this.componentHeight) {
|
||||
imgLeftBound = leftTop[0];
|
||||
imgTopBound = leftTop[1] + (this.componentHeight * scale - imgDisplayHeight) / 2;
|
||||
} else {
|
||||
// 控件宽度减掉图片宽度,除以2就能得到图片左边到控件左边的距离,加上offsetX就是就是图片当前显示的左边界
|
||||
imgLeftBound = (this.componentWidth * scale - imgDisplayWidth) / 2 + leftTop[0];
|
||||
imgTopBound = leftTop[1];
|
||||
}
|
||||
return [imgLeftBound, imgTopBound];
|
||||
}
|
||||
|
||||
// 计算图片显示边界
|
||||
private evaluateBounds(): void {
|
||||
let imgDisplaySize: [number, number] = this.evaluateImgDisplaySize();
|
||||
let imgDisplayWidth = imgDisplaySize[0];
|
||||
|
||||
let imgDisplayBounds = this.evaluateImgDisplayBounds();
|
||||
let imgLeftBound = imgDisplayBounds[0];
|
||||
|
||||
// 因底层计算有误差(小数点后6位),不能以0作为精确边界,左右分别容错1像素
|
||||
this.hasReachLeft = imgLeftBound > -1;
|
||||
this.hasReachRight = imgLeftBound + imgDisplayWidth < this.componentWidth + 1;
|
||||
Log.info(TAG, `evaluateBounds scale: ${this.hasReachLeft}, offset: ${this.hasReachRight}`);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算当前scale下x及y方向上的offset上下界
|
||||
*
|
||||
* @param scale 当前控件显示倍率,通常是 this.lastScale * this.scale
|
||||
* @returns 0&1 x方向offset下界&上界,2&3 y方向offset下界&上界
|
||||
*/
|
||||
private evaluateOffsetRange(scale: number): [number, number, number, number] {
|
||||
let result: [number, number, number, number] = [0, 0, 0, 0];
|
||||
let screenScale = 1;
|
||||
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) / 2;
|
||||
let top = (screenScale * scale * this.height - this.componentHeight) / 2;
|
||||
top = Math.max(top, 0);
|
||||
left = Math.max(left, 0);
|
||||
result = [-left, left, -top, top];
|
||||
Log.info(TAG, `evaluateOffsetRange scale: ${scale}, defaultScale: ${this.defaultScale}, result: ${result}`);
|
||||
return result;
|
||||
}
|
||||
|
||||
private emitPullDownToBackEvent(): void {
|
||||
Log.debug(TAG, `emitPullDownToBackEvent`);
|
||||
if (this.isExiting) {
|
||||
Log.info(TAG, `emitPullDownToBack isExiting: ${this.isExiting}`);
|
||||
return;
|
||||
}
|
||||
this.isExiting = true;
|
||||
Log.info(TAG, `emitPullDownToBack change isExiting into: ${this.isExiting}`);
|
||||
this.broadCast.emit(PhotoConstants.PULL_DOWN_END, []);
|
||||
ReportToBigDataUtil.report(BigDataConstants.PHOTO_PULL_DOWN_ID, null);
|
||||
}
|
||||
|
||||
private emitPullUpToDisplayEvent(): void {
|
||||
Log.debug(TAG, 'emitPullUpToDisplayEvent');
|
||||
if (!this.canTouch()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private emitPullDownCancelEvent(): void {
|
||||
Log.debug(TAG, 'emitPullDownCancelEvent');
|
||||
this.broadCast.emit(PhotoConstants.PULL_DOWN_CANCEL, []);
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算当前缩放中心相对控件的百分比位置
|
||||
*
|
||||
* @param centerX 触摸点在屏幕上的绝对位置
|
||||
* @param centerY 触摸点在屏幕上的绝对位置
|
||||
* @returns 当前缩放中心相对控件的百分比位置
|
||||
*/
|
||||
private evaluateCenter(centerX: number, centerY: number): [number, number] {
|
||||
// 计算出控件左上角相对于当前显示左上角的坐标
|
||||
let scale = this.lastScale * this.scale;
|
||||
let leftTop = this.evaluateCompBounds();
|
||||
|
||||
// 得出相对于控件的触摸坐标
|
||||
let cxRelativeToComp = MathUtil.clamp((centerX - leftTop[0]) / (this.componentWidth * scale), this.leftMost, 1 - this.leftMost);
|
||||
let cyRelativeToComp = MathUtil.clamp((centerY - leftTop[1]) / (this.componentHeight * scale), this.topMost, 1 - this.topMost);
|
||||
|
||||
let imgDisplaySize: [number, number] = this.evaluateImgDisplaySize();
|
||||
let imgDisplayWidth = imgDisplaySize[0];
|
||||
let imgDisplayHeight = imgDisplaySize[1];
|
||||
|
||||
let imgDisplayBounds = this.evaluateImgDisplayBounds();
|
||||
let imgLeftBound = imgDisplayBounds[0];
|
||||
let imgTopBound = imgDisplayBounds[1];
|
||||
|
||||
// 触摸中心点在图片显示区域外时,取中点
|
||||
if (this.width / this.height > this.componentWidth / this.componentHeight) {
|
||||
if (centerY < imgTopBound || centerY > imgTopBound + imgDisplayHeight) {
|
||||
cyRelativeToComp = 0.5;
|
||||
}
|
||||
} else {
|
||||
if (centerX < imgLeftBound || centerX > imgLeftBound + imgDisplayWidth) {
|
||||
cxRelativeToComp = 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
// 算出触摸的中心点百分比
|
||||
let center: [number, number] = [cxRelativeToComp, cyRelativeToComp];
|
||||
Log.info(TAG, `evaluateCenter center: ${center}, ${[centerX, centerY]}, size: ${imgDisplaySize}, bounds: ${imgDisplayBounds}, leftTop: ${leftTop}, compSize: ${[this.componentWidth * scale, this.componentHeight * scale]}`);
|
||||
return center;
|
||||
}
|
||||
|
||||
private evaluateAnimeMatrix(scale: number, center: [number, number]): Matrix4.Matrix4Transit {
|
||||
let offset = [
|
||||
this.lastOffset[0] + this.offset[0] + (center[0] - 0.5) * this.componentWidth * (this.defaultScale - scale / this.lastScale) * this.lastScale,
|
||||
this.lastOffset[1] + this.offset[1] + (center[1] - 0.5) * this.componentHeight * (this.defaultScale - scale / this.lastScale) * this.lastScale
|
||||
]
|
||||
if (Number(scale.toFixed(PhotoConstants.RESERVED_DIGITS)) > Number(this.defaultScale.toFixed(PhotoConstants.RESERVED_DIGITS))) {
|
||||
let limits = this.evaluateOffsetRange(scale);
|
||||
offset[0] = MathUtil.clamp(offset[0], limits[0], limits[1]);
|
||||
// 非缩小场景,始终限制x方向上的offset
|
||||
offset[0] = MathUtil.clamp(offset[0], limits[0], limits[1]);
|
||||
if (Number(scale.toFixed(PhotoConstants.RESERVED_DIGITS)) > Number(this.defaultScale.toFixed(PhotoConstants.RESERVED_DIGITS))) {
|
||||
// 不可下拉返回场景,限制y
|
||||
offset[1] = MathUtil.clamp(offset[1], limits[PhotoConstants.NUMBER_2], limits[PhotoConstants.NUMBER_3]);
|
||||
} else {
|
||||
// 可下拉返回场景,只限制y向上拖动,即限制下界
|
||||
offset[1] = Math.max(limits[PhotoConstants.NUMBER_2], offset[1]);
|
||||
}
|
||||
} else {
|
||||
// 缩小时调整缩放中心为显示中心点
|
||||
offset = [0, 0];
|
||||
}
|
||||
let animationEndMatrix = Matrix4.identity().copy().scale({
|
||||
x: scale,
|
||||
y: scale,
|
||||
}).translate({
|
||||
x: offset[0],
|
||||
y: offset[1]
|
||||
}).copy();
|
||||
Log.debug(TAG, `evaluateAnimeMatrix scale: ${scale}, center: ${center}, result: ${animationEndMatrix}`);
|
||||
return animationEndMatrix;
|
||||
}
|
||||
}
|
83
common/src/main/ets/default/model/browser/photo/FifoCache.ts
Normal file
83
common/src/main/ets/default/model/browser/photo/FifoCache.ts
Normal file
@ -0,0 +1,83 @@
|
||||
/*
|
||||
* 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 { Log } from '../../../utils/Log';
|
||||
import type { Releasable } from '../../common/Releasable';
|
||||
|
||||
const TAG: string = 'common_FifoCache';
|
||||
|
||||
export class FifoCache<T extends Releasable> {
|
||||
map: Map<string, T> = new Map<string, T>();
|
||||
pendingSet: Set<string> = new Set<string>();
|
||||
limit: number;
|
||||
|
||||
constructor(limit: number) {
|
||||
this.limit = limit || 5;
|
||||
}
|
||||
|
||||
set(key: string, value: T) {
|
||||
if (this.pendingSet.has(key)) {
|
||||
this.pendingSet.delete(key);
|
||||
Log.debug(TAG, `FifoCache add new pixmap: ${key} ${this.map.size}`);
|
||||
if (this.map.has(key)) {
|
||||
Log.debug(TAG, `FifoCache has same pixmap value: ${key} ${this.map.size}`);
|
||||
value.release();
|
||||
return;
|
||||
}
|
||||
this.map.set(key, value);
|
||||
} else {
|
||||
Log.error(TAG, `FifoCache add new pixmap failed because pending set don't have it: ${key}`);
|
||||
value.release();
|
||||
}
|
||||
}
|
||||
|
||||
addPendingPixmap(key: string): boolean {
|
||||
Log.debug(TAG, `FifoCache add pending pixmap: ${key} ${this.pendingSet.size}`);
|
||||
if (!this.pendingSet.has(key)) {
|
||||
this.pendingSet.add(key);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
get(key: string): T {
|
||||
Log.debug(TAG, `get: ${key} map size: ${this.map.size}`);
|
||||
if (this.map.has(key)) {
|
||||
return this.map.get(key);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
release(key: string): void {
|
||||
Log.debug(TAG, `release: ${key}`);
|
||||
if (this.pendingSet.has(key)) {
|
||||
this.pendingSet.delete(key);
|
||||
}
|
||||
if (this.map.has(key)) {
|
||||
let value = this.map.get(key);
|
||||
value.release();
|
||||
this.map.delete(key);
|
||||
}
|
||||
}
|
||||
|
||||
releaseAll(): void {
|
||||
Log.debug(TAG, 'release all');
|
||||
this.map.forEach((item) => {
|
||||
item.release();
|
||||
})
|
||||
this.map.clear();
|
||||
this.pendingSet.clear();
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (c) 2023 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 type { AsyncCallback } from '../../common/AsyncCallback';
|
||||
import type { MediaDataSource } from './MediaDataSource';
|
||||
import { Log } from '../../../utils/Log';
|
||||
import { TraceControllerUtils } from '../../../utils/TraceControllerUtils';
|
||||
|
||||
const TAG: string = 'common_GetItemIndexCallback';
|
||||
|
||||
export class GetItemIndexCallback implements AsyncCallback<number> {
|
||||
source: MediaDataSource;
|
||||
requestTime: number;
|
||||
indexNotifyCallback: Function;
|
||||
|
||||
constructor(source: MediaDataSource, indexNotifyCallback: Function) {
|
||||
this.source = source;
|
||||
this.requestTime = Date.now();
|
||||
this.indexNotifyCallback = indexNotifyCallback;
|
||||
TraceControllerUtils.startTraceWithTaskId('getMediaItemIndex', this.requestTime);
|
||||
}
|
||||
|
||||
callback(index: number): void {
|
||||
TraceControllerUtils.finishTraceWithTaskId('getMediaItemIndex', this.requestTime);
|
||||
Log.info(TAG, `GetItemIndex finish: index=${index}`);
|
||||
this.indexNotifyCallback(index);
|
||||
}
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* 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 type { AsyncCallback } from '../../common/AsyncCallback';
|
||||
import { MediaItem } from './MediaItem';
|
||||
import { MediaDataSource } from './MediaDataSource';
|
||||
import { Log } from '../../../utils/Log';
|
||||
import { TraceControllerUtils } from '../../../utils/TraceControllerUtils';
|
||||
|
||||
const TAG: string = 'common_GetItemsCallback';
|
||||
|
||||
export class GetItemsCallback implements AsyncCallback<MediaItem[]> {
|
||||
source: MediaDataSource;
|
||||
requestTime: number;
|
||||
start: number;
|
||||
|
||||
constructor(source: MediaDataSource, start: number) {
|
||||
this.source = source;
|
||||
this.requestTime = Date.now();
|
||||
this.start = start;
|
||||
TraceControllerUtils.startTraceWithTaskId('getMediaItems', this.requestTime);
|
||||
}
|
||||
|
||||
callback(assets: MediaItem[]) {
|
||||
TraceControllerUtils.finishTraceWithTaskId('getMediaItems', this.requestTime);
|
||||
Log.info(TAG, `took ${Date.now() - this.requestTime} milliseconds to load data: ${assets.length}`);
|
||||
this.source.updateMediaData(this.requestTime, this.start, assets);
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (c) 2022 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import type { AsyncCallback } from '../../common/AsyncCallback';
|
||||
import { MediaDataSource } from './MediaDataSource';
|
||||
import { Log } from '../../../utils/Log';
|
||||
import { TraceControllerUtils } from '../../../utils/TraceControllerUtils';
|
||||
|
||||
const TAG: string = 'common_GetMediaCountCallback';
|
||||
|
||||
// DataSource request media photo quantity callback
|
||||
export class GetMediaCountCallback implements AsyncCallback<number> {
|
||||
source: MediaDataSource;
|
||||
requestTime: number;
|
||||
|
||||
// source: MediaDataSource
|
||||
constructor(source: MediaDataSource) {
|
||||
this.source = source;
|
||||
this.requestTime = Date.now();
|
||||
TraceControllerUtils.startTraceWithTaskId('getMediaCount', this.requestTime);
|
||||
}
|
||||
|
||||
// Data callback
|
||||
callback(count: number) {
|
||||
TraceControllerUtils.finishTraceWithTaskId('getMediaCount', this.requestTime);
|
||||
this.source.updateMediaCount(this.requestTime, count);
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user