!4862 medialibrary sample

Merge pull request !4862 from lumingfei(zhouhui)/master
This commit is contained in:
openharmony_ci 2024-10-24 06:45:53 +00:00 committed by Gitee
commit 6e7c69efd0
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
15 changed files with 665 additions and 21 deletions

View File

@ -16,9 +16,9 @@
1. 主界面:查询显示所有照片、系统相册(相机/视频/截屏录屏/动态照片/我的收藏/最近删除)、用户相册 1. 主界面:查询显示所有照片、系统相册(相机/视频/截屏录屏/动态照片/我的收藏/最近删除)、用户相册
2. 主界面点击“+”,创建用户相册 2. 主界面点击“+”,创建用户相册
3. 创建用户相册时添加图片到用户相册 3. 创建用户相册时添加图片到用户相册
4. 长按相册,删除相册 4. 长按用户相册,删除相册
5. 长按相册,重命名相册(不可重名) 5. 长按系统相册,重命名相册(不可重名)
6. 长按相册,相册多选,批量删除 6. 长按用户相册,相册多选,批量删除
7. 点击相册,查看相册中的图片列表 7. 点击相册,查看相册中的图片列表
8. 点击图片,查看单个图片大图 8. 点击图片,查看单个图片大图
9. 点击心形图标,收藏图片 9. 点击心形图标,收藏图片
@ -29,7 +29,7 @@
14. 点击视频,查看视频并播放 14. 点击视频,查看视频并播放
15. 点击图片页面右上角叹号,查看图片详情 15. 点击图片页面右上角叹号,查看图片详情
16. 长按图片批量操作:多选/全选、删除、恢复 16. 长按图片批量操作:多选/全选、删除、恢复
17. 相册内图片列表界面点击“+”,从已有相册添加照片 17. 用户相册内图片列表界面点击“+”,从已有相册添加照片
18. 长按图片列表图片,更多菜单,从图片选择添加到已有相册 18. 长按图片列表图片,更多菜单,从图片选择添加到已有相册
19. 在相册图片列表界面,长按图片,选择图片,点击更多,可以将图片加入到其他相册(可多选) 19. 在相册图片列表界面,长按图片,选择图片,点击更多,可以将图片加入到其他相册(可多选)
20. 在用户相册图片列表界面,长按图片,选择图片,点击更多,可以将图片从当前相册移除(可多选) 20. 在用户相册图片列表界面,长按图片,选择图片,点击更多,可以将图片从当前相册移除(可多选)

View File

@ -19,8 +19,8 @@
{ {
"name": "default", "name": "default",
"signingConfig": "default", "signingConfig": "default",
"compileSdkVersion": 12, "compileSdkVersion": 14,
"compatibleSdkVersion": 12, "compatibleSdkVersion": 14,
"runtimeOS": "OpenHarmony" "runtimeOS": "OpenHarmony"
} }
] ]

View File

@ -19,7 +19,9 @@ import { userFileModel } from './UserFileModel';
import { MediaConstants } from '../constants/MediaConstants'; import { MediaConstants } from '../constants/MediaConstants';
import { selectManager } from '../common/SelectManager'; import { selectManager } from '../common/SelectManager';
import photoAccessHelper from '@ohos.file.photoAccessHelper'; import photoAccessHelper from '@ohos.file.photoAccessHelper';
import fs from '@ohos.file.fs';
import { screenManager } from '../common/ScreenManager'; import { screenManager } from '../common/ScreenManager';
import image from '@ohos.multimedia.image';
const TAG = 'UserFileDataItem'; const TAG = 'UserFileDataItem';
const STATUS_UNDEFINED = -1; const STATUS_UNDEFINED = -1;
@ -57,6 +59,9 @@ export class UserFileDataItem implements DateAdded {
selections: string = ''; selections: string = '';
selectionArgs: string[] = []; selectionArgs: string[] = [];
deviceId: string = ''; deviceId: string = '';
longitude: string = '';
latitude: string = '';
shootingParams: string = '';
fileAsset: photoAccessHelper.PhotoAsset = undefined; fileAsset: photoAccessHelper.PhotoAsset = undefined;
defaultThumbnail: PixelMap = undefined; defaultThumbnail: PixelMap = undefined;
thumbnailArray: Map<string, PixelMap> = new Map<string, PixelMap>(); thumbnailArray: Map<string, PixelMap> = new Map<string, PixelMap>();
@ -174,6 +179,21 @@ export class UserFileDataItem implements DateAdded {
} else { } else {
this.status = MediaConstants.PART_LOADED; this.status = MediaConstants.PART_LOADED;
} }
this.getExif(fileAsset);
}
async getExif(fileAsset: photoAccessHelper.PhotoAsset): Promise<void> {
let file = await fs.open(fileAsset.uri);
let imageSourceApi: image.ImageSource = image.createImageSource(file.fd);
this.latitude = await imageSourceApi.getImageProperty(image.PropertyKey.GPS_LATITUDE);
this.longitude = await imageSourceApi.getImageProperty(image.PropertyKey.GPS_LONGITUDE);
let light = await imageSourceApi.getImageProperty(image.PropertyKey.EXPOSURE_TIME);
let fNumber = await imageSourceApi.getImageProperty(image.PropertyKey.F_NUMBER);
let photographicSensitivity = await imageSourceApi.getImageProperty(
image.PropertyKey.PHOTOGRAPHIC_SENSITIVITY);
this.shootingParams = 'F_NUMBER ' + fNumber +
' PHOTOGRAPHIC_SENSITIVITY ' + photographicSensitivity +
' EXPOSURE_TIME ' + light;
} }
async getThumbnail(width: number, height: number): Promise<PixelMap> { async getThumbnail(width: number, height: number): Promise<PixelMap> {
@ -255,6 +275,15 @@ export class UserFileDataItem implements DateAdded {
return this.favouriteStatus === STATUS_TRUE; return this.favouriteStatus === STATUS_TRUE;
} }
async isVideo(): Promise<boolean> {
let fileAsset = await this.loadFileAsset();
this.mediaType = fileAsset.photoType;
if (this.mediaType === photoAccessHelper.PhotoType.VIDEO) {
return true;
}
return false;
}
async setFavor(): Promise<boolean> { async setFavor(): Promise<boolean> {
let status = !(await this.isFavor()); let status = !(await this.isFavor());
try { try {

View File

@ -23,6 +23,7 @@ import dataSharePredicates from '@ohos.data.dataSharePredicates';
import { MediaConstants } from '../constants/MediaConstants' import { MediaConstants } from '../constants/MediaConstants'
import { getSystemAlbumDisplayName } from './UserFileDataHelper'; import { getSystemAlbumDisplayName } from './UserFileDataHelper';
import { SimpleAlbumDataItem } from '../common/SimpleAlbumDataItem'; import { SimpleAlbumDataItem } from '../common/SimpleAlbumDataItem';
import bundleManager from '@ohos.bundle.bundleManager';
const TAG = 'UserFileModel'; const TAG = 'UserFileModel';
@ -535,6 +536,15 @@ class UserFileModel {
Log.error(TAG, 'addPhotoAssetsDemoPromise failed with error: ' + err); Log.error(TAG, 'addPhotoAssetsDemoPromise failed with error: ' + err);
} }
} }
async hideSensitives(type: number, uris: string[]): Promise<void> {
let flags = bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_SIGNATURE_INFO;
let bundleInfo = bundleManager.getBundleInfoForSelfSync(flags);
let appId = bundleInfo.signatureInfo.appId;
for (let uri of uris) {
await this.userFileMgr.grantPhotoUriPermission(appId, uri, 1, type);
}
}
} }
export let userFileModel: UserFileModel = stashOrGetObject<UserFileModel>(new UserFileModel(), TAG); export let userFileModel: UserFileModel = stashOrGetObject<UserFileModel>(new UserFileModel(), TAG);

View File

@ -33,6 +33,8 @@ import { NewAlbumDialog } from './NewAlbumDialog';
import { FindSameNameDialog, FindSameNameParam } from './FindSameNameDialog'; import { FindSameNameDialog, FindSameNameParam } from './FindSameNameDialog';
import { screenManager } from '../common/ScreenManager'; import { screenManager } from '../common/ScreenManager';
import { SaveImageDialog } from './SaveImageDialog'; import { SaveImageDialog } from './SaveImageDialog';
import { SelectSensitiveDialog } from './SelectSensitiveDialog';
import { TransCodingDialog } from './TransCodingDialog';
const TAG: string = 'CustomDialogView' const TAG: string = 'CustomDialogView'
@ -52,6 +54,7 @@ export struct CustomDialogView {
@Provide findSameNameParam: FindSameNameParam = new FindSameNameParam(); @Provide findSameNameParam: FindSameNameParam = new FindSameNameParam();
@Provide cancelMessage: Resource = $r('app.string.common_place_holder', String('')); @Provide cancelMessage: Resource = $r('app.string.common_place_holder', String(''));
@Provide renameFileName: string = ''; @Provide renameFileName: string = '';
@Provide uris: string[] = [];
@Provide mediaDetails: MediaDetails = { @Provide mediaDetails: MediaDetails = {
mediaType: 0, mediaType: 0,
height: 0, height: 0,
@ -64,7 +67,9 @@ export struct CustomDialogView {
dateAdded: 0, dateAdded: 0,
uri: '', uri: '',
displayName: '', displayName: '',
dateModified: 0 dateModified: 0,
location: '',
shootingParams: ''
}; };
@Provide targetMediaDetails: MediaDetails = { @Provide targetMediaDetails: MediaDetails = {
mediaType: 0, mediaType: 0,
@ -78,7 +83,9 @@ export struct CustomDialogView {
dateAdded: 0, dateAdded: 0,
uri: '', uri: '',
displayName: '', displayName: '',
dateModified: 0 dateModified: 0,
location: '',
shootingParams: ''
}; };
@Provide multiSelectDetails: MultiSelectDetails = { @Provide multiSelectDetails: MultiSelectDetails = {
count: 0, count: 0,
@ -98,6 +105,8 @@ export struct CustomDialogView {
newAlbumDialogController?: CustomDialogController ; newAlbumDialogController?: CustomDialogController ;
findSameNameDialog?: CustomDialogController ; findSameNameDialog?: CustomDialogController ;
saveImageDialogController?: CustomDialogController ; saveImageDialogController?: CustomDialogController ;
sensitiveDialogController?: CustomDialogController ;
transCodingFileDialogController?: CustomDialogController ;
aboutToDisappear(): void { aboutToDisappear(): void {
Log.info(TAG, 'aboutToDisappear'); Log.info(TAG, 'aboutToDisappear');
@ -113,6 +122,7 @@ export struct CustomDialogView {
this.newAlbumDialogController = undefined; this.newAlbumDialogController = undefined;
this.findSameNameDialog = undefined; this.findSameNameDialog = undefined;
this.saveImageDialogController = undefined; this.saveImageDialogController = undefined;
this.sensitiveDialogController = undefined;
} }
aboutToAppear(): void { aboutToAppear(): void {
@ -128,6 +138,16 @@ export struct CustomDialogView {
}, },
customStyle: true customStyle: true
}); });
this.sensitiveDialogController = new CustomDialogController({
builder: SelectSensitiveDialog(),
autoCancel: false,
alignment: this.isHorizontal || this.isSidebar ? DialogAlignment.Center : DialogAlignment.Bottom,
offset: {
dx: 0,
dy: this.isHorizontal || this.isSidebar ? 0 : $r('app.float.dialog_offset_bottom')
},
customStyle: true
});
this.multiSelectDialog = new CustomDialogController({ this.multiSelectDialog = new CustomDialogController({
builder: MultiSelectDialog(), builder: MultiSelectDialog(),
autoCancel: false, autoCancel: false,
@ -188,6 +208,16 @@ export struct CustomDialogView {
}, },
customStyle: true customStyle: true
}); });
this.transCodingFileDialogController = new CustomDialogController({
builder: TransCodingDialog(),
autoCancel: false,
alignment: this.isHorizontal || this.isSidebar ? DialogAlignment.Center : DialogAlignment.Bottom,
offset: {
dx: 0,
dy: this.isHorizontal || this.isSidebar ? 0 : $r('app.float.dialog_offset_bottom')
},
customStyle: true
});
this.saveDialogController = new CustomDialogController({ this.saveDialogController = new CustomDialogController({
builder: SaveDialog(), builder: SaveDialog(),
autoCancel: false, autoCancel: false,
@ -231,6 +261,16 @@ export struct CustomDialogView {
this.showDetailDialog(item) this.showDetailDialog(item)
}); });
this.broadCast.on(BroadcastConstants.SHOW_SENSITIVE_DIALOG,
(items: UserFileDataItem[]): void => {
let uris: string[] = [];
for (let item of items) {
uris.push(item.uri);
}
self.uris = uris;
self.sensitiveDialogController?.open();
});
this.broadCast.on(BroadcastConstants.SHOW_MULTI_SELECT_DIALOG, this.broadCast.on(BroadcastConstants.SHOW_MULTI_SELECT_DIALOG,
(count: number, size: number): void => { (count: number, size: number): void => {
Log.info(TAG, 'SHOW_MULTI_SELECT_DIALOG '); Log.info(TAG, 'SHOW_MULTI_SELECT_DIALOG ');
@ -258,6 +298,13 @@ export struct CustomDialogView {
self.renameFileDialogController?.open(); self.renameFileDialogController?.open();
}); });
this.broadCast.on(BroadcastConstants.SHOW_TRANS_CODING_DIALOG,
(fileName: string, confirmCallback: Function, cancelCallback?: Function): void => {
Log.info(TAG, 'SHOW_TRANS_CODING_DIALOG ');
self.renameFileName = fileName;
self.dialogCallback = { confirmCallback: confirmCallback, cancelCallback: cancelCallback };
self.transCodingFileDialogController?.open();
});
this.broadCast.on(BroadcastConstants.SHOW_ADD_NOTES_PHOTO_DIALOG, this.broadCast.on(BroadcastConstants.SHOW_ADD_NOTES_PHOTO_DIALOG,
(confirmCallback: Function, cancelCallback?: Function): void => { (confirmCallback: Function, cancelCallback?: Function): void => {
Log.info(TAG, 'SHOW_ADD_NOTES_PHOTO_DIALOG '); Log.info(TAG, 'SHOW_ADD_NOTES_PHOTO_DIALOG ');
@ -365,7 +412,9 @@ export struct CustomDialogView {
dateAdded: item.dateAdded, dateAdded: item.dateAdded,
uri: item.uri, uri: item.uri,
displayName: item.displayName, displayName: item.displayName,
dateModified: item.dateModified dateModified: item.dateModified,
location: 'longitude ' + item.longitude + ' latitude ' + item.latitude,
shootingParams: item.shootingParams
}; };
this.dialogController?.open(); this.dialogController?.open();
}) })

View File

@ -33,6 +33,8 @@ export class MediaDetails {
uri: string = ''; uri: string = '';
displayName: string = ''; displayName: string = '';
dateModified: number = 0; dateModified: number = 0;
location: string = '';
shootingParams: string = '';
} }
@CustomDialog @CustomDialog
@ -161,6 +163,42 @@ export struct DetailsDialog {
}.margin({ }.margin({
bottom: $r('sys.float.ohos_id_text_paragraph_margin_s') }) bottom: $r('sys.float.ohos_id_text_paragraph_margin_s') })
Row() {
Column() {
Text($r('app.string.location'))
.fontSize($r('sys.float.ohos_id_text_size_body2'))
.fontFamily($r('app.string.id_text_font_family_regular'))
.fontColor($r('sys.color.ohos_id_color_text_primary'))
}
Column() {
Text(this.mediaDetails.location)
.fontSize($r('sys.float.ohos_id_text_size_body2'))
.fontFamily($r('app.string.id_text_font_family_regular'))
.fontColor($r('sys.color.ohos_id_color_text_secondary'))
.textOverflow({ overflow: TextOverflow.Ellipsis })
}
}.margin({
bottom: $r('sys.float.ohos_id_text_paragraph_margin_s') })
Row() {
Column() {
Text($r('app.string.shooting_params'))
.fontSize($r('sys.float.ohos_id_text_size_body2'))
.fontFamily($r('app.string.id_text_font_family_regular'))
.fontColor($r('sys.color.ohos_id_color_text_primary'))
}
Column() {
Text(this.mediaDetails.shootingParams)
.fontSize($r('sys.float.ohos_id_text_size_body2'))
.fontFamily($r('app.string.id_text_font_family_regular'))
.fontColor($r('sys.color.ohos_id_color_text_secondary'))
.textOverflow({ overflow: TextOverflow.Ellipsis })
}
}.margin({
bottom: $r('sys.float.ohos_id_text_paragraph_margin_s') })
if (this.mediaDetails.mediaType === userFileManager.FileType.VIDEO) { if (this.mediaDetails.mediaType === userFileManager.FileType.VIDEO) {
Row() { Row() {
Column() { Column() {

View File

@ -0,0 +1,118 @@
/*
* Copyright (c) 2024 Shenzhen Kaihong Digital Industry Development 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 { screenManager } from '../common/ScreenManager';
import { Constants } from '../constants/Constants';
import { userFileModel } from '../base/UserFileModel';
const TAG: string = 'SelectSensitiveDialog';
@CustomDialog
export struct SelectSensitiveDialog {
@StorageLink('isHorizontal') isHorizontal: boolean = screenManager.isHorizontal();
@StorageLink('isSidebar') isSidebar: boolean = screenManager.isSidebar();
@StorageLink('leftBlank') leftBlank: number[] = [0, 0, 0, 0];
controller?: CustomDialogController ;
@Consume uris: string[];
aboutToAppear(): void {
}
getResolution(height: number, width: number): string {
return width + 'x' + height;
}
hideSensitive(type: number): void {
if (this.uris.length === 0) {
Log.warn(TAG, 'uris is empty');
return;
} else {
userFileModel.hideSensitives(type, this.uris);
}
}
build() {
Column() {
Button() {
Text($r('app.string.hide_location_and_shootingparam'))
.fontSize($r('sys.float.ohos_id_text_size_button1'))
.fontColor($r('app.color.color_control_highlight'))
.width('100%')
.textAlign(TextAlign.Center)
.fontWeight(FontWeight.Medium)
}
.backgroundColor($r('app.color.transparent'))
.height($r('app.float.details_dialog_button_height'))
.onClick((): void => {
this.hideSensitive(0);
this.controller?.close();
})
Button() {
Text($r('app.string.hide_location_only'))
.fontSize($r('sys.float.ohos_id_text_size_button1'))
.fontColor($r('app.color.color_control_highlight'))
.width('100%')
.textAlign(TextAlign.Center)
.fontWeight(FontWeight.Medium)
}
.backgroundColor($r('app.color.transparent'))
.height($r('app.float.details_dialog_button_height'))
.onClick((): void => {
this.hideSensitive(1);
this.controller?.close();
})
Button() {
Text($r('app.string.hide_shootingparam_only'))
.fontSize($r('sys.float.ohos_id_text_size_button1'))
.fontColor($r('app.color.color_control_highlight'))
.width('100%')
.textAlign(TextAlign.Center)
.fontWeight(FontWeight.Medium)
}
.backgroundColor($r('app.color.transparent'))
.height($r('app.float.details_dialog_button_height'))
.onClick((): void => {
this.hideSensitive(2);
this.controller?.close();
})
Button() {
Text($r('app.string.no_hide_sensitive_type'))
.fontSize($r('sys.float.ohos_id_text_size_button1'))
.fontColor($r('app.color.color_control_highlight'))
.width('100%')
.textAlign(TextAlign.Center)
.fontWeight(FontWeight.Medium)
}
.backgroundColor($r('app.color.transparent'))
.height($r('app.float.details_dialog_button_height'))
.onClick((): void => {
this.hideSensitive(3);
this.controller?.close();
})
}
.borderRadius($r('app.float.dialog_border_radius'))
.width(screenManager.getColumnsWidth(4))
.backgroundColor($r('app.color.white'))
.margin({
right: $r('app.float.dialog_window_margin'),
left: $r('app.float.dialog_window_margin'),
bottom: this.isHorizontal || this.isSidebar ? 0 : Constants.DIALOG_BOTTOM_OFFSET + px2vp(this.leftBlank[3])
})
.padding({ left: $r('app.float.dialog_content_margin'), right: $r('app.float.dialog_content_margin') })
.alignItems(HorizontalAlign.Start)
}
}

View File

@ -0,0 +1,135 @@
/*
* Copyright (c) 2024 Shenzhen Kaihong Digital Industry Development 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 { DialogCallback } from '../utils/DialogUtil';
import { screenManager } from '../common/ScreenManager';
import { Constants } from '../constants/Constants';
const TAG: string = 'TransCodingDialog';
@CustomDialog
export struct TransCodingDialog {
@StorageLink('isHorizontal') isHorizontal: boolean = screenManager.isHorizontal();
@StorageLink('isSidebar') isSidebar: boolean = screenManager.isSidebar();
@StorageLink('leftBlank') leftBlank: number[] = [0, 0, 0, 0];
controller?: CustomDialogController ;
@Consume renameFileName: string;
@Consume dialogCallback: DialogCallback;
@State isNull: boolean = false;
@State dividerColor: Resource = $r('app.color.dialog_divider_h_color_182431');
@State dividerWidth: string = '1vp';
@State showProgressNum: number = 0;
@State transCodingResult: boolean = false;
@State fileUri: string = '';
aboutToAppear(): void {
Log.info(TAG, 'aboutToAppear');
}
build() {
Column() {
if(this.transCodingResult === true) {
Column() {
Text($r('app.string.action_transcoding_path')).fontSize(16)
Text(`${this.fileUri}`).fontSize(16)
Text($r('app.string.action_transcoding_success')).fontSize(30)
}.justifyContent(FlexAlign.Center).padding($r('app.float.crop_vertical_padding'))
}
if(this.showProgressNum !== 0 && this.transCodingResult !== true) {
Row() {
Text($r('app.string.action_transcoding_progress')).fontSize(20)
Text(`: ${this.showProgressNum}` + ' %').fontSize(20)
}.justifyContent(FlexAlign.Center)
.alignItems(VerticalAlign.Center)
}
Stack({ alignContent: Alignment.Top }) {
Row() {
Button() {
Text($r('app.string.no'))
.fontSize($r('sys.float.ohos_id_text_size_button1'))
.fontColor($r('app.color.color_control_highlight'))
.fontWeight(FontWeight.Medium)
.width('50%')
.textAlign(TextAlign.Center)
}
.margin({ right: $r('app.float.details_dialog_button_margin_right') })
.backgroundColor($r('app.color.transparent'))
.height($r('app.float.details_dialog_button_height'))
.onClick((): void => {
if (this.dialogCallback?.cancelCallback !== undefined) {
this.dialogCallback.cancelCallback();
};
this.controller?.close();
})
Row() {
Divider()
.vertical(true)
.height($r('app.float.dialog_divider_height'))
.color($r('app.color.divider_vertical_color'))
}.height($r('app.float.details_dialog_button_height'))
.alignItems(VerticalAlign.Center)
Button() {
Text($r('app.string.action_transcoding'))
.fontSize($r('sys.float.ohos_id_text_size_button1'))
.fontColor($r('app.color.color_control_highlight'))
.fontWeight(FontWeight.Medium)
.width('50%')
.textAlign(TextAlign.Center)
}
.enabled(!this.isNull)
.opacity(this.isNull ? $r('app.float.disable_button_opacity') : 1)
.margin({ right: $r('app.float.details_dialog_button_margin_left') })
.backgroundColor($r('app.color.transparent'))
.height($r('app.float.details_dialog_button_height'))
.onClick((): void => {
if (this.dialogCallback != null && this.dialogCallback.confirmCallback !== null) {
const fileUri = (uri: string) => {
this.fileUri = uri;
Log.info(TAG, 'fileUri uri:' + uri);
};
const transCodingResult = (result: boolean) => {
this.transCodingResult = result;
Log.info(TAG, 'Transcoding Result:' + result);
};
const showProgressNum = (progress: number) => {
this.showProgressNum = progress;
Log.info(TAG, 'Progress:' + progress);
};
this.dialogCallback.confirmCallback(fileUri, transCodingResult, showProgressNum);
}
})
}
}
.height($r('app.float.details_dialog_button_area_height'))
.margin({
left: $r('app.float.dialog_content_margin'), right: $r('app.float.dialog_content_margin')
})
}
.alignItems(HorizontalAlign.Start)
.borderRadius($r('app.float.dialog_border_radius'))
.width(screenManager.getColumnsWidth(4))
.backgroundColor($r('app.color.white'))
.margin({
right: $r('app.float.dialog_window_margin'),
left: $r('app.float.dialog_window_margin'),
bottom: this.isHorizontal || this.isSidebar ? 0 : Constants.DIALOG_BOTTOM_OFFSET + px2vp(this.leftBlank[3])
})
}
}

View File

@ -28,6 +28,7 @@ export class BroadcastConstants {
static readonly ON_TAB_CHANGED = 'onTabChanged'; static readonly ON_TAB_CHANGED = 'onTabChanged';
static readonly RESET_ZERO = 'resetZero'; static readonly RESET_ZERO = 'resetZero';
static readonly SHOW_DETAIL_DIALOG = 'showDetailDialog'; static readonly SHOW_DETAIL_DIALOG = 'showDetailDialog';
static readonly SHOW_SENSITIVE_DIALOG = 'showSensitiveDialog';
static readonly SHOW_THIRD_DELETE_DIALOG = 'showThirdDeleteDialog'; static readonly SHOW_THIRD_DELETE_DIALOG = 'showThirdDeleteDialog';
static readonly SHOW_MULTI_SELECT_DIALOG = 'showMultiSelectDialog'; static readonly SHOW_MULTI_SELECT_DIALOG = 'showMultiSelectDialog';
static readonly UPDATE_DATA_SOURCE = 'updateDataSource'; static readonly UPDATE_DATA_SOURCE = 'updateDataSource';
@ -55,6 +56,7 @@ export class BroadcastConstants {
static readonly ON_DATA_RELOADED_WITH_EDIT = 'on_data_reloaded_with_edit'; 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 PHOTO_EDIT_SAVE_COMPLETE: string = 'photo_edit_save_complete';
static readonly CHANGE_SWIPER_DURATION = 'change_swiper_duration'; static readonly CHANGE_SWIPER_DURATION = 'change_swiper_duration';
static readonly SHOW_TRANS_CODING_DIALOG = 'showTranscodingDialog';
// USED for AppStorage // USED for AppStorage
static readonly LEFT_BLANK: string = 'leftBlank'; static readonly LEFT_BLANK: string = 'leftBlank';
static readonly RESET_TAB_SELECTED_STATUE: string = 'reset_tab_selected_statue'; static readonly RESET_TAB_SELECTED_STATUE: string = 'reset_tab_selected_statue';

View File

@ -0,0 +1,130 @@
/*
* Copyright (c) 2024 Shenzhen Kaihong Digital Industry Development 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 { BroadcastConstants } from '../constants/BroadcastConstants';
import { MenuOperationCallback } from './MenuOperationCallback';
import { MenuOperation } from './MenuOperation';
import { MenuContext } from './MenuContext';
import dataSharePredicates from '@ohos.data.dataSharePredicates';
import photoAccessHelper from '@ohos.file.photoAccessHelper';
const TAG = 'TranscodingMenuOperation';
export class TranscodingMenuOperation implements MenuOperation, MenuOperationCallback {
private menuContext: MenuContext;
constructor(menuContext: MenuContext) {
this.menuContext = menuContext;
}
doAction(): void {
if (this.menuContext == null) {
Log.warn(TAG, ' menuContext is null, return');
return;
}
let mediaItem = this.menuContext.items[0];
if (mediaItem == null) {
Log.warn(TAG, ' mediaItem is null, return');
return;
}
this.confirmCallback = (fileUri: Function, transCodingResult: Function, showProgressNum: Function): Promise<void> =>
this.confirmCallbackBindImpl(fileUri, transCodingResult, showProgressNum);
this.cancelCallback = (): void => this.cancelCallbackBindImpl();
let fileName = '';
if (mediaItem.title != null) {
fileName = mediaItem.title;
} else if (mediaItem.displayName != null) {
let index = mediaItem.displayName.lastIndexOf('.');
fileName = mediaItem.displayName.substr(0, index);
}
this.menuContext.broadCast.emit(BroadcastConstants.SHOW_TRANS_CODING_DIALOG,
[fileName, this.confirmCallback, this.cancelCallback]);
}
onCompleted(): void {
Log.info(TAG, ' TransCoding data succeed!');
}
onError(): void {
Log.error(TAG, ' TransCoding data failed!');
}
private async confirmCallback(fileUri: Function, transCodingResult: Function, showProgressNum: Function): Promise<void> {
this.confirmCallbackBindImpl(fileUri, transCodingResult, showProgressNum);
}
private async confirmCallbackBindImpl(fileUri: Function, transCodingResult: Function, showProgressNum: Function): Promise<void> {
let context = getContext(this);
let phAccessHelper = photoAccessHelper.getPhotoAccessHelper(context);
let predicates: dataSharePredicates.DataSharePredicates = new dataSharePredicates.DataSharePredicates();
let mediaItem = this.menuContext.items[0];
predicates.equalTo(photoAccessHelper.PhotoKeys.URI, mediaItem.uri);
let fetchOptions: photoAccessHelper.FetchOptions = {
fetchColumns: [],
predicates: predicates
};
let testHandler: photoAccessHelper.MediaAssetProgressHandler = {
onProgress: (progress: number) => {
if (progress > 0) {
showProgressNum(progress)
}
Log.info(TAG, ` Current video conversion progress: ${progress}%`);
}
};
let mediaDataHandler: photoAccessHelper.MediaAssetDataHandler<boolean> = {
onDataPrepared: (data: boolean) => {
transCodingResult(data)
Log.info(TAG, ' transCodingSuccess: ' + data);
}
}
Log.info(TAG, ' requestOptions before');
try {
let requestOptions: photoAccessHelper.RequestOptions = {
deliveryMode: photoAccessHelper.DeliveryMode.HIGH_QUALITY_MODE,
compatibleMode: photoAccessHelper.CompatibleMode.COMPATIBLE_FORMAT_MODE,
mediaAssetProgressHandler: testHandler,
}
let tempDir = context.getApplicationContext().tempDir;
let fetchResult: photoAccessHelper.FetchResult<photoAccessHelper.PhotoAsset> = await phAccessHelper.getAssets(fetchOptions);
let photoAsset: photoAccessHelper.PhotoAsset = await fetchResult.getFirstObject();
let uri = tempDir + photoAsset.displayName;
fileUri(uri)
Log.info(TAG, ' this.fileUri ' + fileUri);
await photoAccessHelper.MediaAssetManager.requestVideoFile(
context,
photoAsset,
requestOptions,
uri,
mediaDataHandler
);
} catch (err) {
Log.info(TAG, ' operation '+ err);
}
}
private cancelCallback(): void {
this.cancelCallbackBindImpl();
}
private cancelCallbackBindImpl(): void {
Log.info(TAG, ' TransCoding cancel');
}
}

View File

@ -56,7 +56,9 @@ enum ActionID {
NAVIGATION_ALBUMS, NAVIGATION_ALBUMS,
DOWNLOAD, DOWNLOAD,
DOWNLOAD_INVALID, DOWNLOAD_INVALID,
CLEAR_RECYCLE_INVALID CLEAR_RECYCLE_INVALID,
HIDE_SENSITIZATION,
TRANSCODING
} }
class ActionOptions { class ActionOptions {
@ -293,6 +295,14 @@ export class Action {
fillColor: $r('app.color.icon_disabled_color'), fillColor: $r('app.color.icon_disabled_color'),
actionType: $r('app.string.action_deRename') actionType: $r('app.string.action_deRename')
}); });
public static TRANSCODING = new Action({
id: ActionID.TRANSCODING,
iconRes: $r('app.media.ic_edit_public_redo'),
textRes: $r('app.string.action_transcoding'),
isAutoTint: null,
fillColor: null,
actionType: null
});
public static MOVE = new Action({ public static MOVE = new Action({
id: ActionID.MOVE, id: ActionID.MOVE,
iconRes: null, iconRes: null,
@ -309,6 +319,14 @@ export class Action {
fillColor: $r('app.color.icon_disabled_color'), fillColor: $r('app.color.icon_disabled_color'),
actionType: null actionType: null
}); });
public static HIDE_SENSITIZATION = new Action({
id: ActionID.HIDE_SENSITIZATION,
iconRes: null,
textRes: $r('app.string.action_hide_sensitization'),
isAutoTint: null,
fillColor: null,
actionType: null
});
public static REMOVE = new Action({ public static REMOVE = new Action({
id: ActionID.REMOVE, id: ActionID.REMOVE,
iconRes: null, iconRes: null,

View File

@ -55,6 +55,7 @@ import { getAlbumDisplayName } from '../base/UserFileDataHelper';
import { startAbility, terminateSelf } from '../utils/AbilityUtils'; import { startAbility, terminateSelf } from '../utils/AbilityUtils';
import { userFileDataItemCache } from '../base/UserFileDataItemCache'; import { userFileDataItemCache } from '../base/UserFileDataItemCache';
import { GlobalContext } from '../common/GlobalContext'; import { GlobalContext } from '../common/GlobalContext';
import { TranscodingMenuOperation } from '../menus/TranscodingMenuOperation';
// page of large photo // page of large photo
const TAG = 'PhotoBrowser'; const TAG = 'PhotoBrowser';
@ -177,10 +178,25 @@ struct PhotoBrowser {
.withBroadCast(this.broadCast) .withBroadCast(this.broadCast)
.withAlbumInfo(this.albumInfo); .withAlbumInfo(this.albumInfo);
menuOperation = new RenameMenuOperation(menuContext); menuOperation = new RenameMenuOperation(menuContext);
} else if (action === Action.TRANSCODING) {
if (currentPhoto == undefined) {
return;
}
menuContext.withItems([currentPhoto])
.withBroadCast(this.broadCast)
.withAlbumInfo(this.albumInfo);
menuOperation = new TranscodingMenuOperation(menuContext);
} else if (action === Action.MOVE) { } else if (action === Action.MOVE) {
this.backFromCopy = true; this.backFromCopy = true;
this.routeSelectAlbumPage(MediaOperationType.Move); this.routeSelectAlbumPage(MediaOperationType.Move);
return; return;
} else if (action == Action.HIDE_SENSITIZATION) {
let currentPhoto = this.getCurrentPhoto();
let items: UserFileDataItem[] = [];
items.push(currentPhoto);
Log.info(TAG, 'count is ' + items.length);
this.broadCast.emit(BroadcastConstants.SHOW_SENSITIVE_DIALOG, [items]);
return;
} else { } else {
return; return;
} }
@ -340,13 +356,22 @@ struct PhotoBrowser {
let list: Action[] = []; let list: Action[] = [];
if (this.pageFrom === Constants.ENTRY_FROM.RECYCLE) { if (this.pageFrom === Constants.ENTRY_FROM.RECYCLE) {
list.push(Action.RECOVER, Action.DELETE); list.push(Action.RECOVER, Action.DELETE);
} else if(await currentPhoto.isVideo()) {
let isFavor = await currentPhoto.isFavor();
Log.info(TAG,'isFavor' + isFavor)
list.push(
isFavor ? Action.FAVORITE : Action.NOT_FAVORITE,
Action.RENAME,
Action.DELETE,
Action.TRANSCODING,);
} else { } else {
let isFavor = await currentPhoto.isFavor(); let isFavor = await currentPhoto.isFavor();
Log.info(TAG,'isFavor' + isFavor) Log.info(TAG,'isFavor' + isFavor)
list.push( list.push(
isFavor ? Action.FAVORITE : Action.NOT_FAVORITE, isFavor ? Action.FAVORITE : Action.NOT_FAVORITE,
Action.RENAME, Action.RENAME,
Action.DELETE,); Action.DELETE,
Action.HIDE_SENSITIZATION,);
} }
return list; return list;
} }

View File

@ -170,6 +170,8 @@ struct PhotoGridPage {
menuOperation.doAction(); menuOperation.doAction();
} else if (action === Action.NEW) { } else if (action === Action.NEW) {
this.routeToAddMediaPage(); this.routeToAddMediaPage();
} else if (action === Action.HIDE_SENSITIZATION) {
this.openSelectSensitiveDialog();
} }
} }
@ -190,6 +192,13 @@ struct PhotoGridPage {
this.broadCast.emit(BroadcastConstants.SHOW_MULTI_SELECT_DIALOG, [items.length, size]); this.broadCast.emit(BroadcastConstants.SHOW_MULTI_SELECT_DIALOG, [items.length, size]);
} }
} }
async openSelectSensitiveDialog(): Promise<void> {
let items: UserFileDataItem[] = this.groupDataSource.getSelectedItems() as UserFileDataItem[];
Log.info(TAG, 'lumingfei count is ' + items.length);
this.broadCast.emit(BroadcastConstants.SHOW_SENSITIVE_DIALOG, [items]);
}
private routeSelectAlbumPage(pageType: string): void { private routeSelectAlbumPage(pageType: string): void {
this.routerStart = true; this.routerStart = true;
router.push({ router.push({
@ -467,9 +476,9 @@ struct PhotoGridPage {
this.initGridRowCount(); this.initGridRowCount();
if (this.albumInfo.albumType==MediaConstants.ALBUM_TYPE_USER){ if (this.albumInfo.albumType==MediaConstants.ALBUM_TYPE_USER){
this.moreMenuList = [Action.MOVE, Action.REMOVE, Action.INFO]; this.moreMenuList = [Action.MOVE, Action.REMOVE, Action.HIDE_SENSITIZATION, Action.INFO];
} else { } else {
this.moreMenuList = [Action.MOVE, Action.INFO]; this.moreMenuList = [Action.MOVE, Action.HIDE_SENSITIZATION, Action.INFO];
} }
this.updateActionBar(); this.updateActionBar();
@ -537,15 +546,16 @@ struct PhotoGridPage {
this.isAllSelected = this.groupDataSource.isSelect(); this.isAllSelected = this.groupDataSource.isSelect();
if (this.totalSelectedCount > 0) { if (this.totalSelectedCount > 0) {
if (this.albumInfo.albumType === MediaConstants.ALBUM_TYPE_USER){ if (this.albumInfo.albumType === MediaConstants.ALBUM_TYPE_USER){
this.moreMenuList = [Action.MOVE, Action.REMOVE, Action.INFO]; this.moreMenuList = [Action.MOVE, Action.REMOVE, Action.HIDE_SENSITIZATION, Action.INFO];
} else { } else {
this.moreMenuList = [Action.MOVE, Action.INFO]; this.moreMenuList = [Action.MOVE, Action.HIDE_SENSITIZATION, Action.INFO];
} }
} else { } else {
if (this.albumInfo.albumType === MediaConstants.ALBUM_TYPE_USER){ if (this.albumInfo.albumType === MediaConstants.ALBUM_TYPE_USER){
this.moreMenuList = [Action.MOVE_INVALID, Action.REMOVE_INVALID, Action.INFO_INVALID]; this.moreMenuList = [Action.MOVE_INVALID, Action.REMOVE_INVALID,
Action.HIDE_SENSITIZATION, Action.INFO_INVALID];
} else { } else {
this.moreMenuList = [Action.MOVE_INVALID, Action.INFO_INVALID]; this.moreMenuList = [Action.MOVE_INVALID, Action.HIDE_SENSITIZATION, Action.INFO_INVALID];
} }
} }
} }

View File

@ -140,6 +140,22 @@
"name": "action_setting", "name": "action_setting",
"value": "Settings" "value": "Settings"
}, },
{
"name": "action_transcoding",
"value": "transCoding"
},
{
"name": "action_transcoding_success",
"value": "transCodingSuccess"
},
{
"name": "action_transcoding_progress",
"value": "transCodingProgress"
},
{
"name": "action_transcoding_path",
"value": "transCodingPath: "
},
{ {
"name": "action_navigation", "name": "action_navigation",
"value": "Get directions to this location" "value": "Get directions to this location"
@ -903,6 +919,34 @@
{ {
"name": "write_image_video_permission", "name": "write_image_video_permission",
"value": "user write image video permission" "value": "user write image video permission"
},
{
"name": "location",
"value": "Location: "
},
{
"name": "shooting_params",
"value": "Shooting params: "
},
{
"name": "action_hide_sensitization",
"value": "Hide sensitization"
},
{
"name": "hide_location_and_shootingparam",
"value": "Both location and shootingparams"
},
{
"name": "hide_location_only",
"value": "Location only"
},
{
"name": "hide_shootingparam_only",
"value": "Shootingparams only"
},
{
"name": "no_hide_sensitive_type",
"value": "none"
} }
] ]
} }

View File

@ -144,6 +144,22 @@
"name": "action_setting", "name": "action_setting",
"value": "设置" "value": "设置"
}, },
{
"name": "action_transcoding",
"value": "转码"
},
{
"name": "action_transcoding_success",
"value": "转码成功"
},
{
"name": "action_transcoding_progress",
"value": "转码进度"
},
{
"name": "action_transcoding_path",
"value": "转码视频路径: "
},
{ {
"name": "action_navigation", "name": "action_navigation",
"value": "导航" "value": "导航"
@ -901,12 +917,32 @@
"value": "user read file permission" "value": "user read file permission"
}, },
{ {
"name": "write_permission", "name": "location",
"value": "user write file permission" "value": "位置: "
}, },
{ {
"name": "write_image_video_permission", "name": "shooting_params",
"value": "user write image video permission" "value": "拍摄参数: "
},
{
"name": "action_hide_sensitization",
"value": "脱敏"
},
{
"name": "hide_location_and_shootingparam",
"value": "位置和拍摄参数"
},
{
"name": "hide_location_only",
"value": "位置"
},
{
"name": "hide_shootingparam_only",
"value": "拍摄参数"
},
{
"name": "no_hide_sensitive_type",
"value": "无"
} }
] ]
} }