From 152a13685998af7d3c914ebbb3b7ac805d0c3f1d Mon Sep 17 00:00:00 2001 From: feng <1362134550@qq.com> Date: Wed, 24 Jul 2024 16:06:50 +0800 Subject: [PATCH] =?UTF-8?q?=E4=B8=80=E5=A4=9Ahsp=E6=94=B9=E6=88=90har?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 10 +- .../ets/constants/BreakpointConstants.ets | 5 + .../main/ets/constants/RouterUrlConstants.ets | 6 +- .../src/main/ets/utils/SongItemBuilder.ets | 2 +- features/live/{src/main/ets => }/Index.ets | 5 +- features/live/hvigorfile.ts | 2 +- features/live/oh-package.json5 | 2 +- features/live/src/main/ets/view/Header.ets | 5 +- features/live/src/main/ets/view/LiveList.ets | 5 +- .../{pages/Index.ets => view/LivePage.ets} | 7 +- features/live/src/main/module.json5 | 6 +- .../resources/base/profile/main_pages.json | 5 - features/musicComment/Index.ets | 1 + features/musicComment/hvigorfile.ts | 2 +- features/musicComment/oh-package.json5 | 2 +- features/musicComment/src/main/ets/Index.ets | 0 .../src/main/ets/view/HeadComponent.ets | 5 +- .../Index.ets => view/MusicCommentPage.ets} | 14 +- features/musicComment/src/main/module.json5 | 6 +- .../resources/base/profile/main_pages.json | 5 - features/musicList/Index.ets | 4 + features/musicList/hvigorfile.ts | 2 +- features/musicList/oh-package.json5 | 2 +- features/musicList/src/main/ets/Index.ets | 3 - .../main/ets/components/AlbumComponent.ets | 7 +- .../src/main/ets/components/Header.ets | 8 +- .../src/main/ets/components/ListContent.ets | 7 +- .../main/ets/components/LyricsComponent.ets | 4 +- .../ets/components/MusicControlComponent.ets | 13 +- .../src/main/ets/components/Player.ets | 4 +- .../main/ets/constants/PlayerConstants.ets | 2 +- .../Index.ets => view/MusicListPage.ets} | 11 +- .../src/main/ets/viewmodel/SongListData.ets | 9 +- features/musicList/src/main/module.json5 | 6 +- .../resources/base/profile/main_pages.json | 5 - products/phone/oh-package.json5 | 5 +- .../main/ets/entryability/EntryAbility.ets | 26 ++- products/phone/src/main/ets/pages/Index.ets | 168 ++++++++++-------- .../PhoneBackupExtAbility.ets | 12 ++ .../src/main/ets/viewmodel/IndexViewModel.ets | 7 +- products/phone/src/main/module.json5 | 20 ++- .../resources/base/profile/backup_config.json | 3 + screenshots/device/config.png | Bin 26186 -> 0 bytes 43 files changed, 243 insertions(+), 180 deletions(-) rename features/live/{src/main/ets => }/Index.ets (78%) rename features/live/src/main/ets/{pages/Index.ets => view/LivePage.ets} (88%) delete mode 100644 features/live/src/main/resources/base/profile/main_pages.json create mode 100644 features/musicComment/Index.ets delete mode 100644 features/musicComment/src/main/ets/Index.ets rename features/musicComment/src/main/ets/{pages/Index.ets => view/MusicCommentPage.ets} (95%) delete mode 100644 features/musicComment/src/main/resources/base/profile/main_pages.json create mode 100644 features/musicList/Index.ets delete mode 100644 features/musicList/src/main/ets/Index.ets rename features/musicList/src/main/ets/{pages/Index.ets => view/MusicListPage.ets} (87%) delete mode 100644 features/musicList/src/main/resources/base/profile/main_pages.json create mode 100644 products/phone/src/main/ets/phonebackupextability/PhoneBackupExtAbility.ets create mode 100644 products/phone/src/main/resources/base/profile/backup_config.json delete mode 100644 screenshots/device/config.png diff --git a/README.md b/README.md index f26dcf8..575b644 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# 一次开发,多端部署-音乐专辑 +# 优秀实践-一次开发,多端部署-音乐专辑 ### 简介 @@ -33,10 +33,4 @@ 1. 本示例仅支持标准系统上运行,支持设备:华为手机。 2. HarmonyOS系统:HarmonyOS NEXT Developer Beta1及以上。 3. DevEco Studio版本:DevEco Studio NEXT Developer Beta1及以上。 -4. HarmonyOS SDK版本:HarmonyOS NEXT Developer Beta1 SDK及以上。 - -### 注意 - -运行时需设置引用所有HSP模块。点击Run > Edit Configurations,选择Deploy Multi Hap标签页,勾选Deploy Multi Hap Packages, 选择使用方模块(phone)和所有HSP模块,点击OK。单击Run > Run “模块名称”(如Run “phone”)或![](screenshots/device/run.PNG)来启动应用/服务的编译构建。 - -![](screenshots/device/config.png) +4. HarmonyOS SDK版本:HarmonyOS NEXT Developer Beta1 SDK及以上。 \ No newline at end of file diff --git a/common/constantsCommon/src/main/ets/constants/BreakpointConstants.ets b/common/constantsCommon/src/main/ets/constants/BreakpointConstants.ets index 4fa710d..01e3b49 100644 --- a/common/constantsCommon/src/main/ets/constants/BreakpointConstants.ets +++ b/common/constantsCommon/src/main/ets/constants/BreakpointConstants.ets @@ -37,6 +37,11 @@ export class BreakpointConstants { */ static readonly BREAKPOINT_VALUE: Array = ['320vp', '600vp', '840vp']; + /** + * The break point value. + */ + static readonly BREAKPOINT_VALUE_NUMBER: Array = [320, 600, 840]; + /** * The number of columns for SM device. */ diff --git a/common/constantsCommon/src/main/ets/constants/RouterUrlConstants.ets b/common/constantsCommon/src/main/ets/constants/RouterUrlConstants.ets index 8c75da8..bbe6e5b 100644 --- a/common/constantsCommon/src/main/ets/constants/RouterUrlConstants.ets +++ b/common/constantsCommon/src/main/ets/constants/RouterUrlConstants.ets @@ -20,15 +20,15 @@ export class RouterUrlConstants { /** * Playback page. */ - static readonly MUSIC_PLAY: string = '@bundle:com.huawei.music.musichome/musicPlay/ets/pages/PlayPage'; + static readonly LIVE: string = 'LivePage'; /** * Music list page. */ - static readonly MUSIC_LIST: string = '@bundle:com.huawei.music.musichome/musicList/ets/pages/Index'; + static readonly MUSIC_LIST: string = 'MusicListPage'; /** * Music review page. */ - static readonly MUSIC_COMMENT: string = '@bundle:com.huawei.music.musichome/musicComment/ets/pages/Index'; + static readonly MUSIC_COMMENT: string = 'MusicCommentPage'; } \ No newline at end of file diff --git a/common/mediaCommon/src/main/ets/utils/SongItemBuilder.ets b/common/mediaCommon/src/main/ets/utils/SongItemBuilder.ets index 7c8804d..500224b 100644 --- a/common/mediaCommon/src/main/ets/utils/SongItemBuilder.ets +++ b/common/mediaCommon/src/main/ets/utils/SongItemBuilder.ets @@ -29,7 +29,7 @@ export default class SongItemBuilder { if (!this.context) { return this.songItem; } - let rawfileFd = await this.context.createModuleContext('musicList').resourceManager.getRawFd(songItem.src) + let rawfileFd = await this.context.resourceManager.getRawFd(songItem.src) .catch((error: BusinessError) => { Logger.error(`resourceManager error code ${error.code} message ${error.message}`); }) diff --git a/features/live/src/main/ets/Index.ets b/features/live/Index.ets similarity index 78% rename from features/live/src/main/ets/Index.ets rename to features/live/Index.ets index 6f75ad6..47cc562 100644 --- a/features/live/src/main/ets/Index.ets +++ b/features/live/Index.ets @@ -13,5 +13,6 @@ * limitations under the License. */ -export { Header } from './view/Header'; -export { LiveList } from './view/LiveList'; \ No newline at end of file +export { Header } from './src/main/ets/view/Header'; +export { LiveList } from './src/main/ets/view/LiveList'; +export { LivePage } from './src/main/ets/view/LivePage'; \ No newline at end of file diff --git a/features/live/hvigorfile.ts b/features/live/hvigorfile.ts index 0e65ea8..e9a64a9 100644 --- a/features/live/hvigorfile.ts +++ b/features/live/hvigorfile.ts @@ -1,2 +1,2 @@ // 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').hspTasks +module.exports = require('@ohos/hvigor-ohos-plugin').harTasks diff --git a/features/live/oh-package.json5 b/features/live/oh-package.json5 index 4ff70ed..4d3c4d4 100644 --- a/features/live/oh-package.json5 +++ b/features/live/oh-package.json5 @@ -4,7 +4,7 @@ "author": "", "name": "live", "description": "Please describe the basic information.", - "main": "./src/main/ets/Index.ets", + "main": "./Index.ets", "version": "1.0.0", "dependencies": {} } diff --git a/features/live/src/main/ets/view/Header.ets b/features/live/src/main/ets/view/Header.ets index a35601b..91df5a1 100644 --- a/features/live/src/main/ets/view/Header.ets +++ b/features/live/src/main/ets/view/Header.ets @@ -13,11 +13,12 @@ * limitations under the License. */ -import { router } from '@kit.ArkUI'; import { LiveConstants } from '../constants/LiveConstants'; @Component export struct Header { + @StorageLink('pageIndexInfos') pageIndexInfos: NavPathStack = new NavPathStack(); + build() { Row() { Image($r('app.media.ic_back')) @@ -25,7 +26,7 @@ export struct Header { .height($r('app.float.back_height')) .margin({ left: $r('app.float.back_left_margin') }) .onClick(() => { - router.back(); + this.pageIndexInfos.pop(); }) Text($r('app.string.live_title')) .fontSize($r('app.float.title_font_size')) diff --git a/features/live/src/main/ets/view/LiveList.ets b/features/live/src/main/ets/view/LiveList.ets index 49448b2..df4f8b4 100644 --- a/features/live/src/main/ets/view/LiveList.ets +++ b/features/live/src/main/ets/view/LiveList.ets @@ -21,7 +21,7 @@ import { LiveStreamViewModel } from '../viewmodel/LiveStreamViewModel'; export struct LiveList { private scroller: Scroller = new Scroller(); @State liveStreams: LiveStream[] = new LiveStreamViewModel().getLiveStreamList(); - @State currentBreakpoint: string = LiveConstants.CURRENT_BREAKPOINT; + @StorageProp('currentBreakpoint') currentBreakpoint: string = LiveConstants.CURRENT_BREAKPOINT; build() { GridRow({ @@ -50,9 +50,6 @@ export struct LiveList { } .margin({ left: $r('app.float.grid_col_left_margin'), right: $r('app.float.grid_col_right_margin') }) } - .onBreakpointChange((breakPoints) => { - this.currentBreakpoint = breakPoints; - }) } @Builder diff --git a/features/live/src/main/ets/pages/Index.ets b/features/live/src/main/ets/view/LivePage.ets similarity index 88% rename from features/live/src/main/ets/pages/Index.ets rename to features/live/src/main/ets/view/LivePage.ets index e7dd9b0..7569800 100644 --- a/features/live/src/main/ets/pages/Index.ets +++ b/features/live/src/main/ets/view/LivePage.ets @@ -13,13 +13,12 @@ * limitations under the License. */ -import { Header } from '../view/Header'; -import { LiveList } from '../view/LiveList'; +import { Header } from './Header'; +import { LiveList } from './LiveList'; import { LiveConstants} from '../constants/LiveConstants'; -@Entry @Component -struct Index { +export struct LivePage { build() { Column() { Header() diff --git a/features/live/src/main/module.json5 b/features/live/src/main/module.json5 index 5ed607b..3264dd9 100644 --- a/features/live/src/main/module.json5 +++ b/features/live/src/main/module.json5 @@ -1,14 +1,12 @@ { "module": { "name": "live", - "type": "shared", + "type": "har", "description": "$string:shared_desc", "deviceTypes": [ "phone", "tablet", "2in1" - ], - "deliveryWithInstall": true, - "pages": "$profile:main_pages" + ] } } \ No newline at end of file diff --git a/features/live/src/main/resources/base/profile/main_pages.json b/features/live/src/main/resources/base/profile/main_pages.json deleted file mode 100644 index 1898d94..0000000 --- a/features/live/src/main/resources/base/profile/main_pages.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "src": [ - "pages/Index" - ] -} diff --git a/features/musicComment/Index.ets b/features/musicComment/Index.ets new file mode 100644 index 0000000..fb27bba --- /dev/null +++ b/features/musicComment/Index.ets @@ -0,0 +1 @@ +export { MusicCommentPage } from './src/main/ets/view/MusicCommentPage'; \ No newline at end of file diff --git a/features/musicComment/hvigorfile.ts b/features/musicComment/hvigorfile.ts index 0e65ea8..e9a64a9 100644 --- a/features/musicComment/hvigorfile.ts +++ b/features/musicComment/hvigorfile.ts @@ -1,2 +1,2 @@ // 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').hspTasks +module.exports = require('@ohos/hvigor-ohos-plugin').harTasks diff --git a/features/musicComment/oh-package.json5 b/features/musicComment/oh-package.json5 index f4dc913..040de4c 100644 --- a/features/musicComment/oh-package.json5 +++ b/features/musicComment/oh-package.json5 @@ -4,7 +4,7 @@ "author": "", "name": "musiccomment", "description": "Please describe the basic information.", - "main": "./src/main/ets/Index.ets", + "main": "./Index.ets", "version": "1.0.0", "dependencies": { "@ohos/mediaCommon": "file:../../common/mediaCommon", diff --git a/features/musicComment/src/main/ets/Index.ets b/features/musicComment/src/main/ets/Index.ets deleted file mode 100644 index e69de29..0000000 diff --git a/features/musicComment/src/main/ets/view/HeadComponent.ets b/features/musicComment/src/main/ets/view/HeadComponent.ets index f64a6d3..5c03a73 100644 --- a/features/musicComment/src/main/ets/view/HeadComponent.ets +++ b/features/musicComment/src/main/ets/view/HeadComponent.ets @@ -13,11 +13,12 @@ * limitations under the License. */ -import { router } from '@kit.ArkUI'; import { StyleConstants } from '@ohos/constantsCommon'; @Component export struct HeadComponent { + @StorageLink('pageIndexInfos') pageIndexInfos: NavPathStack = new NavPathStack(); + build() { Row() { Image($r('app.media.ic_public_back')) @@ -36,7 +37,7 @@ export struct HeadComponent { .width(StyleConstants.FULL_WIDTH) .height($r('app.float.header_height')) .onClick(() => { - router.back(); + this.pageIndexInfos.pop(); }) } } \ No newline at end of file diff --git a/features/musicComment/src/main/ets/pages/Index.ets b/features/musicComment/src/main/ets/view/MusicCommentPage.ets similarity index 95% rename from features/musicComment/src/main/ets/pages/Index.ets rename to features/musicComment/src/main/ets/view/MusicCommentPage.ets index b8b7cf6..4a09f62 100644 --- a/features/musicComment/src/main/ets/pages/Index.ets +++ b/features/musicComment/src/main/ets/view/MusicCommentPage.ets @@ -16,15 +16,14 @@ import { StyleConstants, BreakpointConstants } from '@ohos/constantsCommon'; import { Comment } from '../viewmodel/Comment'; import CommentViewModel from '../viewmodel/CommentViewModel'; -import { ListItemComponent } from '../view/ListItemComponent'; -import { HeadComponent } from '../view/HeadComponent'; -import { MusicInfoComponent } from '../view/MusicInfoComponent'; +import { ListItemComponent } from './ListItemComponent'; +import { HeadComponent } from './HeadComponent'; +import { MusicInfoComponent } from './MusicInfoComponent'; import { CommonConstants } from '../constants/CommonConstants'; -@Entry @Component -struct Index { - @State currentBp: string = BreakpointConstants.CURRENT_BREAKPOINT; +export struct MusicCommentPage { + @StorageProp('currentBreakpoint') currentBp: string = BreakpointConstants.BREAKPOINT_SM; @State wonderfulComment: Comment[] = CommentViewModel.getWonderfulReview(); @State newComment: Comment[] = CommentViewModel.getNewComment(); @@ -181,8 +180,5 @@ struct Index { } } .backgroundColor(Color.White) - .onBreakpointChange((breakpoint) => { - this.currentBp = breakpoint; - }) } } \ No newline at end of file diff --git a/features/musicComment/src/main/module.json5 b/features/musicComment/src/main/module.json5 index 85c114a..373e135 100644 --- a/features/musicComment/src/main/module.json5 +++ b/features/musicComment/src/main/module.json5 @@ -1,14 +1,12 @@ { "module": { "name": "musicComment", - "type": "shared", + "type": "har", "description": "$string:shared_desc", "deviceTypes": [ "phone", "tablet", "2in1" - ], - "deliveryWithInstall": true, - "pages": "$profile:main_pages" + ] } } \ No newline at end of file diff --git a/features/musicComment/src/main/resources/base/profile/main_pages.json b/features/musicComment/src/main/resources/base/profile/main_pages.json deleted file mode 100644 index 1898d94..0000000 --- a/features/musicComment/src/main/resources/base/profile/main_pages.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "src": [ - "pages/Index" - ] -} diff --git a/features/musicList/Index.ets b/features/musicList/Index.ets new file mode 100644 index 0000000..917bff7 --- /dev/null +++ b/features/musicList/Index.ets @@ -0,0 +1,4 @@ +export { Content } from './src/main/ets/components/ListContent'; +export { Header } from './src/main/ets/components/Header'; +export { Player } from './src/main/ets/components/Player'; +export { MusicListPage } from './src/main/ets/view/MusicListPage'; diff --git a/features/musicList/hvigorfile.ts b/features/musicList/hvigorfile.ts index 0e65ea8..e9a64a9 100644 --- a/features/musicList/hvigorfile.ts +++ b/features/musicList/hvigorfile.ts @@ -1,2 +1,2 @@ // 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').hspTasks +module.exports = require('@ohos/hvigor-ohos-plugin').harTasks diff --git a/features/musicList/oh-package.json5 b/features/musicList/oh-package.json5 index b26077e..c1a58ff 100644 --- a/features/musicList/oh-package.json5 +++ b/features/musicList/oh-package.json5 @@ -4,7 +4,7 @@ "author": "", "name": "@ohos/musiclist", "description": "Please describe the basic information.", - "main": "./src/main/ets/Index.ets", + "main": "./Index.ets", "version": "1.0.0", "dependencies": { "@ohos/mediaCommon": "file:../../common/mediaCommon", diff --git a/features/musicList/src/main/ets/Index.ets b/features/musicList/src/main/ets/Index.ets deleted file mode 100644 index ffd08a4..0000000 --- a/features/musicList/src/main/ets/Index.ets +++ /dev/null @@ -1,3 +0,0 @@ -export { Content } from './components/ListContent'; -export { Header } from './components/Header'; -export { Player } from './components/Player'; diff --git a/features/musicList/src/main/ets/components/AlbumComponent.ets b/features/musicList/src/main/ets/components/AlbumComponent.ets index 0856353..56e8610 100644 --- a/features/musicList/src/main/ets/components/AlbumComponent.ets +++ b/features/musicList/src/main/ets/components/AlbumComponent.ets @@ -22,6 +22,7 @@ import { ContentConstants } from '../constants/ContentConstants'; export struct AlbumComponent { @State imgHeight: Length = 0; @Link currentBreakpoint: string; + @StorageLink('pageIndexInfos') pageIndexInfos: NavPathStack = new NavPathStack(); @Builder CoverImage() { @@ -107,7 +108,11 @@ export struct AlbumComponent { lg: $r('app.float.option_font_lg') }).getValue(this.currentBreakpoint)) } - .onClick(item.action) + .onClick(() => { + if (item.action) { + item.action(this.pageIndexInfos); + } + }) }, (item: OptionItem, index?: number) => index + JSON.stringify(item)) } .height($r('app.float.option_area_height')) diff --git a/features/musicList/src/main/ets/components/Header.ets b/features/musicList/src/main/ets/components/Header.ets index 259bdf4..de5c031 100644 --- a/features/musicList/src/main/ets/components/Header.ets +++ b/features/musicList/src/main/ets/components/Header.ets @@ -13,15 +13,15 @@ * limitations under the License. */ -import { router } from '@kit.ArkUI'; import { promptAction } from '@kit.ArkUI'; import { BreakpointType, MenuData } from '@ohos/mediaCommon'; -import { StyleConstants } from '@ohos/constantsCommon'; +import { BreakpointConstants, StyleConstants } from '@ohos/constantsCommon'; import { HeaderConstants } from '../constants/HeaderConstants'; @Component export struct Header { - @Link currentBreakpoint: string; + @StorageProp('currentBreakpoint') currentBreakpoint: string = BreakpointConstants.BREAKPOINT_SM; + @StorageLink('pageIndexInfos') pageIndexInfos: NavPathStack = new NavPathStack(); build() { Row() { @@ -30,7 +30,7 @@ export struct Header { .height($r('app.float.icon_height')) .margin({ left: $r('app.float.icon_margin') }) .onClick(() => { - router.back(); + this.pageIndexInfos.pop(); }) Text($r('app.string.play_list')) .fontSize(new BreakpointType({ diff --git a/features/musicList/src/main/ets/components/ListContent.ets b/features/musicList/src/main/ets/components/ListContent.ets index b2ed1e2..9a5ebc3 100644 --- a/features/musicList/src/main/ets/components/ListContent.ets +++ b/features/musicList/src/main/ets/components/ListContent.ets @@ -13,13 +13,13 @@ * limitations under the License. */ -import { GridConstants, StyleConstants } from '@ohos/constantsCommon'; +import { BreakpointConstants, GridConstants, StyleConstants } from '@ohos/constantsCommon'; import { AlbumCover } from './AlbumCover'; import { PlayList } from './PlayList'; @Component export struct Content { - @Link currentBreakpoint: string; + @StorageProp('currentBreakpoint') currentBreakpoint: string = BreakpointConstants.BREAKPOINT_SM; build() { GridRow() { @@ -34,8 +34,5 @@ export struct Content { .borderRadius($r('app.float.playlist_border_radius')) } .height(StyleConstants.FULL_HEIGHT) - .onBreakpointChange((breakpoints: string) => { - this.currentBreakpoint = breakpoints; - }) } } \ No newline at end of file diff --git a/features/musicList/src/main/ets/components/LyricsComponent.ets b/features/musicList/src/main/ets/components/LyricsComponent.ets index 139f568..a0c7629 100644 --- a/features/musicList/src/main/ets/components/LyricsComponent.ets +++ b/features/musicList/src/main/ets/components/LyricsComponent.ets @@ -52,9 +52,7 @@ export struct LyricsComponent { if (!this.context) { return; } - this.context.createModuleContext('musicList') - .resourceManager - .getRawFileContent(this.songList[this.selectIndex].lyric) + this.context .resourceManager .getRawFileContent(this.songList[this.selectIndex].lyric) .then((value: Uint8Array) => { let textDecoder = util.TextDecoder.create(PlayerConstants.ENCODING, { ignoreBOM: true }); let stringData = textDecoder.decodeWithStream(value, { stream: false }); diff --git a/features/musicList/src/main/ets/components/MusicControlComponent.ets b/features/musicList/src/main/ets/components/MusicControlComponent.ets index d25435d..1422d6a 100644 --- a/features/musicList/src/main/ets/components/MusicControlComponent.ets +++ b/features/musicList/src/main/ets/components/MusicControlComponent.ets @@ -35,6 +35,7 @@ export struct MusicControlComponent { @StorageLink('imageColor') imageColor: string = 'rgba(0, 0, 2, 1.00)'; @StorageLink('topArea') topArea: number = 0; @StorageLink('bottomArea') bottomArea: number = 0; + @State imageLabel: PixelMap | Resource = this.songList[this.selectIndex].label; @State isShowControl: boolean = true; @State isShowControlLg: boolean = false; @State isTablet: boolean = true; @@ -77,7 +78,7 @@ export struct MusicControlComponent { build() { Stack() { - Image(this.songList[this.selectIndex].label) + Image(this.imageLabel) .size(this.currentBreakpoint === BreakpointConstants.BREAKPOINT_LG ? { width: PlayerConstants.BACK_IMAGE @@ -88,7 +89,6 @@ export struct MusicControlComponent { .aspectRatio(1) .objectFit(ImageFit.Cover) .opacity(0.5) - .blur(PlayerConstants.IMAGE_BLUR) Row() { if (this.isFoldFull) { Column() { @@ -244,7 +244,7 @@ export struct MusicControlComponent { if (!this.context) { return ; } - this.context.createModuleContext('musicList').resourceManager.getMediaContent(this.songList[this.selectIndex].label) + this.context.resourceManager.getMediaContent(this.songList[this.selectIndex].label) .then((value: Uint8Array) => { let buffer = value.buffer as ArrayBuffer; image.createImageSource(buffer).createPixelMap().then((pixelMap) => { @@ -257,6 +257,13 @@ export struct MusicControlComponent { this.imageColor = `rgba(${colorArr[0]}, ${colorArr[1]}, ${colorArr[2]}, 1)`; } }) + let headFilter = effectKit.createEffect(pixelMap); + if (headFilter !== null) { + headFilter.blur(PlayerConstants.IMAGE_BLUR); + headFilter.getEffectPixelMap().then((value) => { + this.imageLabel = value; + }) + } }) .catch((error: BusinessError) => { Logger.error(`${error.code} + ${error.message}`) diff --git a/features/musicList/src/main/ets/components/Player.ets b/features/musicList/src/main/ets/components/Player.ets index 9d6865a..0180f13 100644 --- a/features/musicList/src/main/ets/components/Player.ets +++ b/features/musicList/src/main/ets/components/Player.ets @@ -16,7 +16,7 @@ import { curves, window } from '@kit.ArkUI'; import { displaySync } from '@kit.ArkGraphics2D'; import { BusinessError } from '@kit.BasicServicesKit'; -import { StyleConstants } from '@ohos/constantsCommon'; +import { BreakpointConstants, StyleConstants } from '@ohos/constantsCommon'; import { BreakpointType, Logger, MediaService, SongItem } from '@ohos/mediaCommon'; import { PlayerConstants } from '../constants/PlayerConstants'; import { MusicControlComponent } from './MusicControlComponent'; @@ -29,7 +29,7 @@ export struct Player { @StorageLink('songList') songList: SongItem[] = []; @StorageLink('topArea') topArea: number = 0; @StorageLink('bottomArea') bottomArea: number = 0; - @Link currentBreakpoint: string; + @StorageProp('currentBreakpoint') currentBreakpoint: string = BreakpointConstants.BREAKPOINT_SM; @State imageRotate: number = 0; @StorageLink('isShowPlay') isShowPlay: boolean = false; @State componentHeight: number = 0; diff --git a/features/musicList/src/main/ets/constants/PlayerConstants.ets b/features/musicList/src/main/ets/constants/PlayerConstants.ets index 4e9c017..d13109f 100644 --- a/features/musicList/src/main/ets/constants/PlayerConstants.ets +++ b/features/musicList/src/main/ets/constants/PlayerConstants.ets @@ -95,5 +95,5 @@ export class PlayerConstants { /** * Set the image blur level. */ - static readonly IMAGE_BLUR: number = 150; + static readonly IMAGE_BLUR: number = 15; } \ No newline at end of file diff --git a/features/musicList/src/main/ets/pages/Index.ets b/features/musicList/src/main/ets/view/MusicListPage.ets similarity index 87% rename from features/musicList/src/main/ets/pages/Index.ets rename to features/musicList/src/main/ets/view/MusicListPage.ets index 45173e6..ad29881 100644 --- a/features/musicList/src/main/ets/pages/Index.ets +++ b/features/musicList/src/main/ets/view/MusicListPage.ets @@ -20,11 +20,10 @@ import { Player } from '../components/Player'; import { Content } from '../components/ListContent'; import { songList } from '../viewmodel/SongListData' -@Entry @Component -struct Index { +export struct MusicListPage { private breakpointSystem: BreakpointSystem = new BreakpointSystem(); - @State currentBreakpoint: string = BreakpointConstants.BREAKPOINT_SM; + @StorageProp('currentBreakpoint') currentBreakpoint: string = BreakpointConstants.BREAKPOINT_SM; @StorageLink('deviceHeight') deviceHeight: number = 0; aboutToAppear() { @@ -39,9 +38,9 @@ struct Index { build() { Stack({ alignContent: Alignment.Top }) { - Header({ currentBreakpoint: this.currentBreakpoint }) - Content({ currentBreakpoint: this.currentBreakpoint }) - Player({ currentBreakpoint: this.currentBreakpoint }) + Header() + Content() + Player() } .width(StyleConstants.FULL_WIDTH) .backgroundColor(this.currentBreakpoint === BreakpointConstants.BREAKPOINT_SM ? diff --git a/features/musicList/src/main/ets/viewmodel/SongListData.ets b/features/musicList/src/main/ets/viewmodel/SongListData.ets index c59ab67..d7f5303 100644 --- a/features/musicList/src/main/ets/viewmodel/SongListData.ets +++ b/features/musicList/src/main/ets/viewmodel/SongListData.ets @@ -13,7 +13,6 @@ * limitations under the License. */ -import { router } from '@kit.ArkUI'; import { RouterUrlConstants } from '@ohos/constantsCommon'; import { SongItem } from '@ohos/mediaCommon'; @@ -92,10 +91,8 @@ const songList: SongItem[] = [ const optionList : OptionItem[] = [ { image: $r('app.media.ic_collect'), text: $r('app.string.collect') }, { image: $r('app.media.ic_download'), text: $r('app.string.download') }, - { image: $r('app.media.ic_comments'), text: $r('app.string.comment'), action: () => { - router.pushUrl({ - url: RouterUrlConstants.MUSIC_COMMENT - }, router.RouterMode.Single); + { image: $r('app.media.ic_comments'), text: $r('app.string.comment'), action: (pageIndexInfos: NavPathStack) => { + pageIndexInfos.pushPathByName(RouterUrlConstants.MUSIC_COMMENT, null); }}, { image: $r('app.media.ic_share'), text: $r('app.string.share') } ] @@ -103,7 +100,7 @@ const optionList : OptionItem[] = [ class OptionItem { image: Resource = $r('app.media.ic_collect'); text?: Resource; - action?: () => void; + action?: (pageIndexInfos: NavPathStack) => void; } export { optionList, OptionItem, songList } \ No newline at end of file diff --git a/features/musicList/src/main/module.json5 b/features/musicList/src/main/module.json5 index 3a0dc90..2223408 100644 --- a/features/musicList/src/main/module.json5 +++ b/features/musicList/src/main/module.json5 @@ -1,14 +1,12 @@ { "module": { "name": "musicList", - "type": "shared", + "type": "har", "description": "$string:shared_desc", "deviceTypes": [ "phone", "tablet", "2in1" - ], - "deliveryWithInstall": true, - "pages": "$profile:main_pages" + ] } } \ No newline at end of file diff --git a/features/musicList/src/main/resources/base/profile/main_pages.json b/features/musicList/src/main/resources/base/profile/main_pages.json deleted file mode 100644 index 1898d94..0000000 --- a/features/musicList/src/main/resources/base/profile/main_pages.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "src": [ - "pages/Index" - ] -} diff --git a/products/phone/oh-package.json5 b/products/phone/oh-package.json5 index 2c39d0c..8d03a15 100644 --- a/products/phone/oh-package.json5 +++ b/products/phone/oh-package.json5 @@ -7,6 +7,9 @@ "main": "", "version": "1.0.0", "dependencies": { - "@ohos/constantsCommon": "file:../../common/constantsCommon" + "@ohos/constantsCommon": "file:../../common/constantsCommon", + "@ohos/live": "file:../../features/live", + "@ohos/musicComment": "file:../../features/musicComment", + "@ohos/musicList": "file:../../features/musicList" } } diff --git a/products/phone/src/main/ets/entryability/EntryAbility.ets b/products/phone/src/main/ets/entryability/EntryAbility.ets index ce59fd0..1540b53 100644 --- a/products/phone/src/main/ets/entryability/EntryAbility.ets +++ b/products/phone/src/main/ets/entryability/EntryAbility.ets @@ -14,9 +14,12 @@ */ import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit'; import { hilog } from '@kit.PerformanceAnalysisKit'; -import { window } from '@kit.ArkUI'; +import { display, window } from '@kit.ArkUI'; +import { BreakpointConstants } from '@ohos/constantsCommon'; export default class EntryAbility extends UIAbility { + private windowObj?: window.Window; + onCreate(want: Want, launchParam: AbilityConstant.LaunchParam) { AppStorage.setOrCreate('context', this.context) hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate'); @@ -30,6 +33,14 @@ export default class EntryAbility extends UIAbility { // Main window is created, set main page for this ability hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate'); + windowStage.getMainWindow().then((data: window.Window) => { + this.windowObj = data; + this.updateBreakpoint(this.windowObj.getWindowProperties().windowRect.width); + this.windowObj.on('windowSizeChange', (windowSize: window.Size) => { + this.updateBreakpoint(windowSize.width); + }) + }) + windowStage.loadContent('pages/Index', (err) => { if (err.code) { hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? ''); @@ -39,6 +50,19 @@ export default class EntryAbility extends UIAbility { }); } + private updateBreakpoint(windowWidth: number): void{ + let windowWidthVp = windowWidth / display.getDefaultDisplaySync().densityPixels; + let curBp: string = ''; + if (windowWidthVp < BreakpointConstants.BREAKPOINT_VALUE_NUMBER[1]) { + curBp = BreakpointConstants.BREAKPOINT_SM; + } else if (windowWidthVp < BreakpointConstants.BREAKPOINT_VALUE_NUMBER[2]) { + curBp = BreakpointConstants.BREAKPOINT_MD; + } else { + curBp = BreakpointConstants.BREAKPOINT_LG; + } + AppStorage.setOrCreate('currentBreakpoint', curBp); + } + onWindowStageDestroy() { // Main window is destroyed, release UI related resources hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageDestroy'); diff --git a/products/phone/src/main/ets/pages/Index.ets b/products/phone/src/main/ets/pages/Index.ets index ed65bf8..111aca5 100644 --- a/products/phone/src/main/ets/pages/Index.ets +++ b/products/phone/src/main/ets/pages/Index.ets @@ -13,94 +13,122 @@ * limitations under the License. */ -import { router } from '@kit.ArkUI'; +import { BreakpointConstants, RouterUrlConstants, StyleConstants } from '@ohos/constantsCommon'; +import { LivePage } from '@ohos/live'; +import { MusicListPage } from '@ohos/musicList'; +import { MusicCommentPage } from '@ohos/musicComment'; import IndexItem from '../viewmodel/IndexItem'; import IndexViewModel from '../viewmodel/IndexViewModel'; -import { BreakpointConstants, StyleConstants } from '@ohos/constantsCommon' import { HomeConstants } from '../common/constants/HomeConstants'; @Entry @Component struct Index { @State indexItemList: IndexItem[] = IndexViewModel.getIndexItemList(); + @StorageLink('pageIndexInfos') pageIndexInfos: NavPathStack = new NavPathStack(); + + @Builder + PagesMap(name: string, param?: object) { + if (name === RouterUrlConstants.LIVE) { + NavDestination() { + LivePage() + } + .hideTitleBar(true) + } else if (name === RouterUrlConstants.MUSIC_LIST) { + NavDestination() { + MusicListPage() + } + .hideTitleBar(true) + } else if (name === RouterUrlConstants.MUSIC_COMMENT) { + NavDestination() { + MusicCommentPage() + } + .hideTitleBar(true) + } + } build() { - GridRow({ - breakpoints: { - value: BreakpointConstants.BREAKPOINT_VALUE, - reference: BreakpointsReference.WindowSize - }, - columns: { - sm: BreakpointConstants.COLUMN_SM, - md: BreakpointConstants.COLUMN_MD, - lg: BreakpointConstants.COLUMN_LG - }, - gutter: { x: BreakpointConstants.GUTTER_X }, - direction: GridRowDirection.Row - }) { - GridCol({ - span: { - sm: BreakpointConstants.SPAN_SM, - md: BreakpointConstants.SPAN_MD, - lg: BreakpointConstants.SPAN_LG + Navigation(this.pageIndexInfos) { + GridRow({ + breakpoints: { + value: BreakpointConstants.BREAKPOINT_VALUE, + reference: BreakpointsReference.WindowSize }, - offset: { - md: BreakpointConstants.OFFSET_MD, - lg: BreakpointConstants.OFFSET_LG - } + columns: { + sm: BreakpointConstants.COLUMN_SM, + md: BreakpointConstants.COLUMN_MD, + lg: BreakpointConstants.COLUMN_LG + }, + gutter: { x: BreakpointConstants.GUTTER_X }, + direction: GridRowDirection.Row }) { - Column({ space: HomeConstants.COLUMN_SPACE }) { - ForEach(this.indexItemList, (item: IndexItem) => { - Column() { - Text(item.title) - .fontSize($r('app.float.title_font_size')) - .fontColor(Color.White) - Text(item.description) - .fontSize($r('app.float.description_font_size')) - .opacity(HomeConstants.TEXT_OPACITY) - .fontColor(Color.White) - .margin({ - top: $r('app.float.description_margin_top') - }) - Blank() + GridCol({ + span: { + sm: BreakpointConstants.SPAN_SM, + md: BreakpointConstants.SPAN_MD, + lg: BreakpointConstants.SPAN_LG + }, + offset: { + md: BreakpointConstants.OFFSET_MD, + lg: BreakpointConstants.OFFSET_LG + } + }) { + Column({ space: HomeConstants.COLUMN_SPACE }) { + ForEach(this.indexItemList, (item: IndexItem) => { Column() { - Button() { - Text(item.button) - .fontSize($r('app.float.button_font_size')) - .fontColor(Color.White) + Text(item.title) + .fontSize($r('app.float.title_font_size')) + .fontColor(Color.White) + Text(item.description) + .fontSize($r('app.float.description_font_size')) + .opacity(HomeConstants.TEXT_OPACITY) + .fontColor(Color.White) + .margin({ + top: $r('app.float.description_margin_top') + }) + Blank() + Column() { + Button() { + Text(item.button) + .fontSize($r('app.float.button_font_size')) + .fontColor(Color.White) + } + .backgroundColor($r('app.color.button_background_color')) + .borderRadius($r('app.float.button_border_radius')) + .width($r('app.float.button_width')) + .height($r('app.float.button_height')) + .onClick(() => { + this.pageIndexInfos.pushPathByName(item.url, null); + }) } - .backgroundColor($r('app.color.button_background_color')) - .borderRadius($r('app.float.button_border_radius')) - .width($r('app.float.button_width')) - .height($r('app.float.button_height')) - .onClick(() => { - router.pushUrl({ - url: item.url - }, router.RouterMode.Single); - }) + .alignItems(HorizontalAlign.End) + .width(StyleConstants.FULL_WIDTH) } - .alignItems(HorizontalAlign.End) .width(StyleConstants.FULL_WIDTH) - } - .width(StyleConstants.FULL_WIDTH) - .height($r('app.float.item_height')) - .backgroundImage(item.icon) - .backgroundImageSize({ - width: StyleConstants.FULL_WIDTH, - height: $r('app.float.item_height') - }) - .borderRadius($r('app.float.item_border_radius')) - .padding($r('app.float.item_padding')) - .alignItems(HorizontalAlign.Start) - .justifyContent(FlexAlign.SpaceBetween) - }, (item: IndexItem, index?: number) => index + JSON.stringify(item)) + .height($r('app.float.item_height')) + .backgroundImage(item.icon) + .backgroundImageSize({ + width: StyleConstants.FULL_WIDTH, + height: $r('app.float.item_height') + }) + .borderRadius($r('app.float.item_border_radius')) + .padding($r('app.float.item_padding')) + .alignItems(HorizontalAlign.Start) + .justifyContent(FlexAlign.SpaceBetween) + }, (item: IndexItem, index?: number) => index + JSON.stringify(item)) + } } } + .padding({ + top: $r('app.float.column_padding_top'), + left: $r('app.float.column_padding_left'), + right: $r('app.float.column_padding_right') + }) } - .padding({ - top: $r('app.float.column_padding_top'), - left: $r('app.float.column_padding_left'), - right: $r('app.float.column_padding_right') - }) + .mode(NavigationMode.Stack) + .navDestination(this.PagesMap) + .height(StyleConstants.FULL_HEIGHT) + .hideTitleBar(true) + .hideToolBar(true) } } \ No newline at end of file diff --git a/products/phone/src/main/ets/phonebackupextability/PhoneBackupExtAbility.ets b/products/phone/src/main/ets/phonebackupextability/PhoneBackupExtAbility.ets new file mode 100644 index 0000000..925e232 --- /dev/null +++ b/products/phone/src/main/ets/phonebackupextability/PhoneBackupExtAbility.ets @@ -0,0 +1,12 @@ +import { hilog } from '@kit.PerformanceAnalysisKit'; +import { BackupExtensionAbility, BundleVersion } from '@kit.CoreFileKit'; + +export default class PhoneBackupExtAbility extends BackupExtensionAbility { + async onBackup() { + hilog.info(0x0000, 'testTag', 'onBackup ok'); + } + + async onRestore(bundleVersion: BundleVersion) { + hilog.info(0x0000, 'testTag', 'onRestore ok %{public}s', JSON.stringify(bundleVersion)); + } +} \ No newline at end of file diff --git a/products/phone/src/main/ets/viewmodel/IndexViewModel.ets b/products/phone/src/main/ets/viewmodel/IndexViewModel.ets index 9dc42c7..697292e 100644 --- a/products/phone/src/main/ets/viewmodel/IndexViewModel.ets +++ b/products/phone/src/main/ets/viewmodel/IndexViewModel.ets @@ -13,6 +13,7 @@ * limitations under the License. */ +import { RouterUrlConstants } from '@ohos/constantsCommon'; import IndexItem from './IndexItem'; /** @@ -27,11 +28,9 @@ class IndexViewModel { getIndexItemList(): IndexItem[] { let IndexItemList: IndexItem[] = []; IndexItemList.push(new IndexItem($r('app.string.music_title'), $r('app.string.music_description'), - $r('app.string.button_music'), $r('app.media.ic_music'), - '@bundle:com.huawei.music.musichome/musicList/ets/pages/Index')); + $r('app.string.button_music'), $r('app.media.ic_music'), RouterUrlConstants.MUSIC_LIST)); IndexItemList.push(new IndexItem($r('app.string.live_title'), $r('app.string.live_description'), - $r('app.string.button_live'), $r('app.media.ic_live'), - '@bundle:com.huawei.music.musichome/live/ets/pages/Index')); + $r('app.string.button_live'), $r('app.media.ic_live'), RouterUrlConstants.LIVE)); return IndexItemList; } } diff --git a/products/phone/src/main/module.json5 b/products/phone/src/main/module.json5 index 9be8f83..022f1bd 100644 --- a/products/phone/src/main/module.json5 +++ b/products/phone/src/main/module.json5 @@ -14,10 +14,12 @@ "pages": "$profile:main_pages", "requestPermissions": [ { - "name": "ohos.permission.KEEP_BACKGROUND_RUNNING", + "name": "ohos.permission.KEEP_BACKGROUND_RUNNING", "reason": "$string:reason_background", "usedScene": { - "abilities": ["EntryAbility"], + "abilities": [ + "EntryAbility" + ], "when": "always" } } @@ -48,6 +50,20 @@ } ] } + ], + "extensionAbilities": [ + { + "name": "PhoneBackupExtAbility", + "srcEntry": "./ets/phonebackupextability/PhoneBackupExtAbility.ets", + "type": "backup", + "exported": false, + "metadata": [ + { + "name": "ohos.extension.backup", + "resource": "$profile:backup_config" + } + ], + } ] } } \ No newline at end of file diff --git a/products/phone/src/main/resources/base/profile/backup_config.json b/products/phone/src/main/resources/base/profile/backup_config.json new file mode 100644 index 0000000..78f40ae --- /dev/null +++ b/products/phone/src/main/resources/base/profile/backup_config.json @@ -0,0 +1,3 @@ +{ + "allowToBackupRestore": true +} \ No newline at end of file diff --git a/screenshots/device/config.png b/screenshots/device/config.png deleted file mode 100644 index 6ed95b7df4bf3e07423bb2cf401e57a46229c95b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 26186 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 u>6n