From 8c19f8f276148ef07919572351e0f2f912b07883 Mon Sep 17 00:00:00 2001 From: fanchenxuan Date: Thu, 18 Jul 2024 18:46:36 +0800 Subject: [PATCH] =?UTF-8?q?=E5=9B=BE=E7=89=87/=E8=A7=86=E9=A2=91=E4=BF=9D?= =?UTF-8?q?=E5=AD=98=E5=BC=B9=E7=AA=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: fanchenxuan --- AppScope/app.json5 | 8 +- build-profile.json5 | 4 +- .../default/view/ImageGridItemComponent.ets | 1 + .../main/resources/base/element/float.json | 32 +++ .../main/resources/base/element/string.json | 20 ++ .../main/resources/zh_CN/element/string.json | 20 ++ .../SaveAbility/SaveUIExtensionAbility.ets | 30 +++ .../main/ets/pages/SaveUIExtensionPage.ets | 229 ++++++++++++++++++ product/phone/src/main/module.json5 | 7 + .../resources/base/profile/main_pages.json | 3 +- 10 files changed, 347 insertions(+), 7 deletions(-) create mode 100644 product/phone/src/main/ets/SaveAbility/SaveUIExtensionAbility.ets create mode 100644 product/phone/src/main/ets/pages/SaveUIExtensionPage.ets diff --git a/AppScope/app.json5 b/AppScope/app.json5 index 52174b95..686a15d4 100644 --- a/AppScope/app.json5 +++ b/AppScope/app.json5 @@ -16,12 +16,12 @@ "app": { "bundleName": "com.ohos.photos", "vendor": "ohos", - "versionCode": 1000000, - "versionName": "1.0.0", + "versionCode": 1000010, + "versionName": "1.1.0", "icon": "$media:ohos_gallery", "label": "$string:app_name", "distributedNotificationEnabled": true, - "minAPIVersion": 9, - "targetAPIVersion": 9 + "minAPIVersion": 12, + "targetAPIVersion": 12 } } \ No newline at end of file diff --git a/build-profile.json5 b/build-profile.json5 index d3104e62..827a6b39 100644 --- a/build-profile.json5 +++ b/build-profile.json5 @@ -26,8 +26,8 @@ { "name": "default", "signingConfig": "debug", - "compileSdkVersion": 11, - "compatibleSdkVersion": 11 + "compileSdkVersion": 12, + "compatibleSdkVersion": 12 }, ], }, diff --git a/common/src/main/ets/default/view/ImageGridItemComponent.ets b/common/src/main/ets/default/view/ImageGridItemComponent.ets index f8c4d8d3..05eccd6d 100644 --- a/common/src/main/ets/default/view/ImageGridItemComponent.ets +++ b/common/src/main/ets/default/view/ImageGridItemComponent.ets @@ -251,6 +251,7 @@ export struct ImageGridItemComponent { @Builder buildImage() { Image(this.imageThumbnail) + .syncLoad(true) .width('100%') .height('100%') .rotate({ x: 0, y: 0, z: 1, angle: 0 }) diff --git a/common/src/main/resources/base/element/float.json b/common/src/main/resources/base/element/float.json index ac71cacd..f942e876 100644 --- a/common/src/main/resources/base/element/float.json +++ b/common/src/main/resources/base/element/float.json @@ -1331,6 +1331,38 @@ { "name": "third_selected_actionbar_padding_top", "value": "8vp" + }, + { + "name": "offset_6", + "value": "6vp" + }, + { + "name": "padding_8", + "value": "8vp" + }, + { + "name": "padding_16", + "value": "16vp" + }, + { + "name": "padding_24", + "value": "24vp" + }, + { + "name": "margin_8", + "value": "8vp" + }, + { + "name": "radius_12", + "value": "12vp" + }, + { + "name": "radius_24", + "value": "24vp" + }, + { + "name": "save_image_border", + "value": "0.8vp" } ] } \ No newline at end of file diff --git a/common/src/main/resources/base/element/string.json b/common/src/main/resources/base/element/string.json index a168d33a..1724ab49 100644 --- a/common/src/main/resources/base/element/string.json +++ b/common/src/main/resources/base/element/string.json @@ -216,6 +216,14 @@ "name":"dialog_cancel", "value":"Cancel" }, + { + "name":"dialog_ban", + "value":"Ban" + }, + { + "name":"dialog_allow", + "value":"Allow" + }, { "name":"remove_picture_tips", "value":"Remove this photo?" @@ -727,6 +735,18 @@ { "name": "third_delete_dialog_message", "value": "Whether allow %s to delete %d files?" + }, + { + "name": "third_save_dialog_picture", + "value": "Whether allow \"%s\" to save %d photos?" + }, + { + "name": "third_save_dialog_video", + "value": "Whether allow \"%s\" to save %d videos?" + }, + { + "name": "third_save_dialog_picture_and_video", + "value": "Whether allow \"%s\" to save %d files?" } ] } \ No newline at end of file diff --git a/common/src/main/resources/zh_CN/element/string.json b/common/src/main/resources/zh_CN/element/string.json index 426b1d26..fc25d3f1 100644 --- a/common/src/main/resources/zh_CN/element/string.json +++ b/common/src/main/resources/zh_CN/element/string.json @@ -216,6 +216,14 @@ "name":"dialog_cancel", "value":"取消" }, + { + "name":"dialog_ban", + "value":"禁止" + }, + { + "name":"dialog_allow", + "value":"允许" + }, { "name":"remove_picture_tips", "value":"是否移除此图片?" @@ -727,6 +735,18 @@ { "name": "third_delete_dialog_message", "value": "是否允许 %s 删除 %d 个文件?" + }, + { + "name": "third_save_dialog_picture", + "value": "是否允许“%s”保存 %d 张图片?" + }, + { + "name": "third_save_dialog_video", + "value": "是否允许“%s”保存 %d 个视频?" + }, + { + "name": "third_save_dialog_picture_and_video", + "value": "是否允许“%s”保存 %d 个文件?" } ] } \ No newline at end of file diff --git a/product/phone/src/main/ets/SaveAbility/SaveUIExtensionAbility.ets b/product/phone/src/main/ets/SaveAbility/SaveUIExtensionAbility.ets new file mode 100644 index 00000000..9cbc4af9 --- /dev/null +++ b/product/phone/src/main/ets/SaveAbility/SaveUIExtensionAbility.ets @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2024 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 UIExtensionAbility from '@ohos.app.ability.UIExtensionAbility'; +import Want from '@ohos.app.ability.Want'; +import { Log } from '@ohos/common'; +import UIExtensionContentSession from '@ohos.app.ability.UIExtensionContentSession'; + +const TAG: string = 'SaveUIExtension'; + +export default class SaveUIExtensionAbility extends UIExtensionAbility { + onSessionCreate(want: Want, session: UIExtensionContentSession) { + Log.info(TAG, `wantParam: ${JSON.stringify(want.parameters)}`); + let storage: LocalStorage = new LocalStorage(); + storage.setOrCreate('session', session); + storage.setOrCreate('wantParam', want.parameters); + session.loadContent('pages/SaveUIExtensionPage', storage); + } +} \ No newline at end of file diff --git a/product/phone/src/main/ets/pages/SaveUIExtensionPage.ets b/product/phone/src/main/ets/pages/SaveUIExtensionPage.ets new file mode 100644 index 00000000..553b42c8 --- /dev/null +++ b/product/phone/src/main/ets/pages/SaveUIExtensionPage.ets @@ -0,0 +1,229 @@ +/* + * Copyright (c) 2024 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 UIExtensionContentSession from '@ohos.app.ability.UIExtensionContentSession'; +import ability from '@ohos.ability.ability'; +import { Constants, Log } from '@ohos/common'; +import common from '@ohos.app.ability.common'; +import photoAccessHelper from '@ohos.file.photoAccessHelper'; +import { CustomContentDialog } from '@ohos.arkui.advanced.Dialog'; + +const TAG: string = 'SaveUIExtension'; +const FOREGROUND_PHOTO_WIDTH: number = 576; +const BACKGROUND_PHOTO_WIDTH: number = 512; +const FOREGROUND_PHOTO_HEIGHT: number = 344; +const BACKGROUND_PHOTO_HEIGHT: number = 360; + +let storage = LocalStorage.getShared(); + +@Entry(storage) +@Component +export struct SaveUIExtensionPage { + private context = getContext(this) as common.UIExtensionContext; + private uris: Array = []; + private bundleName: string = ''; + private appName: string = ''; + private appId: string = ''; + private srcFileUris: Array = []; + private title: string = 'app.string.third_save_dialog_picture_and_video'; + private wantParam: Record = storage.get('wantParam') as Record; + private session: UIExtensionContentSession = + storage.get('session') as UIExtensionContentSession; + + dialogController: CustomDialogController | null = new CustomDialogController({ + builder: CustomContentDialog({ + contentBuilder: () => { + this.buildContent(); + }, + contentAreaPadding: { right: 0 }, + buttons: [ + { + value: $r('app.string.dialog_ban'), + buttonStyle: ButtonStyleMode.TEXTUAL, + action: () => { + this.setSaveResult(false); + } + }, + { + value: $r('app.string.dialog_allow'), + buttonStyle: ButtonStyleMode.TEXTUAL, + action: () => { + this.setSaveResult(true); + } + } + ], + }), + autoCancel: false, + cancel: () => { + this.context.terminateSelf(); + } + }); + + @Builder + buildContent(): void { + Column() { + Shape() { + Circle({ width: Constants.NUMBER_32, height: Constants.NUMBER_32 }) + .fill($r('sys.color.multi_color_03')) + Row() { + SymbolGlyph($r('sys.symbol.picture_fill')) + .fontSize(Constants.NUMBER_20) + .fontColor([$r('sys.color.ohos_id_color_primary_contrary')]) + .draggable(false) + } + .offset({ x: $r('app.float.offset_6'), y: $r('app.float.offset_6') }) + } + + Column() { + Text($r(this.title, this.appName, this.uris.length)) + .textAlign(TextAlign.Center) + .fontSize($r('sys.float.Title_S')) + .fontWeight(FontWeight.Bold) + .fontColor($r('sys.color.font_primary')) + .textOverflow({ overflow: TextOverflow.Ellipsis }) + .maxLines(Constants.NUMBER_2) + .minFontSize($r('sys.float.Subtitle_M')) + .maxFontSize($r('sys.float.Title_S')) + .heightAdaptivePolicy(TextHeightAdaptivePolicy.MIN_FONT_SIZE_FIRST) + } + .height($r('app.float.dialog_title_height')) + .justifyContent(FlexAlign.Center) + + Stack({ alignContent: Alignment.Bottom }) { + if (this.uris.length > 1) { + Image(this.getThumbnail(false)) + .objectFit(ImageFit.Fill) + .border({ + radius: $r('app.float.radius_24'), + color: $r('sys.color.ohos_id_color_click_effect'), + width: $r('app.float.save_image_border') + }) + .height('100%') + .width('100%') + .padding({ left: $r('app.float.padding_16'), right: $r('app.float.padding_16') }) + .opacity(0.4) + } + + Image(this.getThumbnail(true)) + .objectFit(ImageFit.Fill) + .border({ + radius: $r('app.float.radius_24'), + color: $r('sys.color.ohos_id_color_click_effect'), + width: $r('app.float.save_image_border') + }) + .height(this.uris.length > 1 ? $r('app.float.third_delete_dialog_ico_height_multi') : '100%') + .width('100%') + .margin({ top: this.uris.length > 1 ? $r('app.float.margin_8') : 0 }) + } + .width('100%') + .height($r('app.float.third_delete_dialog_ico_height')) + .alignContent(Alignment.Top) + } + .alignItems(HorizontalAlign.Center) + .width('100%') + .padding({ + top: $r('app.float.padding_24'), + bottom: $r('app.float.padding_8'), + left: $r('app.float.dialog_content_padding_left'), + right: $r('app.float.dialog_content_padding_right') + }) + } + + build() {} + + onPageShow() { + this.session.setWindowBackgroundColor('#00000000'); + } + + aboutToAppear() { + this.uris = this.wantParam?.srcFileUris as string[]; + this.bundleName = this.wantParam?.bundleName as string; + this.appName = this.wantParam?.appName as string; + this.appId = this.wantParam?.appId as string; + let titleArray = this.wantParam?.titleArray as string[]; + let extensionArray = this.wantParam?.extensionArray as string[]; + let photoTypeArray = this.wantParam?.photoTypeArray as photoAccessHelper.PhotoType[]; + let photoSubtypeArray = this.wantParam?.photoSubTypeArray as photoAccessHelper.PhotoSubtype[]; + try { + let imageArray = photoTypeArray.filter(type => type === photoAccessHelper.PhotoType.IMAGE); + if (imageArray.length === photoTypeArray.length) { + this.title = 'app.string.third_save_dialog_picture'; + } else if (imageArray.length === 0) { + this.title = 'app.string.third_save_dialog_video'; + } + titleArray.forEach((title, idx) => { + let photoCreateConfig = { + title, + fileNameExtension: extensionArray[idx], + photoType: photoTypeArray[idx], + subtype: photoSubtypeArray[idx] + } as photoAccessHelper.PhotoCreationConfig; + this.srcFileUris.push(photoCreateConfig); + }) + Log.info(TAG, `srcFileUris: ${JSON.stringify(this.srcFileUris)}.`); + this.dialogController?.open(); + } catch (err) { + Log.error(TAG, `aboutToAppear data collection failure. err: ${JSON.stringify(err)}`); + this.session.terminateSelf(); + } + } + + private async setSaveResult(isSave: boolean) { + if (isSave) { + let result = await this.saveBox(); + let abilityResult: ability.AbilityResult = { + resultCode: 0, + want: { + parameters: { + 'desFileUris': result + } + } + }; + Log.info(TAG, 'terminateSelfWithResult start, abilityResult:' + JSON.stringify(abilityResult)); + this.session.terminateSelfWithResult(abilityResult); + } else { + let abilityResult: ability.AbilityResult = { + resultCode: -1 + }; + Log.info(TAG, 'terminateSelfWithResult start, isSave:' + isSave); + this.session.terminateSelfWithResult(abilityResult); + } + } + + async saveBox(): Promise> { + try { + let phAccessHelper = photoAccessHelper.getPhotoAccessHelper(this.context); + let result: string[] = + await phAccessHelper.createAssetsForApp(this.bundleName, this.appName, this.appId, this.srcFileUris); + Log.info(TAG, `Photo agentCreateAssets: ${JSON.stringify(result)}`); + return result; + } catch (err) { + Log.error(TAG, `Photo agentCreateAssets failed with error: ${err.code}, ${err.message}.`); + return []; + } + } + + private getThumbnail(isForeground: boolean): string { + if (this.uris.length == 0) { + return ''; + } + if (this.uris.length == 1) { + return `${this.uris[0]}?oper=thumbnail&width=${FOREGROUND_PHOTO_WIDTH}&height=${BACKGROUND_PHOTO_HEIGHT}`; + } else if (isForeground) { + return `${this.uris[0]}?oper=thumbnail&width=${FOREGROUND_PHOTO_WIDTH}&height=${FOREGROUND_PHOTO_HEIGHT}`; + } else { + return `${this.uris[1]}?oper=thumbnail&width=${BACKGROUND_PHOTO_WIDTH}&height=${BACKGROUND_PHOTO_HEIGHT}`; + } + } +} \ No newline at end of file diff --git a/product/phone/src/main/module.json5 b/product/phone/src/main/module.json5 index efbd0ab7..fcdb6069 100644 --- a/product/phone/src/main/module.json5 +++ b/product/phone/src/main/module.json5 @@ -143,6 +143,13 @@ "type": "sysDialog/common", "exported": true, "srcEntry": "./ets/DeleteAbility/DeleteUIExtensionAbility.ets" + }, + { + "name": "SaveUIExtensionAbility", + "description": "SaveUIExtensionAbility", + "type": "sysDialog/common", + "exported": true, + "srcEntry": "./ets/SaveAbility/SaveUIExtensionAbility.ets" } ] }, diff --git a/product/phone/src/main/resources/base/profile/main_pages.json b/product/phone/src/main/resources/base/profile/main_pages.json index 92fd02fa..b83b8a36 100644 --- a/product/phone/src/main/resources/base/profile/main_pages.json +++ b/product/phone/src/main/resources/base/profile/main_pages.json @@ -15,6 +15,7 @@ "pages/EditMain", "pages/FormEditorPage", "pages/ResourceDeletePage", - "pages/DeleteUIExtensionPage" + "pages/DeleteUIExtensionPage", + "pages/SaveUIExtensionPage" ] }