Signed-off-by: Fanny <liujuan76@h-partners.com>

Changes to be committed:
This commit is contained in:
Fanny 2023-06-28 15:54:53 +08:00
parent d463ea09ca
commit bc35c9b6b8
799 changed files with 45149 additions and 31449 deletions

23
.gitignore vendored
View File

@ -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

View File

@ -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

View File

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
View File

@ -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>

View File

@ -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"
]
}
]
},
],
}

View File

@ -1,3 +1,4 @@
/node_modules
/.preview
/build
/oh_modules

View File

@ -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

View File

@ -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"
}

View File

@ -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') })
}
}

View File

@ -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();
}
}))
}
}

View File

@ -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%')
}
}

View File

@ -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'))
})
}
}

View File

@ -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;
}
})
}
}

View File

@ -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;
}

View File

@ -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';
}

View File

@ -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';
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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();
}
}

View File

@ -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);

View File

@ -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);
}
}

View File

@ -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
}
}

View File

@ -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;
}
}
}

View File

@ -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);

View File

@ -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;
}

View File

@ -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);

View File

@ -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();

View File

@ -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;
}
// Unitvp
getWinWidth(): number {
return px2vp(this.winWidth);
}
setWinWidth(width: number): void {
this.winWidth = width;
}
// Unitvp
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);

View File

@ -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);

View File

@ -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');
}
}

View File

@ -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;
}
}

View File

@ -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]);
}
}
}
}

View File

@ -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);

View File

@ -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);

View File

@ -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);
}
}

View File

@ -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');
}
}

View File

@ -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();
})
}
}

View File

@ -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();
}
}

View File

@ -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();
}
}

View File

@ -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;
}
}

View File

@ -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();
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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();
}
}

View File

@ -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);
}

View File

@ -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();
}
}

View File

@ -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);

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -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);
}
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}
}

View File

@ -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);
})
}
}

View File

@ -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"
}
]
}

View File

@ -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"
}
]
}

View File

@ -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"
}
]
}

View File

@ -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 个文件?"
}
]
}

View File

@ -1,12 +0,0 @@
{
"string": [
{
"name": "yes",
"value": "[CJ_874431]_OK"
},
{
"name": "no",
"value": "[CJ_874432]_Cancel"
}
]
}

View File

@ -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
View 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';

View File

@ -1,5 +1,5 @@
{
"name": "@ohos/base",
"name": "@ohos/common",
"version": "1.0.0",
"lockfileVersion": 1
}

13
common/package.json Normal file
View 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"
}

View 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;
}
}

View 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;
}
}

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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;
}

View File

@ -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);
}
}

View 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();
}
}
}
}

View 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;
}
}

View 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;
}
}
}

View File

@ -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);
}
}

View File

@ -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;
}

View 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();
}
}
}

View File

@ -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,
}

View 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');
}
}

View 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}`;
}
}

View File

@ -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 {
}
}

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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!');
}
}
}

View 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;
}

View 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小于等于1doubleTapScalescale大于11
*
* @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>1scale<=1reachLeftreachRight必然为true
* T T TVertical
* T T FVertical
* T F TVertical | Left
* F T TVertical | Right
* F F TAll
*/
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_FACTORmaxScale
* doubleTapScale * PhotoConstants.MAX_SCALE_EXTRA_FACTOR
* 2. doubleTapScale
* 使PhotoConstants.SAME_RATIO_SCALE_FACTOR4/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;
}
}

View 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();
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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