!306 【Sample】仿应用参考示例-D

Merge pull request !306 from zhaoxin/appsample_d
This commit is contained in:
openharmony_ci 2023-10-11 09:04:08 +00:00 committed by Gitee
commit fd2e5ed283
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
70 changed files with 6640 additions and 0 deletions

12
sample/AppSampleD/.gitignore vendored Normal file
View File

@ -0,0 +1,12 @@
/node_modules
/oh_modules
/local.properties
/oh-package-lock.json5
/.idea
**/build
/.hvigor
.cxx
/.clangd
/.clang-format
/.clang-tidy
**/.test

View File

@ -0,0 +1,24 @@
/*
* Copyright (c) 2023 Hunan OpenValley 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.
*/
{
"app": {
"bundleName": "com.samples.appsampled",
"vendor": "example",
"versionCode": 1000000,
"versionName": "1.0.0",
"icon": "$media:app_icon",
"label": "$string:app_name"
}
}

View File

@ -0,0 +1,8 @@
{
"string": [
{
"name": "app_name",
"value": "仿应用"
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

View File

@ -0,0 +1,122 @@
# 仿应用示例
### 介绍
本示例主要展示了网络连接、文件上传、音视频播放等媒体方面的应用。
使用说明
1. 搭建服务器环境https://help.jeecg.com/java/setup/tools.html 。
2. 启动服务器:[服务器前端目录](../../../../jeecgboot-vue3-master)[服务器后端目录](../../../../jeecg-boot-master)。
3. 打开应用,此时为仿应用主页,循环播放视频,可点击暂停或者播放。
4. 点击右上角**搜索图标**,可进入搜索页面,默认展示**综合类**结果页面,由于搜索历史记录及对应搜索结果都是静态模拟数据,所以可点击前三个任意一条记录以展示不同搜索结果,也可输入与前三条记录一致的结果以展示不同搜索结果。
5. 点击**头像**可播放音乐,下滑点击**播放**按钮可播放视频。
6. 点击**视频**展示**视频类**结果页面,点击左上角返回图标回到**首页**。
7. 点击首页**消息**进入好友列表,好友列表为模拟数据,只可点击第一位进入聊天页面。
8. 进入聊天页面,输入文字,点击**发送**图标可发送消息至好友,点击返回回到首页。
9. 点击首页**加号**图标进入**录制视频**页面,首先进行授权,每条权限等待上一条权限授权成功后再继续授权,点击**红色按钮**录制,等待若干秒后再次点击停止录制,点击**下一步**进入发布页面。
10. 在发布页面点击右下角**发布按钮**,则发布视频至服务端,发布成功后回到首页。
### 工程目录
```
/Socket
├── entry # 主entry模块目录
│ └── src
│ ├── main
│ ├── ets # ets模块目录
│ ├── components # 组件目录
│ ├── ChatComponent.ets # 聊天
│ ├── MessageComponent.ets # 首页中消息组件
│ ├── SearchComponent.ets # 搜索
│ ├── SearchPlayMusicComponent.ets # 搜索结果综合类音频
│ ├── SearchPlayVideoComponent.ets # 搜索结果综合类视频
│ ├── SearchResultComponent.ets # 搜索结果组件
│ ├── SearchSynthesizeComponent.ets # 搜索结果综合类
│ ├── SearchVideoComponent.ets # 搜索结果视频类
│ ├── VideoComponent.ets # 首页中视频组件
│ ├── controller
│ ├── ChatController.ts # 负责聊天发送消息
│ ├── LoginController.ts # 负责登录
│ ├── UploadController.ts # 负责上传文件
│ ├── entryability
│ ├── appsampled
│ ├── data # 实体类目录
│ ├── ChatBox.ts # 消息信息实体
│ ├── DataSource.ts # 数据源,懒加载使用
│ ├── LoginResult.ts # 登录信息实体
│ ├── R.ts # 返回结果信息实体
│ ├── SearchResult.ts # 搜索结果信息实体
│ ├── Tool.ts # 工具类实体
│ ├── User.ts # 用户类实体
│ ├── pages # 数据源实体
│ ├── CameraPage.ets # 相机录制页面
│ ├── ChatPage.ets # 聊天页面
│ ├── Login.ets # 登录页面
│ ├── PublishPage.ets # 发布页面
│ ├── SearchPage.ets # 搜索页面
│ ├── mock # 模拟数据
│ ├── model
│ ├── AVPlayerModel.ts # 负责音视频播放
│ ├── CameraModel.ts # 负责相机预览和录制等管理
│ ├── MediaModel.ts # 负责媒体查询等媒体文件操作
│ ├── NetworkModel.ts # 负责网络通信等操作
│ ├── pages
│ ├── Index.ets # 首页
│ ├── utils # 工具类目录
```
### 具体实现
- 网络连接合请求:@ohos.net.http
- 消息接收:@ohos.net.webSocket
- 文件上传:@ohos.request
- 文件操作:@ohos.multimedia.mediaLibrary
- 音视频播放:@ohos.multimedia.media
### 相关权限
网络权限: ohos.permission.INTERNET
相机权限: ohos.permission.CAMERA
麦克风权限: ohos.permission.MICROPHONE
媒体位置权限: ohos.permission.MEDIA_LOCATION
媒体文件写入权限: ohos.permission.WRITE_MEDIA
媒体文件读取权限: ohos.permission.READ_MEDIA
### 依赖
1. windows上启动服务器前端代码模拟消息转发服务器[服务器前端目录](../../../../jeecgboot-vue3-master)
2. windows上启动服务器后端代码模拟消息转发服务器[服务器后端目录](../../../../jeecg-boot-master)
### 约束与限制
1. 本示例仅支持标准系统上运行支持设备RK3568。
2. 本示例为Stage模型仅支持API10版本SDK版本号4.0.7.5,镜像版本号: OpenHarmony 4.0.7.5。
3. 本示例需要使用DevEco Studio 3.1 Release (Build Version: 3.1.0.500, built on April 28, 2023)才可编译运行。
4. 本示例在启动前需搭建服务端环境,需与客户端处于同一局域网,成功启动服务端后再运行客户端,服务端代码([服务器前端代码](../../../../jeecgboot-vue3-master)[服务器后端代码](../../../../jeecg-boot-master))。
5. 在进入录制页面授权时,在授权第三条权限之前等待若干秒,等待上一条权限授权成功后再继续授权,否则可能授权失败。
### 下载
如需单独下载本工程,执行如下命令:
```
git init
git config core.sparsecheckout true
echo sample/AppSampleD/ > .git/info/sparse-checkout
git remote add origin https://gitee.com/openharmony/xts_tools.git
git pull origin master
```

View File

@ -0,0 +1,41 @@
/*
* Copyright (c) 2023 Hunan OpenValley 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.
*/
{
"app": {
"signingConfigs": [],
"compileSdkVersion": 11,
"compatibleSdkVersion": 10,
"products": [
{
"name": "default",
"signingConfig": "default"
}
]
},
"modules": [
{
"name": "entry",
"srcPath": "./entry",
"targets": [
{
"name": "default",
"applyToProducts": [
"default"
]
}
]
}
]
}

6
sample/AppSampleD/entry/.gitignore vendored Normal file
View File

@ -0,0 +1,6 @@
/node_modules
/oh_modules
/.preview
/build
/.cxx
/.test

View File

@ -0,0 +1,28 @@
/*
* Copyright (c) 2023 Hunan OpenValley 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.
*/
{
"apiType": 'stageMode',
"buildOption": {
},
"targets": [
{
"name": "default",
"runtimeOS": "OpenHarmony"
},
{
"name": "ohosTest",
}
]
}

View File

@ -0,0 +1,2 @@
// Script for compiling build behavior. It is built in the build plug-in and cannot be modified currently.
export { hapTasks } from '@ohos/hvigor-ohos-plugin';

View File

@ -0,0 +1,24 @@
/*
* Copyright (c) 2023 Hunan OpenValley 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.
*/
{
"license": "",
"devDependencies": {},
"author": "",
"name": "entry",
"description": "Please describe the basic information.",
"main": "",
"version": "1.0.0",
"dependencies": {}
}

View File

@ -0,0 +1,26 @@
/*
* Copyright (c) 2023 Hunan OpenValley 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.
*/
export class ChatBox {
isSend: boolean;
message: string;
userIcon: Resource;
constructor(isSend: boolean, message: string, userIcon: Resource) {
this.isSend = isSend;
this.message = message;
this.userIcon = userIcon;
}
}

View File

@ -0,0 +1,97 @@
/*
* Copyright (c) 2023 Hunan OpenValley 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 type { ChatBox } from './ChatBox';
import Logger from '../../utils/Logger';
class BasicDataSource implements IDataSource {
private listeners: DataChangeListener[] = [];
public totalCount(): number {
return 0;
}
public getData(index: number): ChatBox {
return undefined;
}
registerDataChangeListener(listener: DataChangeListener): void {
if (this.listeners.indexOf(listener) < 0) {
Logger.info('add listener');
this.listeners.push(listener);
}
}
unregisterDataChangeListener(listener: DataChangeListener): void {
const pos = this.listeners.indexOf(listener);
if (pos >= 0) {
Logger.info('remove listener');
this.listeners.splice(pos, 1);
}
}
notifyDataReload(): void {
this.listeners.forEach((listener) => {
listener.onDataReloaded();
});
}
notifyDataAdd(index: number): void {
this.listeners.forEach((listener) => {
listener.onDataAdd(index);
});
}
notifyDataChange(index: number): void {
this.listeners.forEach((listener) => {
listener.onDataChange(index);
});
}
notifyDataDelete(index: number): void {
this.listeners.forEach((listener) => {
listener.onDataDelete(index);
});
}
notifyDataMove(from: number, to: number): void {
this.listeners.forEach((listener) => {
listener.onDataMove(from, to);
});
}
}
export class ChatSource extends BasicDataSource {
private chatsArray: Array<ChatBox> = [];
public totalCount(): number {
return this.chatsArray.length;
}
public getData(index: number): ChatBox {
return this.chatsArray[index];
}
public addData(index: number, data: ChatBox): void {
this.chatsArray.splice(index, 0, data);
this.notifyDataAdd(index);
}
public pushData(data: ChatBox): void {
this.chatsArray.push(data);
this.notifyDataAdd(this.chatsArray.length - 1);
}
}

View File

@ -0,0 +1,52 @@
/*
* Copyright (c) 2023 Hunan OpenValley 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.
*/
export default class LoginResult{
private token: string;
private id: string;
private username: string;
private realName: string;
private avatar: string;
public getToken(): string{
return this.token;
}
public setToken(token: string){
this.token = token;
}
public getId(): string{
return this.id;
}
public setId(id: string){
this.id = id;
}
public getUsername(): string{
return this.username;
}
public setUsername(username: string){
this.username = username;
}
public getRealName(): string{
return this.realName;
}
public setRealName(realName: string){
this.realName = realName;
}
public getAvatar(): string{
return this.avatar;
}
public setAvatar(avatar: string){
this.avatar = avatar;
}
}

View File

@ -0,0 +1,45 @@
/*
* Copyright (c) 2023 Hunan OpenValley 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.
*/
export default class R{
private success: boolean;
private message: string;
private code: number;
private data: any;
public getSuccess(): boolean{
return this.success;
}
public setSuccess(success: boolean){
this.success = success;
}
public getMessage(): string{
return this.message;
}
public setMessage(message: string){
this.message = message;
}
public getCode(): number{
return this.code;
}
public setCode(code: number){
this.code = code;
}
public getData(): any{
return this.data;
}
public setData(data: any){
this.data = data;
}
}

View File

@ -0,0 +1,114 @@
/*
* Copyright (c) 2023 Hunan OpenValley 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.
*/
/**
*
*/
export class AudioInfo{
public audioId: number; // 音频ID
public audioName: string; // 音频名称
public audioIcon: Resource; // 音频图片
public audioAuthorName: string; // 音频作者名称
public audioTime: string; // 音频时间
public audioNum: string; // 音频使用人数
public audio: string; // 播放音频的文件名称
constructor(audioId?: number, audioName?: string, audioIcon?: Resource, audioAuthorName?: string, audioTime?: string, audioNum?: string, audio?: string) {
this.audioId = audioId;
this.audioName = audioName;
this.audioIcon = audioIcon;
this.audioAuthorName = audioAuthorName;
this.audioTime = audioTime;
this.audioNum = audioNum;
this.audio = audio;
}
}
/**
*
*/
export class VideoDetailInfo{
public videoDetailId: number; // 视频ID
public videoDetailAuthorName: string; // 视频作者名称
public videoDetailAuthorIcon: Resource; // 视频作者头像
public videoDetailTime: string; // 视频发布时间
public videoDetailTitle: string; // 视频标题
public videoDetailLabel: string; // 视频标签
public videoDetailLike: string; // 视频点赞数
public videoDetailComment: string; // 视频评论数
public videoDetailCollect: string; // 视频收藏数
public videoDetailTransmit: string; // 视频评论数
public videoDetail: string; // 播放视频的文件名称
public commenterName: string; // 评论人名称
public commenterIcon: Resource; // 评论人头像
public commenterContent: string; // 评论内容
public commenterLike: string; // 评论点赞数
constructor(videoDetailId?: number, videoDetailAuthorName?: string, videoDetailAuthorIcon?: Resource, videoDetailTime?: string, videoDetailTitle?: string, videoDetailLabel?: string,
videoDetailLike?: string, videoDetailComment?: string, videoDetailCollect?: string, videoDetailTransmit?: string, videoDetail?: string,
commenterName?: string, commenterIcon?: Resource, commenterContent?: string, commenterLike?: string) {
this.videoDetailId = videoDetailId;
this.videoDetailAuthorName = videoDetailAuthorName;
this.videoDetailAuthorIcon = videoDetailAuthorIcon;
this.videoDetailTime = videoDetailTime;
this.videoDetailTitle = videoDetailTitle;
this.videoDetailLabel = videoDetailLabel;
this.videoDetailLike = videoDetailLike;
this.videoDetailComment = videoDetailComment;
this.videoDetailCollect = videoDetailCollect;
this.videoDetailTransmit = videoDetailTransmit;
this.videoDetail = videoDetail;
this.commenterName = commenterName;
this.commenterIcon = commenterIcon;
this.commenterContent = commenterContent;
this.commenterLike = commenterLike;
}
}
/**
*
*/
export class VideoInfo{
public videoAuthorName: string; // 视频作者名称
public videoAuthorIcon: Resource; // 视频作者头像
public videoLikeNum: string; // 视频点赞数
public videoTitle: string; // 视频标题
public video: Resource; // 视频展示图片的文件名称
constructor(videoAuthorName?: string, videoAuthorIcon?: Resource, videoLikeNum?: string, videoTitle?: string, video?: Resource) {
this.videoAuthorName = videoAuthorName;
this.videoAuthorIcon = videoAuthorIcon;
this.videoLikeNum = videoLikeNum;
this.videoTitle = videoTitle;
this.video = video;
}
}
/**
*
*/
export class SearchResult{
public labelList: Array<string>;
public audioInfoList: Array<AudioInfo>;
public videoDetailInfo: Array<VideoDetailInfo>;
public videoInfo: Array<VideoInfo>;
constructor(labelList?: Array<string>, audioInfoList?: Array<AudioInfo>, videoDetailInfo?: Array<VideoDetailInfo>, videoInfo?: Array<VideoInfo>) {
this.labelList = labelList;
this.audioInfoList = audioInfoList;
this.videoDetailInfo = videoDetailInfo;
this.videoInfo = videoInfo;
}
}

View File

@ -0,0 +1,36 @@
/*
* Copyright (c) 2023 Hunan OpenValley 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.
*/
export default class Tool{
private toolName: string;
private toolIcon: Resource;
constructor(toolName?: string, toolIcon?: Resource) {
this.toolName = toolName;
this.toolIcon = toolIcon;
}
public getToolName(): string{
return this.toolName;
}
public setToolName(toolName: string){
this.toolName = toolName;
}
public getToolIcon(): Resource{
return this.toolIcon;
}
public setToolIcon(toolIcon: Resource){
this.toolIcon = toolIcon;
}
}

View File

@ -0,0 +1,36 @@
/*
* Copyright (c) 2023 Hunan OpenValley 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.
*/
export default class User{
private username: string;
private userIcon: Resource;
constructor(username?: string, userIcon?: Resource) {
this.username = username;
this.userIcon = userIcon;
}
public getUsername(): string{
return this.username;
}
public setUsername(username: string){
this.username = username;
}
public getUserIcon(): Resource{
return this.userIcon;
}
public setUserIcon(userIcon: Resource){
this.userIcon = userIcon;
}
}

View File

@ -0,0 +1,497 @@
/*
* Copyright (c) 2023 Hunan OpenValley 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 type { Permissions } from '@ohos.abilityAccessCtrl'
import abilityAccessCtrl from '@ohos.abilityAccessCtrl'
import router from '@ohos.router'
import Logger from '../../utils/Logger'
import CameraModel from '../../model/CameraModel'
import User from '../data/User'
const TAG: string = '[CameraPage]'
const PERMISSIONS: Array<Permissions> = ['ohos.permission.READ_MEDIA', 'ohos.permission.WRITE_MEDIA', 'ohos.permission.MEDIA_LOCATION', 'ohos.permission.MICROPHONE', 'ohos.permission.CAMERA']
@Entry
@Component
struct CameraPage {
// 底部特效模拟图片资源数组
private imageList: Array<Resource> = [$r('app.media.app_icon'), $r('app.media.app_icon'), $r('app.media.app_icon'), $r('app.media.app_icon'), $r('app.media.app_icon'), $r('app.media.app_icon')];
// 文字资源数组
private textList: Array<Resource> = [$r('app.string.Word'), $r('app.string.Subsection'), $r('app.string.Video'), $r('app.string.Photo'), $r('app.string.Everyday'), $r('app.string.Live_streaming')];
// 侧边图标资源数组
private sidebarList_1: Array<Resource> = [$r('app.media.app_icon'), $r('app.media.app_icon'), $r('app.media.app_icon'), $r('app.media.app_icon'), $r('app.media.app_icon'), $r('app.media.app_icon')];
private sidebarList_2: Array<Resource> = [$r('app.media.app_icon'), $r('app.media.app_icon'), $r('app.media.app_icon'), $r('app.media.app_icon'), $r('app.media.app_icon'), $r('app.media.app_icon')];
private xComponentController: XComponentController = new XComponentController();
private textTimerController: TextTimerController = new TextTimerController();
private cameraModel: CameraModel = new CameraModel(getContext(this))
private scrollerHorText: Scroller = new Scroller();
private scrollerHorImage: Scroller = new Scroller();
private currentUser: User = null; // 当前用户信息
@State recordingStatus: number = 0; // 0未录制 1正在录制 2结束录制
@State surfaceId: string = '-1';
@State format: string = 'mm:ss';
@State uploadFile: string = '';
pageTransition() {
// 登录页面从底部滑入滑出
PageTransitionEnter({ type: RouteType.Push, duration: 200 })
.slide(SlideEffect.Bottom)
PageTransitionExit({ type: RouteType.Pop, duration: 200 })
.slide(SlideEffect.Bottom)
}
aboutToAppear() {
let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager()
try {
atManager.requestPermissionsFromUser(getContext(this), PERMISSIONS).then((data) => {
this.cameraModel.createCamera(this.surfaceId);
Logger.info(TAG, 'requestPermissionsFromUser success')
}).catch((err) => {
Logger.info(TAG, `requestPermissionsFromUser err: ${JSON.stringify(err)}`)
})
} catch (err) {
Logger.info(TAG, `requestPermissionsFromUser catch err->${JSON.stringify(err)}`);
}
if (globalThis.currentUser) {
this.currentUser = globalThis.currentUser;
}
}
onPageHide() {
Logger.info(TAG, 'page onPageHide');
this.stopVideo();
this.cameraModel.releaseCamera();
}
onPageShow() {
Logger.info(TAG, 'page onPageHide');
this.cameraModel.createCamera(this.surfaceId);
}
startVideo() {
Logger.info(TAG, 'page startVideo');
this.recordingStatus = 1;
this.textTimerController.reset();
this.textTimerController.start();
this.cameraModel.startVideo();
}
async stopVideo() {
Logger.info(TAG, 'page stopVideo');
this.recordingStatus = 2;
this.textTimerController.pause();
this.uploadFile = await this.cameraModel.stopVideo();
Logger.info(TAG, `page stopVideo uploadFile = ${this.uploadFile}`);
}
build() {
Column() {
Stack() {
XComponent({
id: 'xComponentId',
type: 'surface',
controller: this.xComponentController
})
.onLoad(() => {
Logger.info(TAG, 'onLoad is called')
// 设置XComponent创建的曲面宽为640vp高为480vp
this.xComponentController.setXComponentSurfaceSize({ surfaceWidth: 640, surfaceHeight: 480 })
this.surfaceId = this.xComponentController.getXComponentSurfaceId()
Logger.info(TAG, `onLoad surfaceId: ${this.surfaceId}`)
this.cameraModel.createCamera(this.surfaceId)
})
.height('100%')
.width('100%')
Column() {
Row() {
Row() {
Image($r('app.media.app_icon'))
.width(30)
.height(30)
.objectFit(ImageFit.Contain)
}
.width(50)
.height(50)
.justifyContent(FlexAlign.Center)
.onClick(e => {
router.back()
})
.visibility(this.recordingStatus !== 1 ? Visibility.Visible : Visibility.None) // 正在录制时不显示
Row({ space: 8 }) {
Image($r('app.media.app_icon'))
.width(28)
.height(28)
.objectFit(ImageFit.Fill)
.borderRadius(14)
Text($r('app.string.Select_music'))
.textAlign(TextAlign.Center)
.fontColor($r('app.color.COLOR_FFFFFF'))
.fontSize(16)
.fontFamily($r('app.string.Font_family_regular'))
.borderRadius(14)
}
.width(132)
.height(48)
.borderRadius(12)
.backgroundColor($r('app.color.COLOR_669F9B9B'))
.justifyContent(FlexAlign.Center)
.visibility(this.recordingStatus !== 1 ? Visibility.Visible : Visibility.None) // 正在录制时不显示
Row() {
Image($r('app.media.app_icon'))
.width(26)
.height(26)
.objectFit(ImageFit.Contain)
.visibility(this.recordingStatus !== 2 ? Visibility.Visible : Visibility.None) // 非录制结束情况下显示
Image($r('app.media.app_icon'))
.width(26)
.height(26)
.objectFit(ImageFit.Contain)
.visibility(this.recordingStatus === 2 ? Visibility.Visible : Visibility.None) // 录制结束情况时显示
}
.width(42)
.height(42)
}
.width('100%')
.height('8%')
.justifyContent(this.recordingStatus !== 1 ? FlexAlign.SpaceBetween : FlexAlign.End)
Column({ space: 18 }) {
if (this.recordingStatus === 0) {
ForEach(this.sidebarList_1, (sidebar: Resource, index: number) => {
Image($r('app.media.app_icon'))
.width(28)
.height(28)
.objectFit(ImageFit.Contain)
if (index === 1) {
Divider()
.vertical(false)
.height(1)
.width(22)
.color($r('app.color.COLOR_FFFFFF'))
.margin({ right: 4 })
}
})
} else if (this.recordingStatus === 2) {
ForEach(this.sidebarList_2, (sidebar: Resource, index: number) => {
Image($r('app.media.app_icon'))
.width(28)
.height(28)
.objectFit(ImageFit.Contain)
if (index === 0) {
Divider()
.vertical(false)
.height(1)
.width(22)
.color($r('app.color.COLOR_FFFFFF'))
.margin({ right: 4 })
}
if (index === 1) {
Text($r('app.string.Wen'))
.textAlign(TextAlign.Center)
.fontColor($r('app.color.COLOR_FFFFFF'))
.fontSize(22)
.fontFamily($r('app.string.Font_family_medium'))
.margin({ right: 4 })
}
})
}
}
.width('100%')
.height('50%')
.padding({ top: 4, right: 14 })
.alignItems(HorizontalAlign.End)
.visibility(this.recordingStatus === 1 ? Visibility.None : Visibility.Visible) // 正在录制时不显示
Blank()
Column() {
Column() {
Column() {
TextTimer({ isCountDown: false, count: 60000, controller: this.textTimerController })
.height('100%')
.fontSize(18)
.format(this.format)
.fontColor($r('app.color.COLOR_FFFFFF'))
}
.justifyContent(FlexAlign.Start)
.visibility(this.recordingStatus === 1 ? Visibility.Visible : Visibility.Hidden)
.width('100%')
.height('30%')
// 文字列表
Scroll(this.scrollerHorText) {
Row({ space: 42 }) {
ForEach(this.textList, (text: Resource, index: number) => {
Text(text)
.height('100%')
.textAlign(TextAlign.Center)
.fontColor(index === 2 ? $r('app.color.COLOR_EEC934') : $r('app.color.COLOR_FFFFFF'))
.fontSize(16)
.fontFamily($r('app.string.Font_family_medium'))
})
}
.height('100%')
.justifyContent(FlexAlign.Start)
.alignItems(VerticalAlign.Bottom)
}
.width('70%')
.height('100%')
.scrollable(ScrollDirection.Horizontal)
.scrollBar(BarState.Off)
.visibility(this.recordingStatus === 0 ? Visibility.Visible : Visibility.Hidden)
}
.width('100%')
.height('15%')
.justifyContent(FlexAlign.Center)
Row() {
if (this.recordingStatus === 0) {
Column({ space: 6 }) {
Image($r('app.media.app_icon'))
.width(56)
.height(56)
.objectFit(ImageFit.Contain)
.borderRadius(12)
Text($r('app.string.Special'))
.textAlign(TextAlign.Center)
.fontColor($r('app.color.COLOR_FFFFFF'))
.fontSize(16)
.fontFamily($r('app.string.Font_family_medium'))
}
.width(64)
.height(64)
this.StartRecordComponent()
Column({ space: 6 }) {
Image($r('app.media.app_icon'))
.width(56)
.height(56)
.objectFit(ImageFit.Fill)
.borderRadius(12)
Text($r('app.string.Album'))
.textAlign(TextAlign.Center)
.fontColor($r('app.color.COLOR_FFFFFF'))
.fontSize(16)
.fontFamily($r('app.string.Font_family_medium'))
}
.width(64)
.height(64)
} else if (this.recordingStatus === 1) {
this.RecordingComponent()
} else {
this.PointComponent()
}
}
.width('100%')
.height('85%')
.justifyContent(FlexAlign.SpaceEvenly)
}
.width('100%')
.height('25%')
}
.width('100%')
.height('100%')
}
.width('100%')
.height('91%')
.borderRadius(12)
Row({ space: 12 }) {
if (this.recordingStatus === 0) {
Scroll(this.scrollerHorImage) {
Row({ space: 14 }) {
ForEach(this.imageList, (img: Resource) => {
Image($r('app.media.app_icon'))
.width(56)
.height(56)
.objectFit(ImageFit.Fill)
.borderRadius(10)
})
}
.height('100%')
.justifyContent(FlexAlign.Start)
.alignItems(VerticalAlign.Bottom)
.margin({ bottom: 1 })
}
.width('70%')
.height('100%')
.scrollable(ScrollDirection.Horizontal)
.scrollBar(BarState.Off)
} else if (this.recordingStatus === 1) {
} else if (this.recordingStatus === 2) {
Row() {
Image($r('app.media.app_icon'))
.width(28)
.height(28)
.objectFit(ImageFit.Fill)
}
.layoutWeight(1)
.height('80%')
.justifyContent(FlexAlign.Center)
.backgroundColor($r('app.color.COLOR_393939'))
.borderRadius(12)
Row({ space: 8 }) {
if (this.currentUser) {
Image($r('app.media.app_icon'))
.width(28)
.height(28)
.objectFit(ImageFit.Fill)
.borderRadius(14)
}
Text($r('app.string.Send_everyday'))
.textAlign(TextAlign.Center)
.fontColor($r('app.color.COLOR_FFFFFF'))
.fontSize(18)
.fontFamily($r('app.string.Font_family_regular'))
.borderRadius(14)
}
.layoutWeight(2)
.height('80%')
.justifyContent(FlexAlign.Center)
.backgroundColor($r('app.color.COLOR_393939'))
.borderRadius(12)
Row() {
Text($r('app.string.Next'))
.textAlign(TextAlign.Center)
.fontColor($r('app.color.COLOR_FFFFFF'))
.fontSize(18)
.fontFamily($r('app.string.Font_family_regular'))
.borderRadius(14)
}
.id('next')
.layoutWeight(2)
.height('80%')
.justifyContent(FlexAlign.Center)
.backgroundColor($r('app.color.COLOR_FC2B55'))
.borderRadius(12)
.onClick(e => {
this.recordingStatus = 0;
router.pushUrl({
url: 'appsampled/pages/PublishPage',
params: {
uploadFile: this.uploadFile
}
})
})
}
}
.width('100%')
.height('9%')
.justifyContent(FlexAlign.Center)
.padding({ left: 12, right: 12 })
}
.width('100%')
.height('100%')
.backgroundColor($r('app.color.COLOR_000000'))
}
@Builder
StartRecordComponent() {
Column() {
Column()
.width(80)
.height(80)
.backgroundColor(Color.Red)
.borderRadius(40)
}
.id('startVideo')
.width(100)
.height(100)
.border({ width: 5, color: $r('app.color.COLOR_FFFFFF'), radius: 50 })
.alignItems(HorizontalAlign.Center)
.justifyContent(FlexAlign.Center)
.onClick(e => {
this.startVideo();
})
}
@Builder
RecordingComponent() {
Stack() {
Column()
.width(60)
.height(60)
.borderRadius(30)
.backgroundColor($r('app.color.COLOR_E6FFFFFF'))
Column()
.width(20)
.height(20)
.borderRadius(4)
.backgroundColor(Color.Red)
}
.id('stopVideo')
.width(120)
.height(120)
.borderRadius(60)
.backgroundColor($r('app.color.COLOR_80FFFFFF'))
.onClick(e => {
this.stopVideo();
})
}
@Builder
PointComponent() {
Row({ space: 8 }) {
Text()
.width(4)
.height(4)
.backgroundColor($r('app.color.COLOR_CCFFFFFF'))
.borderRadius(2)
Text()
.width(6)
.height(6)
.backgroundColor($r('app.color.COLOR_CCFFFFFF'))
.borderRadius(3)
Text()
.width(8)
.height(8)
.backgroundColor($r('app.color.COLOR_CCFFFFFF'))
.borderRadius(4)
Text()
.width(10)
.height(10)
.backgroundColor($r('app.color.COLOR_FFFFFF'))
.borderRadius(5)
Text()
.width(8)
.height(8)
.backgroundColor($r('app.color.COLOR_CCFFFFFF'))
.borderRadius(4)
Text()
.width(6)
.height(6)
.backgroundColor($r('app.color.COLOR_CCFFFFFF'))
.borderRadius(3)
Text()
.width(4)
.height(4)
.backgroundColor($r('app.color.COLOR_CCFFFFFF'))
.borderRadius(2)
}
.width(100)
.height(30)
.alignItems(VerticalAlign.Center)
.justifyContent(FlexAlign.Center)
}
}

View File

@ -0,0 +1,310 @@
/*
* Copyright (c) 2023 Hunan OpenValley 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 router from '@ohos.router';
import Logger from '../../utils/Logger';
import { ChatSource } from '../data/DataSource';
import ChatComponent from '../../component/ChatComponent'
import { ChatBox } from '../data/ChatBox'
import { getMockTool } from '../../mock/MockData'
import Tool from '../data/Tool'
import User from '../data/User'
import ChatController from '../../controller/ChatController';
import LoginResult from '../data/LoginResult';
const TAG: string = '[ChatPage]';
@Entry
@Component
struct ChatPage {
private scroller: Scroller = new Scroller();
private scrollerTool: Scroller = new Scroller();
@State chats: ChatSource = new ChatSource();
private toolArr: Array<Tool> = getMockTool(); // 用户信息模拟数据
@State isSend: boolean = true; // 是否为发送消息
@State isInput: boolean = false; // 是否正在输入
private currentUser: User = null; // 当前用户信息
private oppositeUser: User = null; // 对端用户信息
private userInfo: LoginResult = null; // 登录返回结果信息
private chatController: ChatController = new ChatController();
@State inputValue: string = '';
aboutToAppear() {
if (globalThis.currentUser) {
this.currentUser = globalThis.currentUser;
}
if (globalThis.oppositeUser) {
this.oppositeUser = globalThis.oppositeUser;
}
if (globalThis.userInfo) {
this.userInfo = globalThis.userInfo
}
this.chatController.onMessage(this.userInfo.getId(), (value) => {
Logger.info(TAG, `ChatPage onMessage begin msg value: ${value}`);
if (value) {
this.chats.pushData(new ChatBox(false, value, this.oppositeUser.getUserIcon()));
}
})
}
build() {
Column() {
Row() {
Image($r('app.media.app_icon'))
.id('chatBack')
.width(20)
.height(20)
.objectFit(ImageFit.Contain)
.margin({ left: 16 })
.onClick(e=>{
router.back();
})
Image($r('app.media.app_icon'))
.width(50)
.height(50)
.objectFit(ImageFit.Contain)
.margin({ left: 16, right: 16 })
.borderRadius(25)
Text(this.oppositeUser.getUsername())
.height(30)
.fontColor($r('app.color.COLOR_FFFFFF'))
.fontSize(20)
.fontFamily($r('app.string.Font_family_regular'))
.textAlign(TextAlign.Center)
Blank()
Image($r('app.media.app_icon'))
.width(32)
.height(32)
.objectFit(ImageFit.Contain)
.margin({ left: 20 })
Image($r('app.media.app_icon'))
.width(32)
.height(32)
.objectFit(ImageFit.Contain)
.margin({ left: 20 })
Image($r('app.media.app_icon'))
.width(32)
.height(32)
.objectFit(ImageFit.Contain)
.margin({ left: 20, right: 20 })
}
.width('100%')
.height('8%')
.justifyContent(FlexAlign.SpaceBetween)
Divider()
.vertical(false)
.height(2)
.color($r('app.color.COLOR_1E1E1E'))
// 消息滚动面板
Column() {
Scroll(this.scroller) {
Column() {
LazyForEach(this.chats, (item, index) => {
Row() {
ChatComponent({ item: item })
}
.margin({ top: 5, bottom: 10 })
}, item => item.message)
}
.width('100%')
.margin({ top: 10 })
}
.scrollable(ScrollDirection.Vertical)
.scrollBar(BarState.Off)
.width('100%')
.height('100%')
.margin({ bottom: 8 })
.align(Alignment.Top)
}
.width('100%')
.height('75%')
Column() {
// 工具栏
Row() {
// 横向工具栏列表
Scroll(this.scrollerTool) {
Row() {
ForEach(this.toolArr, (tool: Tool) => {
Row() {
Image($r('app.media.app_icon'))
.width(30)
.height(30)
.objectFit(ImageFit.Contain)
.margin({ right: 8 })
Text(tool.getToolName())
.height(20)
.fontColor($r('app.color.COLOR_E6FFFFFF'))
.fontSize(16)
.fontFamily($r('app.string.Font_family_regular'))
.textAlign(TextAlign.Center)
.textOverflow({ overflow: TextOverflow.Ellipsis })
}
.width(120)
.height('80%')
.margin({ left: 12 })
.backgroundColor($r('app.color.COLOR_393939'))
.borderRadius(18)
.justifyContent(FlexAlign.Center)
})
}
.height('100%')
.justifyContent(FlexAlign.Start)
}
.scrollable(ScrollDirection.Horizontal)
.scrollBar(BarState.Off)
.width('95%')
.height('100%')
}
.width('100%')
.height('40%')
// 消息输入框
Row() {
this.inputComponent()
}
.width('100%')
.height('60%')
}
.width('100%')
.height('17%')
}
.width('100%')
.height('100%')
.backgroundColor($r('app.color.COLOR_000000'))
}
@Builder
inputComponent() {
Stack() {
Row()
.width('95%')
.height('70%')
.borderRadius(32)
.backgroundColor($r('app.color.COLOR_393939'))
if (this.isInput) {
Row() {
Row() {
Image($r('app.media.app_icon'))
.width(26)
.height(26)
.objectFit(ImageFit.Contain)
}
.width(44)
.height(44)
.margin({ left: 5 })
.borderRadius(22)
.backgroundColor($r('app.color.COLOR_168CF6'))
.justifyContent(FlexAlign.Center)
Blank()
Image($r('app.media.app_icon'))
.width(42)
.height(42)
.objectFit(ImageFit.Contain)
Row() {
Image($r('app.media.app_icon'))
.width(32)
.height(32)
.objectFit(ImageFit.Contain)
}
.id('msgSend')
.width(36)
.height(36)
.margin({ left: 15, right: 10 })
.borderRadius(22)
.backgroundColor($r('app.color.COLOR_FE2B54'))
.justifyContent(FlexAlign.Center)
.onClick(e => {
Logger.info(TAG, 'onClick send');
if (this.inputValue) {
this.chats.pushData(new ChatBox(true, this.inputValue, this.currentUser.getUserIcon()));
this.chatController.sendMessage(this.oppositeUser.getUsername(), this.inputValue);
this.inputValue = '';
}
})
}
.width('95%')
.height('70%')
} else {
Row() {
Row() {
Image($r('app.media.app_icon'))
.width(28)
.height(28)
.objectFit(ImageFit.Contain)
}
.width(44)
.height(44)
.margin({ left: 5 })
.borderRadius(22)
.backgroundColor($r('app.color.COLOR_AE4EF7'))
.justifyContent(FlexAlign.Center)
Blank()
Image($r('app.media.app_icon'))
.width(42)
.height(42)
.objectFit(ImageFit.Contain)
Image($r('app.media.app_icon'))
.width(42)
.height(42)
.objectFit(ImageFit.Contain)
.margin({ left: 15, right: 15 })
Image($r('app.media.app_icon'))
.width(36)
.height(36)
.objectFit(ImageFit.Contain)
.margin({ right: 10 })
}
.width('95%')
.height('70%')
}
TextInput({ placeholder: $r('app.string.Send_Message'), text: this.inputValue })
.id('chatInput')
.width('50%')
.height('65%')
.placeholderColor($r('app.color.COLOR_99F1F3F5'))
.backgroundColor($r('app.color.COLOR_393939'))
.fontColor($r('app.color.COLOR_FFFFFF'))
.offset({ x: -50 })
.padding({ left: 0 })
.onChange(value => {
Logger.info(TAG, `TextInput onChange value= ${value}`);
this.inputValue = value;
if (this.inputValue) {
this.isInput = true;
} else {
this.isInput = false;
}
})
}
.alignContent(Alignment.Center)
.width('100%')
.height('100%')
.backgroundColor($r('app.color.COLOR_000000'))
}
}

View File

@ -0,0 +1,141 @@
/*
* Copyright (c) 2023 Hunan OpenValley 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 promptAction from '@ohos.promptAction';
import router from '@ohos.router';
import Logger from '../../utils/Logger';
import LoginController from '../../controller/LoginController';
import LoginResult from '../data/LoginResult';
import User from '../data/User';
const TAG: string = '[Login]';
@Entry
@Component
struct Login {
private loginController: LoginController = new LoginController();
@State phoneNumber: string = '13111111111';
@State password: string = '123456';
@State isLoginSuccess: boolean = false;
pageTransition(){
// 登录页面从底部滑入滑出
PageTransitionEnter({ type: RouteType.Push, duration: 300 })
.slide(SlideEffect.Bottom)
PageTransitionExit({ type: RouteType.Pop, duration: 300 })
.slide(SlideEffect.Bottom)
}
build() {
Column() {
Row() {
Text($r('app.string.LoginByPhone'))
.height('100%')
.fontColor($r('app.color.COLOR_E6000000'))
.fontSize(24)
.fontFamily($r('app.string.Font_family_medium'))
}
.width('80%')
.height('8%')
.margin({ bottom: 10 })
.justifyContent(FlexAlign.Start)
Column({ space: 10 }) {
Stack() {
TextInput({ placeholder: $r('app.string.Input_phone') })
.width('100%')
.height(50)
.borderRadius(5)
.type(InputType.PhoneNumber)
.onChange(value => {
this.phoneNumber = value;
})
}
.width('80%')
.height(50)
TextInput({ placeholder: $r('app.string.Input_password') })
.width('80%')
.height(50)
.borderRadius(5)
.type(InputType.Password)
.onChange(value => {
this.password = value;
})
Row() {
Image($r('app.media.app_icon'))
.width(240)
.height(25)
.objectFit(ImageFit.Contain)
}
.width('80%')
.height(20)
.justifyContent(FlexAlign.Start)
Text($r('app.string.Login'))
.id('login')
.width('80%')
.height(50)
.borderRadius(10)
.textAlign(TextAlign.Center)
.backgroundColor($r('app.color.COLOR_FF785F'))
.fontColor($r('app.color.COLOR_FFFFFF'))
.fontSize(20)
.fontFamily($r('app.string.Font_family_medium'))
.onClick(e => {
this.loginController.login(this.phoneNumber, this.password).then(res => {
Logger.info(TAG, `login then: ${JSON.stringify(res)}`);
// 提示服务端返回的登录信息
promptAction.showToast({ message: res.getMessage(), duration: 1000, bottom: 500 });
setTimeout(() => {
if (res.getCode() === 200) {
let data: LoginResult = res.getData();
Logger.info(TAG, `login success: ${JSON.stringify(data.getToken())}`);
// 存储用户信息, 包括token
globalThis.userInfo = data;
// 分别存储当前用户和对端用户的用户名和头像
if (data.getUsername() === '13111111111') {
let currUser = new User(data.getUsername(),$r('app.media.app_icon'))
let oppositeUser = new User('13122222222',$r('app.media.app_icon'))
globalThis.currentUser = currUser;
globalThis.oppositeUser = oppositeUser;
}else{
let currentUser = new User(data.getUsername(),$r('app.media.app_icon'))
let oppositeUser = new User('13111111111',$r('app.media.app_icon'))
globalThis.currentUser = currentUser;
globalThis.oppositeUser = oppositeUser;
}
// 跳转页面
router.pushUrl({ url: 'pages/Index' });
return;
}
Logger.info(TAG, `login failed: ${JSON.stringify(res)}`);
}, 800)
}).catch(err => {
Logger.info(TAG, `login err: ${JSON.stringify(err)}`);
promptAction.showToast({ message: $r('app.string.Connection_timesout'), duration: 1000, bottom: 500 });
})
})
}
.width('100%')
.height('92%')
}
.width('100%')
.height('100%')
.backgroundColor($r('app.color.COLOR_FFFFFF'))
}
}

View File

@ -0,0 +1,256 @@
/*
* Copyright (c) 2023 Hunan OpenValley 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 promptAction from '@ohos.promptAction';
import router from '@ohos.router';
import UploadController from '../../controller/UploadController';
import User from '../data/User';
import Logger from '../../utils/Logger';
const TAG: string = '[PublishPage]';
type Item = {
res: Resource,
name: Resource
}
@Entry
@Component
struct PublishPage {
private itemList: Array<Item> = [{ res: $r('app.media.app_icon'), name: $r('app.string.Where_are_you') },
{ res: $r('app.media.app_icon'), name: $r('app.string.Add_applet') },
{ res: $r('app.media.app_icon'), name: $r('app.string.Publicly_visible') },
{ res: $r('app.media.app_icon'), name: $r('app.string.Advanced_setup') }];
private uploadController: UploadController = new UploadController();
private uploadFile: string = router.getParams()['uploadFile']; // 需要上传的文件名
private currentUser: User = null; // 当前用户信息
@State uploadState: boolean = false;
pageTransition() {
// 登录页面从底部滑入滑出
PageTransitionEnter({ type: RouteType.Push, duration: 10 })
.slide(SlideEffect.Right);
PageTransitionExit({ type: RouteType.Pop, duration: 10 })
.slide(SlideEffect.Right);
}
aboutToAppear() {
if (globalThis.currentUser) {
this.currentUser = globalThis.currentUser;
}
}
build() {
Column() {
Row({ space: 12 }) {
Image($r('app.media.app_icon'))
.width(24)
.height(24)
.objectFit(ImageFit.Fill)
Text($r('app.string.Return_edit'))
.textAlign(TextAlign.Center)
.fontColor($r('app.color.COLOR_CCFFFFFF'))
.fontSize(16)
.fontFamily($r('app.string.Font_family_regular'))
.borderRadius(14)
}
.width('100%')
.height('8%')
.padding({ left: 12 })
.onClick(e => {
router.back();
})
Row() {
Column() {
TextArea({ placeholder: $r('app.string.Add_work_description') })
.id('textArea')
.width('100%')
.height('50%')
.fontColor($r('app.color.COLOR_FFFFFF'))
.placeholderColor($r('app.color.COLOR_CCFFFFFF'))
.fontSize(18)
.fontFamily($r('app.string.Font_family_regular'))
Blank()
Row({ space: 6 }) {
Text($r('app.string.Topic'))
.width(88)
.height(42)
.fontColor($r('app.color.COLOR_FFFFFF'))
.backgroundColor($r('app.color.COLOR_669F9B9B'))
.textAlign(TextAlign.Center)
.fontFamily($r('app.string.Font_family_regular'))
.borderRadius(12)
Text($r('app.string.Well_Number_Friend'))
.width(88)
.height(42)
.fontColor($r('app.color.COLOR_FFFFFF'))
.textAlign(TextAlign.Center)
.backgroundColor($r('app.color.COLOR_669F9B9B'))
.fontFamily($r('app.string.Font_family_regular'))
.borderRadius(12)
}
.width('100%')
.height(48)
}
.width('70%')
.height('100%')
.padding({ left: 12 })
Blank()
Stack() {
Image($r('app.media.app_icon'))
.width('80%')
.height('90%')
.objectFit(ImageFit.Fill)
.borderRadius(12)
Text($r('app.string.Select_cover'))
.width('80%')
.height(32)
.fontColor($r('app.color.COLOR_FFFFFF'))
.textAlign(TextAlign.Center)
.backgroundColor($r('app.color.COLOR_669F9B9B'))
.borderRadius(12)
.fontFamily($r('app.string.Font_family_regular'))
}
.width('30%')
.height('100%')
.borderRadius(12)
.alignContent(Alignment.Bottom)
}
.width('100%')
.height('22%')
Divider()
.vertical(false)
.height(1)
.width('92%')
.color($r('app.color.COLOR_5A5B63'))
.margin({ top: 12 })
Column({ space: 2 }) {
ForEach(this.itemList, (item: Item) => {
Row({ space: 12 }) {
Image(item.res)
.width(24)
.height(24)
.objectFit(ImageFit.Fill)
.borderRadius(4)
Text(item.name)
.fontColor($r('app.color.COLOR_FFFFFF'))
.textAlign(TextAlign.Center)
.fontFamily($r('app.string.Font_family_regular'))
Blank()
Image($r('app.media.app_icon'))
.width(18)
.height(18)
.objectFit(ImageFit.Fill)
}
.width('100%')
.height(64)
.padding({ left: 12, right: 12 })
})
}
.width('100%')
.height('40%')
Blank()
// 发布成功的提示
if (this.uploadState) {
Row({ space: 8 }) {
if (this.currentUser) {
Image($r('app.media.app_icon'))
.width(36)
.height(36)
.objectFit(ImageFit.Contain)
.borderRadius(18)
}
Text($r('app.string.Publish_Success'))
.fontColor($r('app.color.COLOR_000000'))
.textAlign(TextAlign.Center)
.fontFamily($r('app.string.Font_family_regular'))
.fontSize(18)
}
.width('96%')
.height(64)
.backgroundColor($r('app.color.COLOR_FFFFFF'))
.margin({ left: 8, right: 8, bottom: 12 })
.padding({ left: 12, right: 12 })
.borderRadius(12)
}
Row({ space: 8 }) {
Row({ space: 8 }) {
Image($r('app.media.app_icon'))
.width(20)
.height(20)
.objectFit(ImageFit.Contain)
.borderRadius(14)
Text($r('app.string.Save_Draft'))
.textAlign(TextAlign.Center)
.fontColor($r('app.color.COLOR_FFFFFF'))
.fontSize(16)
.fontFamily($r('app.string.Font_family_regular'))
.borderRadius(14)
}
.layoutWeight(1)
.height('80%')
.justifyContent(FlexAlign.Center)
.backgroundColor($r('app.color.COLOR_393939'))
.borderRadius(12)
Row({ space: 8 }) {
Image($r('app.media.app_icon'))
.width(20)
.height(20)
.objectFit(ImageFit.Contain)
.borderRadius(14)
Text($r('app.string.Publish'))
.textAlign(TextAlign.Center)
.fontColor($r('app.color.COLOR_FFFFFF'))
.fontSize(16)
.fontFamily($r('app.string.Font_family_regular'))
.borderRadius(14)
}
.id('upload')
.layoutWeight(1)
.height('80%')
.justifyContent(FlexAlign.Center)
.backgroundColor($r('app.color.COLOR_FC2B55'))
.borderRadius(12)
.onClick(e => {
Logger.info(TAG, `uploadFile = ${this.uploadFile}`);
this.uploadController.uploadFile(this.uploadFile).then(res => {
Logger.info(TAG, `uploadFile success= ${JSON.stringify(res)}`);
this.uploadState = true;
setTimeout(() => {
this.uploadState = false;
router.pushUrl({ url: 'pages/Index' })
}, 500)
}).catch(err => {
Logger.info(TAG, `uploadFile faild= ${JSON.stringify(err)}`);
router.pushUrl({ url: 'pages/Index' })
})
})
}
.width('100%')
.height('9%')
.padding({ left: 8, right: 8 })
}
.width('100%')
.height('100%')
.backgroundColor($r('app.color.COLOR_151724'))
}
}

View File

@ -0,0 +1,143 @@
/*
* Copyright (c) 2023 Hunan OpenValley 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 router from '@ohos.router';
import Logger from '../../utils/Logger';
import { getMockSearch } from '../../mock/MockData';
import SearchComponent from '../../component/SearchComponent';
import SearchResultComponent from '../../component/SearchResultComponent';
const TAG: string = '[SearchPage]';
@Entry
@Component
struct SearchPage {
private searchArr: Array<string> = getMockSearch();
@State inputValue: string = '';
@State isInput: boolean = false;
@State isShowResult: boolean = false;
pageTransition(){
// 登录页面从底部滑入滑出
PageTransitionEnter({ type: RouteType.Push, duration: 10 })
.slide(SlideEffect.Right)
PageTransitionExit({ type: RouteType.Pop, duration: 10 })
.slide(SlideEffect.Right)
}
build() {
Column() {
Row() {
Row() {
Image($r('app.media.app_icon'))
.width(22)
.height(22)
.objectFit(ImageFit.Contain)
}
.id('searchBack')
.width(50)
.height('100%')
.justifyContent(FlexAlign.Center)
.onClick(e => {
Logger.info(TAG, `ic_cancel_cir onClick`);
// 如果在搜索结果界面,则返回至搜索界面
if (this.isShowResult) {
this.isShowResult = false;
}else {
// 在搜索界面直接返回上一级页面
router.back();
}
})
Row() {
Image($r('app.media.app_icon'))
.width(24)
.height(24)
.margin({ left: 10, right: 10 })
.objectFit(ImageFit.Contain)
TextInput({ placeholder: this.searchArr[0], text: this.inputValue })
.width('75%')
.height('80%')
.placeholderColor($r('app.color.COLOR_99F1F3F5'))
.fontColor($r('app.color.COLOR_FFFFFF'))
.padding({ left: 0 })
.onChange(value => {
Logger.info(TAG, `TextInput onChange value= ${value}`);
this.inputValue = value;
if (this.inputValue) {
this.isInput = true;
} else {
this.isInput = false;
}
})
Row() {
Image(this.isInput ? $r('app.media.app_icon') : $r('app.media.app_icon'))
.width(24)
.height(24)
.margin({ left: 10, right: 10 })
.objectFit(ImageFit.Contain)
.opacity(0.8)
}
.width(50)
.height('100%')
.onClick(e => {
Logger.info(TAG, `ic_cancel_cir onClick`);
if (this.inputValue) {
this.inputValue = '';
}
})
}
.width('75%')
.height('65%')
.backgroundColor($r('app.color.COLOR_393939'))
.borderRadius(4)
Column(){
Text($r('app.string.Search'))
.fontColor($r('app.color.COLOR_E3163D'))
.fontSize(18)
.fontFamily($r('app.string.Font_family_medium'))
.textAlign(TextAlign.Center)
}
.width(64)
.height('100%')
.alignItems(HorizontalAlign.Center)
.justifyContent(FlexAlign.Center)
.onClick(e=>{
this.isShowResult = true;
})
}
.width('100%')
.height('10%')
.backgroundColor($r('app.color.COLOR_151724'))
Column() {
if (this.isShowResult){
// 搜索结果界面
SearchResultComponent({ inputSearch: this.inputValue })
}else{
// 搜索界面
SearchComponent({inputValue: $inputValue, isShowResult: $isShowResult})
}
}
.width('100%')
.height('90%')
}
.width('100%')
.height('100%')
.backgroundColor($r('app.color.COLOR_151724'))
}
}

View File

@ -0,0 +1,56 @@
/*
* Copyright (c) 2023 Hunan OpenValley 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 { ChatBox } from '../appsampled/data/ChatBox';
@Component
export default struct ChatComponent {
private item: ChatBox = undefined;
build() {
Row() {
if (!this.item.isSend) {
Image($r('app.media.app_icon'))
.width(50)
.height(50)
.objectFit(ImageFit.Contain)
.borderRadius(25)
.margin({ left: 10, right: 10 })
}
Column() {
Text(this.item.message)
.maxLines(5)
.padding(10)
.fontSize(18)
.fontColor($r('app.color.COLOR_FFFFFF'))
.fontFamily($r('app.string.Font_family_regular'))
.borderRadius(14)
.alignSelf(this.item.isSend ? ItemAlign.End : ItemAlign.Start)
.backgroundColor(this.item.isSend ? $r('app.color.COLOR_3DA0F1') : $r('app.color.COLOR_393939'))
}
.width('85%')
if (this.item.isSend) {
Image($r('app.media.app_icon'))
.width(50)
.height(50)
.objectFit(ImageFit.Contain)
.borderRadius(25)
.margin({ left: 10, right: 10 })
}
}
.width('100%')
.height(40)
}
}

View File

@ -0,0 +1,244 @@
/*
* Copyright (c) 2023 Hunan OpenValley 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 router from '@ohos.router';
import User from '../appsampled/data/User';
import { getMockUser } from '../mock/MockData'
import Logger from '../utils/Logger';
const TAG: string = '[MessagePage]';
@Component
export default struct MessagePage {
@State selectDownIndex: number = 2; // 底部选择索引
private scrollerHor: Scroller = new Scroller();
private scrollerVer: Scroller = new Scroller();
private userArr: Array<User> = getMockUser(); // 用户信息模拟数据
private currentUser: User = null; // 当前用户信息
private oppositeUser: User = null; // 对端用户信息
aboutToAppear(){
// globalThis.oppositeUser = new User('13222222222',$r('app.media.ic_headphoto_2'));
if (globalThis.currentUser) {
this.currentUser = globalThis.currentUser;
}
if (globalThis.oppositeUser) {
this.oppositeUser = globalThis.oppositeUser;
// 将模拟数据中的第一条替换成真实对端数据
this.userArr[0].setUsername(this.oppositeUser.getUsername());
this.userArr[0].setUserIcon(this.oppositeUser.getUserIcon());
}
}
build() {
Column() {
Row() {
Image($r('app.media.app_icon'))
.width(30)
.height(30)
.objectFit(ImageFit.Contain)
.margin({ left: 15 })
Image($r('app.media.app_icon'))
.width(40)
.height(40)
.objectFit(ImageFit.Contain)
Image($r('app.media.app_icon'))
.width(30)
.height(30)
.objectFit(ImageFit.Contain)
.margin({ right: 15 })
}
.width('100%')
.height('7%')
.justifyContent(FlexAlign.SpaceBetween)
Column() {
Scroll(this.scrollerVer) {
Column() {
// 横向列表
Scroll(this.scrollerHor) {
Row() {
ForEach(this.userArr, (user) => {
Column(){
Image($r('app.media.app_icon'))
.width(70)
.height(70)
.objectFit(ImageFit.Contain)
.borderRadius(35)
.margin({bottom: 8})
Text(user.getUsername())
.height(20)
.fontColor($r('app.color.COLOR_E6FFFFFF'))
.fontSize(16)
.fontFamily($r('app.string.Font_family_regular'))
.textAlign(TextAlign.Center)
.textOverflow({ overflow: TextOverflow.Ellipsis })
}
.width(90)
.height(90)
})
}
.height('100%')
}
.scrollable(ScrollDirection.Horizontal)
.scrollBar(BarState.Off)
.width('100%')
.height(120)
// 新朋友
Row(){
Column(){
Image($r('app.media.app_icon'))
.width(30)
.height(30)
.objectFit(ImageFit.Contain)
}
.width(60)
.height(60)
.backgroundColor($r('app.color.COLOR_57A9FE'))
.borderRadius(30)
.justifyContent(FlexAlign.Center)
.margin({left: 15, right: 15})
Column({space: 8}){
Text($r('app.string.NewFriend'))
.height(20)
.fontColor($r('app.color.COLOR_FFFFFF'))
.fontSize(18)
.fontFamily($r('app.string.Font_family_regular'))
Text($r('app.string.No_new_notice'))
.height(20)
.fontColor($r('app.color.COLOR_CCFFFFFF'))
.fontSize(16)
.fontFamily($r('app.string.Font_family_regular'))
}
.height(70)
.justifyContent(FlexAlign.Center)
.alignItems(HorizontalAlign.Start)
Blank()
Image($r('app.media.app_icon'))
.width(20)
.height(20)
.objectFit(ImageFit.Contain)
.margin({right: 20})
}
.width('100%')
.height(80)
.alignItems(VerticalAlign.Center)
// 互动消息
Row(){
Column(){
Image($r('app.media.app_icon'))
.width(50)
.height(50)
.objectFit(ImageFit.Contain)
.rotate({angle: -90})
}
.width(60)
.height(60)
.backgroundColor($r('app.color.COLOR_FF689F'))
.borderRadius(30)
.justifyContent(FlexAlign.Center)
.margin({left: 15, right: 15})
Column({space: 8}){
Text($r('app.string.Interactive_message'))
.height(20)
.fontColor($r('app.color.COLOR_FFFFFF'))
.fontSize(18)
.fontFamily($r('app.string.Font_family_regular'))
Text($r('app.string.Interactive_message_content'))
.height(20)
.fontColor($r('app.color.COLOR_CCFFFFFF'))
.fontSize(16)
.fontFamily($r('app.string.Font_family_regular'))
}
.height(70)
.justifyContent(FlexAlign.Center)
.alignItems(HorizontalAlign.Start)
Blank()
Image($r('app.media.app_icon'))
.width(20)
.height(20)
.objectFit(ImageFit.Contain)
.margin({right: 20})
}
.width('100%')
.height(80)
.alignItems(VerticalAlign.Center)
// 竖向列表
ForEach(this.userArr, (user: User, index: number) => {
Row(){
Column(){
Image($r('app.media.app_icon'))
.width(60)
.height(60)
.objectFit(ImageFit.Contain)
.borderRadius(30)
}
.width(60)
.height(60)
.borderRadius(30)
.justifyContent(FlexAlign.Center)
.margin({left: 15, right: 15})
Column({space: 8}){
Text(user.getUsername())
.height(20)
.fontColor($r('app.color.COLOR_FFFFFF'))
.fontSize(18)
.fontFamily($r('app.string.Font_family_regular'))
Text($r('app.string.Greet'))
.height(20)
.fontColor($r('app.color.COLOR_CCFFFFFF'))
.fontSize(16)
.fontFamily($r('app.string.Font_family_regular'))
}
.height(70)
.justifyContent(FlexAlign.Center)
.alignItems(HorizontalAlign.Start)
}
.id(`userID_${index+1}`)
.width('100%')
.height(80)
.alignItems(VerticalAlign.Center)
.onClick(e=>{
if (index !== 0) {
return;
}
router.pushUrl({url: 'appsampled/pages/ChatPage'})
})
})
}
.width('100%')
}
.scrollable(ScrollDirection.Vertical)
.scrollBar(BarState.Off)
.width('100%')
.height('100%')
}
.width('100%')
.height('93%')
}
.width('100%')
.height('100%')
.backgroundColor($r('app.color.COLOR_000000'))
}
}

View File

@ -0,0 +1,98 @@
/*
* Copyright (c) 2023 Hunan OpenValley 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 Logger from '../utils/Logger';
import { getMockSearch } from '../mock/MockData'
const TAG: string = '[SearchComponent]';
@Component
export default struct SearchComponent {
private scroller: Scroller = new Scroller();
private searchArr: Array<string> = getMockSearch();
@Link inputValue: string
@Link isShowResult: boolean // 点击Item改变此值以展示搜索结果页面
build() {
Column() {
Scroll(this.scroller) {
Column({ space: 4 }) {
ForEach(this.searchArr, (item, index) => {
Row() {
Image($r('app.media.app_icon'))
.width(18)
.height(18)
.objectFit(ImageFit.Contain)
.margin({ left: 14, right: 10 })
.opacity(0.8)
Text(item)
.height(20)
.fontColor($r('app.color.COLOR_CCFFFFFF'))
.fontSize(20)
.fontFamily($r('app.string.Font_family_medium'))
.textAlign(TextAlign.Center)
.textOverflow({ overflow: TextOverflow.Ellipsis })
.margin({ right: 12 })
Blank()
Image($r('app.media.app_icon'))
.width(16)
.height(16)
.objectFit(ImageFit.Contain)
.margin({ right: 14 })
.opacity(0.7)
}
.id(`searchItem_${index+1}`)
.width('100%')
.height(40)
.onClick(e => {
// 只有前三条拥有对应的假数据其他item不做处理
if (index < 3) {
this.inputValue = item;
this.isShowResult = true;
}
})
})
}
.width('100%')
}
.scrollable(ScrollDirection.Vertical)
.scrollBar(BarState.Off)
.width('100%')
.height('45%')
.align(Alignment.Top)
Column({ space: 12 }) {
Text($r('app.string.Clear_all_search_record'))
.fontColor($r('app.color.COLOR_5A5B63'))
.fontSize(18)
.fontFamily($r('app.string.Font_family_medium'))
.textAlign(TextAlign.Center)
Divider()
.vertical(false)
.height(1)
.width('90%')
.color($r('app.color.COLOR_5A5B63'))
}
.width('100%')
.height(30)
.margin({ top: 10 })
.justifyContent(FlexAlign.Center)
.alignItems(HorizontalAlign.Center)
}
.width('100%')
.height('100%')
.backgroundColor($r('app.color.COLOR_151724'))
}
}

View File

@ -0,0 +1,162 @@
/*
* Copyright (c) 2023 Hunan OpenValley 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 emitter from '@ohos.events.emitter';
import Logger from '../utils/Logger';
import { AudioInfo } from '../appsampled/data/SearchResult';
import AVPlayerModel from '../model/AVPlayerModel'
import Constant from '../utils/Constant';
const TAG: string = '[SearchPlayMusicComponent]';
@Component
export default struct SearchPlayMusicComponent {
private audioInfo: AudioInfo;
private avPlayerModel: AVPlayerModel = new AVPlayerModel(getContext(this));
@State isCollect: boolean = false;
@State isPlay: boolean = false;
@State isInit: boolean = false;
aboutToAppear() {
// 监听暂停事件,当有其他音乐播放时当前播放
emitter.on({ eventId: Constant.EVENT_PAUSED_AUDIO }, data => {
Logger.info(TAG, `emitter on data = ${JSON.stringify(data)}`)
if (data) {
// 拿出传过来的ID
let audioId = data.data.audioId;
Logger.info(TAG, `emitter on data audioId= ${JSON.stringify(audioId)}`)
// 不与当前ID相同则暂停规避自身也会暂停的问题
if (audioId && audioId !== this.audioInfo.audioId) {
Logger.info(TAG, `emitter on data this.isPlay= ${JSON.stringify(this.isPlay)}`)
if (this.isPlay) {
this.avPlayerModel.paused();
this.isPlay = false;
}
}
}
});
}
build() {
Row() {
// 音乐头像
Stack() {
Image($r('app.media.app_icon'))
.width(74)
.height(74)
.objectFit(ImageFit.Contain)
.borderRadius(10)
Image(this.isPlay ? $r('app.media.app_icon') : $r('app.media.app_icon'))
.width(26)
.height(26)
.objectFit(ImageFit.Contain)
}
.id(`musicID_${this.audioInfo.audioId}`)
.width(74)
.height(74)
.margin({ right: 12 })
.alignContent(Alignment.Center)
.onClick(e => {
// 播放的音乐点击则暂停
if (this.isPlay) {
this.avPlayerModel.paused();
} else {
// 播放当前音乐时发送事件暂停其他音乐播放事件
emitter.emit({ eventId: Constant.EVENT_PAUSED_AUDIO }, {
data: {
['audioId']: this.audioInfo.audioId
}
});
// 第一次点击播放先初始化音乐
if (!this.isInit) {
this.avPlayerModel.avPlayerFdSrcDemo(this.audioInfo.audio);
this.isInit = !this.isInit;
} else {
// 初始化过的直接播放
this.avPlayerModel.play();
}
}
this.isPlay = !this.isPlay;
})
// 音乐信息
Column({ space: 2 }) {
Row({ space: 2 }) {
Image($r('app.media.app_icon'))
.width(18)
.height(18)
.objectFit(ImageFit.Contain)
.borderRadius(10)
Text(this.audioInfo.audioName)
.height(18)
.fontColor($r('app.color.COLOR_FFFFFF'))
.fontSize(16)
.fontFamily($r('app.string.Font_family_medium'))
.textAlign(TextAlign.Start)
}
.height(30)
Text(this.audioInfo.audioAuthorName)
.height(18)
.fontColor($r('app.color.COLOR_CCFFFFFF'))
.fontSize(14)
.fontFamily($r('app.string.Font_family_regular'))
.textAlign(TextAlign.Start)
Row({ space: 5 }) {
Text(this.audioInfo.audioTime)
.height(18)
.fontColor($r('app.color.COLOR_CCFFFFFF'))
.fontSize(14)
.fontFamily($r('app.string.Font_family_regular'))
.textAlign(TextAlign.Start)
Text()
.width(2)
.height(2)
.backgroundColor($r('app.color.COLOR_CCFFFFFF'))
.borderRadius(1)
Text(this.audioInfo.audioNum)
.height(18)
.fontColor($r('app.color.COLOR_CCFFFFFF'))
.fontSize(14)
.fontFamily($r('app.string.Font_family_regular'))
.textAlign(TextAlign.Center)
}
.height(20)
}
.height(70)
.alignItems(HorizontalAlign.Start)
Blank()
Column() {
Image(this.isCollect ? $r('app.media.app_icon') : $r('app.media.app_icon'))
.width(20)
.height(20)
.objectFit(ImageFit.Contain)
.margin({ right: 12 })
}
.width(40)
.height(40)
.justifyContent(FlexAlign.Center)
.alignItems(HorizontalAlign.Center)
.onClick(e => {
this.isCollect = !this.isCollect;
})
}
.height(90)
.width('100%')
}
}

View File

@ -0,0 +1,246 @@
/*
* Copyright (c) 2023 Hunan OpenValley 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 emitter from '@ohos.events.emitter';
import { VideoDetailInfo } from '../appsampled/data/SearchResult';
import AVPlayerModel from '../model/AVPlayerModel'
import Constant from '../utils/Constant';
import Logger from '../utils/Logger';
const TAG: string = '[SearchPlayVideoComponent]';
@Component
export default struct SearchPlayVideoComponent {
private videoDetailInfo: VideoDetailInfo;
private xComponentController: XComponentController = new XComponentController();
private avPlayerModel: AVPlayerModel = new AVPlayerModel(getContext(this));
@State surfaceId: string = '-1';
@State isPlay: boolean = false;
@State isInit: boolean = false;
aboutToAppear() {
// 监听暂停事件,当有其他音乐播放时当前播放
emitter.on({ eventId: Constant.EVENT_PAUSED_VIDEO }, data => {
Logger.info(TAG, `emitter on data = ${JSON.stringify(data)}`)
if (data) {
// 拿出传过来的ID
let videoDetailId = data.data.videoDetailId;
Logger.info(TAG, `emitter on data videoId= ${JSON.stringify(videoDetailId)}`)
// 不与当前ID相同则暂停规避自身也会暂停的问题
if (videoDetailId && videoDetailId !== this.videoDetailInfo.videoDetailId) {
Logger.info(TAG, `emitter on data this.isPlay= ${JSON.stringify(this.isPlay)}`)
if (this.isPlay) {
this.avPlayerModel.paused();
this.isPlay = false;
}
}
}
});
}
build() {
Column() {
// 作者信息
Row({ space: 8 }) {
Image($r('app.media.app_icon'))
.width(48)
.height(48)
.objectFit(ImageFit.Contain)
.borderRadius(24)
Column({ space: 5 }) {
Text(this.videoDetailInfo.videoDetailAuthorName)
.height(18)
.fontColor($r('app.color.COLOR_FFFFFF'))
.fontSize(18)
.fontFamily($r('app.string.Font_family_medium'))
.textAlign(TextAlign.Start)
Text(this.videoDetailInfo.videoDetailTime)
.height(18)
.fontColor($r('app.color.COLOR_CCFFFFFF'))
.fontSize(14)
.fontFamily($r('app.string.Font_family_regular'))
.textAlign(TextAlign.Start)
}
.height(80)
.justifyContent(FlexAlign.Center)
.alignItems(HorizontalAlign.Start)
Blank()
Image($r('app.media.app_icon'))
.width(22)
.height(30)
.objectFit(ImageFit.Contain)
.margin({ right: 5 })
}
.width('100%')
.height(70)
// 视频Title
Column({ space: 5 }) {
Text(this.videoDetailInfo.videoDetailTitle)
.fontColor($r('app.color.COLOR_FFFFFF'))
.fontSize(18)
.fontFamily($r('app.string.Font_family_regular'))
.textAlign(TextAlign.Start)
.textOverflow({ overflow: TextOverflow.Ellipsis })
Text(this.videoDetailInfo.videoDetailLabel)
.fontColor($r('app.color.COLOR_EEC934'))
.fontSize(18)
.maxLines(3)
.fontFamily($r('app.string.Font_family_regular'))
.textAlign(TextAlign.Start)
.textOverflow({ overflow: TextOverflow.Ellipsis })
}
.width('100%')
.height(60)
.justifyContent(FlexAlign.Center)
.alignItems(HorizontalAlign.Start)
// 视频
Stack() {
XComponent({
id: 'xComponentId',
type: 'surface',
controller: this.xComponentController
})
.onLoad(() => {
Logger.info(TAG, 'onLoad is called')
this.xComponentController.setXComponentSurfaceSize({ surfaceWidth: 640, surfaceHeight: 480 })
this.surfaceId = this.xComponentController.getXComponentSurfaceId()
Logger.info(TAG, `onLoad surfaceId: ${this.surfaceId}`)
})
.height('100%')
.width('100%')
.borderRadius(14)
Row() {
Image(this.isPlay ? $r('app.media.app_icon') : $r('app.media.app_icon'))
.width(24)
.height(24)
.objectFit(ImageFit.Contain)
}
.width(56)
.height(56)
.justifyContent(FlexAlign.Center)
.onClick(e => {
Logger.info(TAG, `onClick this.isPlay= ${JSON.stringify(this.isPlay)}`)
// 播放的视频点击则暂停
if (this.isPlay) {
this.avPlayerModel.paused();
} else {
// 播放当前视频时发送事件暂停其他视频播放事件
emitter.emit({ eventId: Constant.EVENT_PAUSED_VIDEO }, {
data: {
['videoDetailId']: this.videoDetailInfo.videoDetailId
}
});
// 第一次点击播放先初始化音乐
if (!this.isInit) {
this.avPlayerModel.avPlayerFdSrcDemo(this.videoDetailInfo.videoDetail, this.surfaceId);
this.isInit = !this.isInit;
} else {
Logger.info(TAG, `onClick Play= ${JSON.stringify(this.isInit)}`)
// 初始化过的直接播放
this.avPlayerModel.play();
}
}
this.isPlay = !this.isPlay;
})
}
.width('100%')
.height(300)
.alignContent(Alignment.BottomEnd)
// 视频点赞等信息
Row() {
this.Item($r('app.media.app_icon'), this.videoDetailInfo.videoDetailLike)
this.Item($r('app.media.app_icon'), this.videoDetailInfo.videoDetailComment)
this.Item($r('app.media.app_icon'), this.videoDetailInfo.videoDetailCollect)
this.Item($r('app.media.app_icon'), this.videoDetailInfo.videoDetailTransmit)
}
.width('100%')
.height(50)
.padding({ left: 10, right: 10 })
.justifyContent(FlexAlign.SpaceBetween)
// 视频具体评论信息
Row({ space: 8 }) {
Image($r('app.media.app_icon'))
.width(36)
.height(36)
.objectFit(ImageFit.Contain)
.borderRadius(18)
Column({ space: 5 }) {
Text(this.videoDetailInfo.commenterName)
.height(18)
.fontColor($r('app.color.COLOR_FFFFFF'))
.fontSize(18)
.fontFamily($r('app.string.Font_family_medium'))
.textAlign(TextAlign.Start)
Text(this.videoDetailInfo.commenterContent)
.height(18)
.fontColor($r('app.color.COLOR_CCFFFFFF'))
.fontSize(14)
.fontFamily($r('app.string.Font_family_regular'))
.textAlign(TextAlign.Start)
}
.height(60)
.justifyContent(FlexAlign.Center)
.alignItems(HorizontalAlign.Start)
Blank()
Column() {
Image($r('app.media.app_icon'))
.width(22)
.height(30)
.objectFit(ImageFit.Contain)
Text(this.videoDetailInfo.commenterLike)
.height(18)
.fontColor($r('app.color.COLOR_CCFFFFFF'))
.fontSize(14)
.fontFamily($r('app.string.Font_family_regular'))
.textAlign(TextAlign.Start)
}
.width(48)
.height(48)
.justifyContent(FlexAlign.Center)
}
.width('100%')
.height(70)
.padding({ left: 10, right: 10 })
}
.width('100%')
.height(550)
.backgroundColor($r('app.color.COLOR_151724'))
}
@Builder
Item(img: Resource, num: string) {
Row({ space: 8 }) {
Image($r('app.media.app_icon'))
.width(24)
.height(24)
.objectFit(ImageFit.Contain)
Text(num)
.fontColor($r('app.color.COLOR_FFFFFF'))
.fontSize(16)
.fontFamily($r('app.string.Font_family_regular'))
.textAlign(TextAlign.Center)
}
.width(64)
.height(48)
.justifyContent(FlexAlign.Center)
}
}

View File

@ -0,0 +1,134 @@
/*
* Copyright (c) 2023 Hunan OpenValley 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 router from '@ohos.router';
import Logger from '../utils/Logger';
import { getMockSearchResult, MockInput } from '../mock/MockData';
import { SearchResult } from '../appsampled/data/SearchResult';
import SearchSynthesizeComponent from './SearchSynthesizeComponent';
import SearchVideoComponent from './SearchVideoComponent';
const TAG: string = '[SearchResultComponent]';
@Component
export default struct SearchResultComponent {
private scrollerHor_1: Scroller = new Scroller();
private titleList: Array<Resource> = [$r('app.string.Synthesize'), $r('app.string.Video'), $r('app.string.Music'),
$r('app.string.User'), $r('app.string.Commodity'), $r('app.string.Live_streaming')];
private searchResultList: Array<SearchResult> = getMockSearchResult(); // mock
private inputSearch: string = ''; // 搜索输入框输入的字符串
@State currSearchResult: SearchResult = this.searchResultList[0]; // mock
@State selectTopIndex: number = 0; // 综合、视频等title选择索引
aboutToAppear() {
// 默认值
if (this.inputSearch === '') {
this.inputSearch = MockInput.TEST_INPUT_CONTENT_1;
}
// 依据不同的搜索展示不同的模拟数据
Logger.info(TAG, `this.inputSearch: ${JSON.stringify(this.inputSearch)}`);
if (this.inputSearch.indexOf(MockInput.TEST_INPUT_CONTENT_1) !== -1) {
// 输入"黑夜问白天"的模拟数据
this.currSearchResult = this.searchResultList[0];
} else if (this.inputSearch.indexOf(MockInput.TEST_INPUT_CONTENT_2) !== -1) {
// 输入"哦想"的模拟数据
this.currSearchResult = this.searchResultList[1];
} else if (this.inputSearch.indexOf(MockInput.TEST_INPUT_CONTENT_3) !== -1) {
// 输入"我不愿让你一个人"的模拟数据
this.currSearchResult = this.searchResultList[2];
}
Logger.info(TAG, `this.currSearchResult: ${JSON.stringify(this.currSearchResult)}`);
}
build() {
Column() {
Row() {
// 横向Label列表
Scroll(this.scrollerHor_1) {
Row() {
ForEach(this.titleList, (title: Resource, index: number) => {
Column() {
Text(title)
.width(60)
.height(20)
.fontColor(this.selectTopIndex === index ? $r('app.color.COLOR_FFFFFF') : $r('app.color.COLOR_CCFFFFFF'))
.fontSize(18)
.fontFamily($r('app.string.Font_family_medium'))
.textAlign(TextAlign.Center)
Divider()
.vertical(false)
.height(20)
.width(60)
.strokeWidth(3)
.color($r('app.color.COLOR_D7B837'))
.visibility(this.selectTopIndex === index ? Visibility.Visible : Visibility.Hidden)
}
.id(`titleID_${index+1}`)
.width(78)
.height('100%')
.onClick(e => {
this.selectTopIndex = index;
})
})
}
.height('100%')
.justifyContent(FlexAlign.Start)
}
.scrollable(ScrollDirection.Horizontal)
.scrollBar(BarState.Off)
.width('90%')
.height('100%')
Row() {
Image($r('app.media.app_icon'))
.width(18)
.height(18)
.objectFit(ImageFit.Contain)
.margin({ left: 4, top: 2 })
}
.width('10%')
.height('100%')
.justifyContent(FlexAlign.Center)
.alignItems(VerticalAlign.Top)
}
.width('100%')
.height('6%')
.padding({ left: 8, right: 6 })
.justifyContent(FlexAlign.Start)
.backgroundColor($r('app.color.COLOR_151724'))
Divider()
.vertical(false)
.height(1)
.width('100%')
.color($r('app.color.COLOR_5A5B63'))
Column() {
if (this.selectTopIndex === 0){
SearchSynthesizeComponent({currSearchResult: this.currSearchResult})
}else if (this.selectTopIndex === 1){
SearchVideoComponent({currSearchResult: this.currSearchResult})
}
}
.width('100%')
.height('94%')
}
.width('100%')
.height('100%')
.backgroundColor($r('app.color.COLOR_151724'))
}
}

View File

@ -0,0 +1,157 @@
/*
* Copyright (c) 2023 Hunan OpenValley 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 { AudioInfo, SearchResult, VideoDetailInfo } from '../appsampled/data/SearchResult';
import SearchPlayMusicComponent from './SearchPlayMusicComponent';
import SearchPlayVideoComponent from './SearchPlayVideoComponent';
import Logger from '../utils/Logger';
const TAG: string = '[SearchSynthesizeComponent]';
@Component
export default struct SearchSynthesizeComponent {
private scrollerHor: Scroller = new Scroller();
private scrollerVer: Scroller = new Scroller();
private currSearchResult: SearchResult;
@State selectTopIndex: number = 0;
build() {
Column() {
Scroll(this.scrollerVer) {
Column() {
// 横向Label列表
Row() {
Scroll(this.scrollerHor) {
Row({ space: 8 }) {
// 全部
Column() {
Text($r('app.string.All'))
.height(20)
.fontColor(this.selectTopIndex === 0 ? $r('app.color.COLOR_FFFFFF') : $r('app.color.COLOR_CCFFFFFF'))
.fontSize(16)
.fontFamily($r('app.string.Font_family_medium'))
.textAlign(TextAlign.Center)
.padding({ left: 16, right: 16 })
}
.height(40)
.justifyContent(FlexAlign.Center)
.backgroundColor(this.selectTopIndex === 0 ? $r('app.color.COLOR_393939') : $r('app.color.COLOR_99393939'))
.borderRadius(4)
.onClick(e => {
this.selectTopIndex = 0;
})
// 模拟数据 label列表
ForEach(this.currSearchResult.labelList, (title: string, index: number) => {
Column() {
Text(title)
.height(20)
.fontColor(this.selectTopIndex === (index + 1) ? $r('app.color.COLOR_FFFFFF') : $r('app.color.COLOR_CCFFFFFF'))
.fontSize(16)
.fontFamily($r('app.string.Font_family_medium'))
.textAlign(TextAlign.Center)
.padding({ left: 16, right: 16 })
}
.height(40)
.justifyContent(FlexAlign.Center)
.backgroundColor(this.selectTopIndex === (index + 1) ? $r('app.color.COLOR_393939') : $r('app.color.COLOR_99393939'))
.borderRadius(4)
.onClick(e => {
this.selectTopIndex = index + 1;
})
})
}
.height('100%')
.justifyContent(FlexAlign.Start)
}
.scrollable(ScrollDirection.Horizontal)
.scrollBar(BarState.Off)
.width('100%')
.height('100%')
}
.width('100%')
.height(60)
.justifyContent(FlexAlign.Start)
.padding({ left: 14, right: 8 })
// 音乐列表
Column() {
// 音乐 Title
Row() {
Text($r('app.string.Music'))
.width(60)
.height(20)
.fontColor($r('app.color.COLOR_FFFFFF'))
.fontSize(18)
.fontFamily($r('app.string.Font_family_medium'))
.textAlign(TextAlign.Start)
Blank()
Image($r('app.media.app_icon'))
.width(22)
.height(30)
.objectFit(ImageFit.Contain)
Image($r('app.media.app_icon'))
.width(18)
.height(18)
.objectFit(ImageFit.Contain)
.margin({ left: 25, right: 14 })
}
.width('100%')
.height(40)
.margin({ top: 10 })
// 模拟数据 音乐列表
ForEach(this.currSearchResult.audioInfoList, (audioInfo: AudioInfo) => {
SearchPlayMusicComponent({ audioInfo: audioInfo })
})
}
.width('100%')
.justifyContent(FlexAlign.Start)
.padding({ left: 14, right: 14 })
// 模拟数据 视频详细信息列表
Column() {
ForEach(this.currSearchResult.videoDetailInfo, (videoDetailInfo: VideoDetailInfo) => {
Divider()
.vertical(false)
.height(10)
.width('100%')
.strokeWidth(8)
.color($r('app.color.COLOR_000000'))
Column() {
SearchPlayVideoComponent({ videoDetailInfo: videoDetailInfo })
}
.width('100%')
.padding({ left: 14, right: 14 })
})
}
.width('100%')
.justifyContent(FlexAlign.Start)
}
.width('100%')
}
.scrollable(ScrollDirection.Vertical)
.scrollBar(BarState.Off)
.width('100%')
.height('100%')
.align(Alignment.Top)
}
.width('100%')
.height('100%')
.backgroundColor($r('app.color.COLOR_151724'))
}
}

View File

@ -0,0 +1,168 @@
/*
* Copyright (c) 2023 Hunan OpenValley 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 router from '@ohos.router';
import Logger from '../utils/Logger';
import { SearchResult, VideoInfo } from '../appsampled/data/SearchResult';
const TAG: string = '[SearchVideoComponent]';
@Component
export default struct SearchVideoComponent {
private scrollerHor: Scroller = new Scroller();
private scrollerVer: Scroller = new Scroller();
private currSearchResult: SearchResult;
@State selectTopIndex: number = 0;
build() {
Column() {
Scroll(this.scrollerVer) {
Column() {
// 横向Label列表
Row() {
Scroll(this.scrollerHor) {
Row({ space: 8 }) {
// 全部
Column() {
Text($r('app.string.All'))
.height(20)
.fontColor(this.selectTopIndex === 0 ? $r('app.color.COLOR_FFFFFF') : $r('app.color.COLOR_CCFFFFFF'))
.fontSize(16)
.fontFamily($r('app.string.Font_family_medium'))
.textAlign(TextAlign.Center)
.padding({ left: 16, right: 16 })
}
.height(40)
.justifyContent(FlexAlign.Center)
.backgroundColor(this.selectTopIndex === 0 ? $r('app.color.COLOR_393939') : $r('app.color.COLOR_99393939'))
.borderRadius(4)
.onClick(e => {
this.selectTopIndex = 0;
})
// 模拟数据 label列表
ForEach(this.currSearchResult.labelList, (title: string, index: number) => {
Column() {
Text(title)
.height(20)
.fontColor(this.selectTopIndex === (index + 1) ? $r('app.color.COLOR_FFFFFF') : $r('app.color.COLOR_CCFFFFFF'))
.fontSize(16)
.fontFamily($r('app.string.Font_family_medium'))
.textAlign(TextAlign.Center)
.padding({ left: 16, right: 16 })
}
.height(40)
.justifyContent(FlexAlign.Center)
.backgroundColor(this.selectTopIndex === (index + 1) ? $r('app.color.COLOR_393939') : $r('app.color.COLOR_99393939'))
.borderRadius(4)
.onClick(e => {
this.selectTopIndex = index + 1;
})
})
}
.height('100%')
.justifyContent(FlexAlign.Start)
}
.scrollable(ScrollDirection.Horizontal)
.scrollBar(BarState.Off)
.width('100%')
.height('100%')
}
.width('100%')
.height(60)
.justifyContent(FlexAlign.Start)
.padding({ left: 14, right: 8 })
// 视频列表
GridRow({columns: 2}) {
// 模拟数据 音乐列表
ForEach(this.currSearchResult.videoInfo, (videoInfo: VideoInfo) => {
GridCol() {
this.VideoItem(videoInfo)
}
.width('100%')
.margin({right: 1,bottom:1})
})
}
.width('100%')
}
.width('100%')
}
.scrollable(ScrollDirection.Vertical)
.scrollBar(BarState.Off)
.width('100%')
.height('100%')
.align(Alignment.Top)
}
.width('100%')
.height('100%')
.backgroundColor($r('app.color.COLOR_151724'))
}
@Builder
VideoItem(videoInfo: VideoInfo) {
Stack() {
Image($r('app.media.app_icon'))
.width('100%')
.height('100%')
.objectFit(ImageFit.Fill)
.borderRadius(4)
Column() {
Text(videoInfo.videoTitle)
.fontColor($r('app.color.COLOR_FFFFFF'))
.fontSize(18)
.fontFamily($r('app.string.Font_family_regular'))
.textAlign(TextAlign.Start)
.textOverflow({ overflow: TextOverflow.Ellipsis })
.padding({ left: 6, right: 6 })
Row({space: 5}) {
Image($r('app.media.app_icon'))
.width(24)
.height(24)
.objectFit(ImageFit.Contain)
.borderRadius(12)
Text(videoInfo.videoAuthorName)
.fontColor($r('app.color.COLOR_FFFFFF'))
.fontSize(18)
.fontFamily($r('app.string.Font_family_regular'))
.textAlign(TextAlign.Start)
.textOverflow({ overflow: TextOverflow.Ellipsis })
Blank()
Image($r('app.media.app_icon'))
.width(24)
.height(24)
.objectFit(ImageFit.Contain)
.borderRadius(12)
Text(videoInfo.videoLikeNum)
.fontColor($r('app.color.COLOR_FFFFFF'))
.fontSize(18)
.fontFamily($r('app.string.Font_family_regular'))
.textAlign(TextAlign.Start)
.textOverflow({ overflow: TextOverflow.Ellipsis })
}
.width('100%')
.height(30)
.padding({ left: 6, right: 6 })
}
.width('100%')
.height(56)
.alignItems(HorizontalAlign.Start)
}
.width('100%')
.height(280)
.backgroundColor(Color.Pink)
.alignContent(Alignment.Bottom)
}
}

View File

@ -0,0 +1,297 @@
/*
* Copyright (c) 2023 Hunan OpenValley 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 router from '@ohos.router';
import Logger from '../utils/Logger';
import AVPlayerModel from '../model/AVPlayerModel';
import Constant from '../utils/Constant';
import emitter from '@ohos.events.emitter';
const TAG: string = '[VideoComponent]';
@Component
export default struct VideoComponent {
private xComponentController: XComponentController = new XComponentController();
private avPlayerModel: AVPlayerModel = new AVPlayerModel(getContext(this));
@State surfaceId: string = '-1';
@State selectTopIndex: number = 4; // 顶部选择索引
@State isLike: boolean = false; // 是否喜欢
@State isCollect: boolean = false; // 是否收藏
@State isPlay: boolean = true; // 是否播放
aboutToAppear() {
// 监听暂停事件,当有其他音乐播放时当前播放
emitter.on({ eventId: Constant.EVENT_PAUSED_INDEX }, data => {
Logger.info(TAG, `emitter on data = ${JSON.stringify(data)}`)
Logger.info(TAG, `emitter on data this.isPlay= ${JSON.stringify(this.isPlay)}`)
if (this.isPlay) {
this.avPlayerModel.paused();
this.isPlay = false;
}
});
}
build() {
Column() {
Stack() {
XComponent({
id: 'xComponentId',
type: 'surface',
controller: this.xComponentController
})
.onLoad(() => {
Logger.info(TAG, 'onLoad is called')
// 设置XComponent创建的曲面宽为640vp高为480vp
this.xComponentController.setXComponentSurfaceSize({ surfaceWidth: 640, surfaceHeight: 480 })
this.surfaceId = this.xComponentController.getXComponentSurfaceId()
Logger.info(TAG, `onLoad surfaceId: ${this.surfaceId}`)
this.avPlayerModel.avPlayerFdSrcDemo(Constant.TEST_NAME_DEMO_VIDEO, this.surfaceId)
})
.height('100%')
.width('100%')
Column() {
Row({space:28}) {
Image($r('app.media.app_icon'))
.width(30)
.height(30)
.objectFit(ImageFit.Contain)
Text($r('app.string.Stroll'))
.height('100%')
.fontColor(this.selectTopIndex === 0 ? $r('app.color.COLOR_FFFFFF') : $r('app.color.COLOR_CCFFFFFF'))
.fontSize(22)
.fontFamily($r('app.string.Font_family_medium'))
.onClick(e => {
this.selectTopIndex = 0;
})
Text($r('app.string.Experience'))
.height('100%')
.fontColor(this.selectTopIndex === 1 ? $r('app.color.COLOR_FFFFFF') : $r('app.color.COLOR_CCFFFFFF'))
.fontSize(22)
.fontFamily($r('app.string.Font_family_medium'))
.onClick(e => {
this.selectTopIndex = 1;
})
Text($r('app.string.Attention'))
.height('100%')
.fontColor(this.selectTopIndex === 2 ? $r('app.color.COLOR_FFFFFF') : $r('app.color.COLOR_CCFFFFFF'))
.fontSize(22)
.fontFamily($r('app.string.Font_family_medium'))
.onClick(e => {
this.selectTopIndex = 2;
})
Text($r('app.string.Store'))
.height('100%')
.fontColor(this.selectTopIndex === 3 ? $r('app.color.COLOR_FFFFFF') : $r('app.color.COLOR_CCFFFFFF'))
.fontSize(22)
.fontFamily($r('app.string.Font_family_medium'))
.onClick(e => {
this.selectTopIndex = 3;
})
Text($r('app.string.Recommend'))
.height('100%')
.fontColor(this.selectTopIndex === 4 ? $r('app.color.COLOR_FFFFFF') : $r('app.color.COLOR_CCFFFFFF'))
.fontSize(22)
.fontFamily($r('app.string.Font_family_medium'))
.onClick(e => {
this.selectTopIndex = 4;
})
Row(){
Image($r('app.media.app_icon'))
.id('search')
.width(30)
.height(30)
.objectFit(ImageFit.Contain)
}
.width(40)
.height(50)
.justifyContent(FlexAlign.Center)
.onClick(e => {
Logger.info(TAG, `search_white onClick`);
emitter.emit({ eventId: Constant.EVENT_PAUSED_INDEX });
router.pushUrl({url: 'appsampled/pages/SearchPage'})
})
}
.width('100%')
.height('8%')
.justifyContent(FlexAlign.Center)
Blank()
Row() {
Column() {
Text($r('app.string.UserNick'))
.height(30)
.fontColor($r('app.color.COLOR_FFFFFF'))
.fontSize(22)
.fontFamily($r('app.string.Font_family_medium'))
.margin({ left: 15, bottom: 10 })
Text($r('app.string.TikContent'))
.fontColor($r('app.color.COLOR_E6FFFFFF'))
.fontSize(20)
.fontFamily($r('app.string.Font_family_regular'))
.margin({ left: 15, bottom: 20 })
}
.width('85%')
.height('100%')
.alignItems(HorizontalAlign.Start)
.justifyContent(FlexAlign.End)
Column({space: 10}) {
Stack(){
Image($r('app.media.app_icon'))
.width(60)
.height(60)
.objectFit(ImageFit.Contain)
.borderRadius(30)
.border({color: $r('app.color.COLOR_FFFFFF'), width: 2})
Image($r('app.media.app_icon'))
.width(20)
.height(20)
.objectFit(ImageFit.Contain)
.borderRadius(10)
.offset({y: 10})
}
.width(60)
.height(60)
.margin({bottom: 10})
.alignContent(Alignment.Bottom)
Column(){
Image(this.isLike ? $r('app.media.app_icon') : $r('app.media.app_icon'))
.width(35)
.height(35)
.objectFit(ImageFit.Contain)
.onClick(e=>{
this.isLike = !this.isLike;
Logger.info(TAG, `isLike= ${this.isLike}`);
})
Text($r('app.string.Num',"273.1"))
.width(60)
.height(20)
.fontColor($r('app.color.COLOR_E6FFFFFF'))
.fontSize(14)
.fontFamily($r('app.string.Font_family_regular'))
.textAlign(TextAlign.Center)
}
.width(60)
.height(60)
.alignItems(HorizontalAlign.Center)
this.Item($r('app.media.app_icon'),$r('app.string.Num','36.3'),()=> {
Logger.info(TAG, 'ic_message');
})
Column(){
Image(this.isCollect ? $r('app.media.app_icon') : $r('app.media.app_icon'))
.width(35)
.height(35)
.objectFit(ImageFit.Contain)
.onClick(e=>{
this.isCollect = !this.isCollect;
Logger.info(TAG, `isCollect= ${this.isCollect}`);
})
Text($r('app.string.Num','18.9'))
.width(60)
.height(20)
.fontColor($r('app.color.COLOR_E6FFFFFF'))
.fontSize(14)
.fontFamily($r('app.string.Font_family_regular'))
.textAlign(TextAlign.Center)
}
.width(60)
.height(60)
.alignItems(HorizontalAlign.Center)
this.Item($r('app.media.app_icon'),$r('app.string.Num','40.2'),()=> {
Logger.info(TAG, 'ic_transmit');
})
Column(){
Image($r('app.media.app_icon'))
.width(20)
.height(20)
.objectFit(ImageFit.Contain)
}
.width(50)
.height(50)
.justifyContent(FlexAlign.Center)
.borderRadius(25)
.margin({bottom: 20})
.backgroundColor($r('app.color.COLOR_FFFFFF'))
}
.width('15%')
.height('100%')
}
.width('100%')
.height('60%')
}
.width('100%')
.height('100%')
Column(){
if (!this.isPlay){
Image($r('app.media.app_icon'))
.width(640)
.height(64)
.objectFit(ImageFit.Contain)
.opacity(0.6)
}
}
.id('video_action')
.width('60%')
.height('70%')
.justifyContent(FlexAlign.Center)
.onClick(e=>{
if (this.isPlay) {
this.avPlayerModel.paused();
} else {
this.avPlayerModel.play();
}
this.isPlay = !this.isPlay;
})
}
.width('100%')
.height('100%')
.alignContent(Alignment.Center)
}
.width('100%')
.height('100%')
.backgroundColor($r('app.color.COLOR_000000'))
}
@Builder
Item(img: Resource, num: Resource, callback) {
Column() {
Image(img)
.width(35)
.height(35)
.objectFit(ImageFit.Contain)
.onClick(e => {
callback();
})
Text(num)
.width(60)
.height(20)
.fontColor($r('app.color.COLOR_E6FFFFFF'))
.fontSize(14)
.fontFamily($r('app.string.Font_family_regular'))
.textAlign(TextAlign.Center)
}
.width(60)
.height(60)
.alignItems(HorizontalAlign.Center)
}
}

View File

@ -0,0 +1,79 @@
/*
* Copyright (c) 2023 Hunan OpenValley 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 http from '@ohos.net.http';
import Logger from '../utils/Logger';
import Constant from '../utils/Constant';
import NetworkModel from '../model/NetworkModel';
import R from '../appsampled/data/R';
const TAG: string = '[ChatController]';
export default class ChatController {
private networkModel: NetworkModel = new NetworkModel();
/**
*
* @param username
* @param msg
* @returns
*/
public async sendMessage(username: string, msg: string): Promise<R> {
Logger.info(TAG, `sendMessage username->${username}msg->${msg}`);
let extraData = {
msgType: 'system',
receiver: username,
templateCode: 'sampled',
templateName: 'appsampled',
testData: `{ \"content\": \"${msg}\" }`
};
Logger.info(TAG, `sendMessage extraData->${JSON.stringify(extraData)}`);
let response = await this.networkModel.request(Constant.ACTION_SEND_MESSAGE, http.RequestMethod.POST, extraData, globalThis.userInfo.token);
// 拿到响应中服务端返回的数据
Logger.info(TAG, `sendMessage response.result->${JSON.stringify(response.result)}`);
let data = response.result.toString();
// 将其转成Json数据
let jsonData = JSON.parse(data);
Logger.info(TAG, `sendMessage jsonData->${JSON.stringify(jsonData)}`);
// 统一的返回类型
let result = new R();
result.setSuccess(jsonData.success);
result.setCode(jsonData.code);
result.setMessage(jsonData.message);
Logger.info(TAG, `sendMessage result->${JSON.stringify(result)}`);
return result;
}
/**
*
* @param id
* @param callback
*/
public onMessage(id: string, callback) {
Logger.info(TAG, `onMessage begin id:${id}`);
this.networkModel.onMessage(id, globalThis.userInfo.token, (value) => {
Logger.info(TAG, `onMessage value: ${value}`);
let result = JSON.parse(value);
Logger.info(TAG, `onMessage result: ${result}`);
Logger.info(TAG, `onMessage msgTxt: ${result.msgTxt}`);
if (result.msgTxt) {
let message = JSON.parse(result.msgTxt);
Logger.info(TAG, `onMessage content: ${message.content}`);
callback(message.content)
}
});
Logger.info(TAG, 'onMessage end');
}
}

View File

@ -0,0 +1,59 @@
/*
* Copyright (c) 2023 Hunan OpenValley 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 http from '@ohos.net.http';
import Logger from '../utils/Logger';
import Constant from '../utils/Constant';
import NetworkModel from '../model/NetworkModel';
import LoginResult from '../appsampled/data/LoginResult';
import R from '../appsampled/data/R';
const TAG: string = '[LoginController]';
export default class LoginController {
private networkModel: NetworkModel = new NetworkModel();
public async login(phoneNumber: string, password: string): Promise<R> {
Logger.info(TAG, `login phoneNumber->${phoneNumber}password->${password}`);
let extraData = {
username: phoneNumber,
password: password
};
Logger.info(TAG, `login extraData->${JSON.stringify(extraData)}`)
let response = await this.networkModel.request(Constant.ACTION_LOGIN, http.RequestMethod.POST, extraData);
// 拿到响应中服务端返回的数据
let data = response.result.toString();
// 将其转成Json数据
let jsonData = JSON.parse(data);
Logger.info(TAG, `login jsonData->${JSON.stringify(jsonData)}`)
// 统一的返回类型
let result = new R();
let loginResult = null;
// result不为空则赋值其中的数据
if (jsonData.result) {
loginResult = new LoginResult();
loginResult.setToken(jsonData.result.token);
loginResult.setUsername(jsonData.result.userInfo.username);
loginResult.setRealName(jsonData.result.userInfo.realname);
loginResult.setAvatar(jsonData.result.userInfo.avatar);
loginResult.setId(jsonData.result.userInfo.id);
}
result.setSuccess(jsonData.success);
result.setCode(jsonData.code);
result.setMessage(jsonData.message);
// 设置返回的数据
result.setData(loginResult);
return result;
}
}

View File

@ -0,0 +1,40 @@
/*
* Copyright (c) 2023 Hunan OpenValley 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 http from '@ohos.net.http';
import Logger from '../utils/Logger';
import Constant from '../utils/Constant';
import NetworkModel from '../model/NetworkModel';
const TAG: string = '[UploadController]';
export default class UploadController {
private networkModel: NetworkModel = new NetworkModel();
public async uploadFile(fileName: string): Promise<void> {
Logger.info(TAG, `uploadFile start`);
let extraData = {
name: fileName,
url: `${Constant.UPLOAD_URL}/${fileName}`
};
Logger.info(TAG, `uploadFile extraData->${JSON.stringify(extraData)}`);
this.networkModel.uploadFile(Constant.ACTION_UPLOAD, fileName, (res) => {
if (res) {
Logger.info(TAG, `uploadFile success`);
// 上传成功后请求服务器添加文件
this.networkModel.request(Constant.ACTION_ADD_FILE, http.RequestMethod.POST, extraData, globalThis.userInfo.token);
}
});
}
}

View File

@ -0,0 +1,62 @@
/*
* Copyright (c) 2023 Hunan OpenValley 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 UIAbility from '@ohos.app.ability.UIAbility';
import hilog from '@ohos.hilog';
import window from '@ohos.window';
import Logger from '../utils/Logger'
const TAG: string = '[EntryAbility]'
export default class EntryAbility extends UIAbility {
onCreate(want, launchParam) {
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate');
globalThis.abilityContext = this.context
Logger.info(TAG, `onCreate:${this.context.cacheDir}`)
Logger.info(TAG, `onCreate:${this.context.filesDir}`)
}
onDestroy() {
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDestroy');
}
onWindowStageCreate(windowStage: window.WindowStage) {
// Main window is created, set main page for this ability
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate');
// pages/Index
windowStage.loadContent('pages/Index', (err, data) => {
if (err.code) {
hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');
return;
}
hilog.info(0x0000, 'testTag', 'Succeeded in loading the content. Data: %{public}s', JSON.stringify(data) ?? '');
});
}
onWindowStageDestroy() {
// Main window is destroyed, release UI related resources
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageDestroy');
}
onForeground() {
// Ability has brought to foreground
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onForeground');
}
onBackground() {
// Ability has back to background
hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onBackground');
}
}

View File

@ -0,0 +1,167 @@
/*
* Copyright (c) 2023 Hunan OpenValley 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 User from '../appsampled/data/User';
import Tool from '../appsampled/data/Tool';
import { SearchResult, AudioInfo, VideoDetailInfo, VideoInfo } from '../appsampled/data/SearchResult'
export class MockInput {
public static readonly TEST_INPUT_CONTENT_1: string = '黑夜问白天';
public static readonly TEST_INPUT_CONTENT_2: string = '哦想';
public static readonly TEST_INPUT_CONTENT_3: string = '我不愿让你一个人';
}
export function getMockUser(): Array<User> {
let userArr: Array<User> = [];
userArr.push(new User('opposite user', $r('app.media.app_icon')));
userArr.push(new User('user1', $r('app.media.app_icon')));
userArr.push(new User('user2', $r('app.media.app_icon')));
userArr.push(new User('user3', $r('app.media.app_icon')));
userArr.push(new User('user4', $r('app.media.app_icon')));
userArr.push(new User('user5', $r('app.media.app_icon')));
userArr.push(new User('user6', $r('app.media.app_icon')));
userArr.push(new User('user7', $r('app.media.app_icon')));
userArr.push(new User('user8', $r('app.media.app_icon')));
return userArr;
}
export function getMockTool(): Array<Tool> {
let userArr: Array<Tool> = [];
userArr.push(new Tool('打招呼', $r('app.media.app_icon')));
userArr.push(new Tool('比个心', $r('app.media.app_icon')));
userArr.push(new Tool('相册随机', $r('app.media.app_icon')));
userArr.push(new Tool('以图换图', $r('app.media.app_icon')));
userArr.push(new Tool('视频通话', $r('app.media.app_icon')));
return userArr;
}
export function getMockSearch(): Array<string> {
let arr: Array<string> = [];
arr.push('黑夜问白天');
arr.push('哦想');
arr.push('我不愿让你一个人');
arr.push('test data 4');
arr.push('测试数据 5');
arr.push('test data 6');
arr.push('测试数据 7');
arr.push('test data 8');
arr.push('测试数据 9');
return arr;
}
export function getMockSearchResult(): Array<SearchResult> {
let labelList: Array<Array<string>> = getLabelList();
let audioInfoList: Array<Array<AudioInfo>> = getAudioInfoList();
let videoDetailInfoList: Array<Array<VideoDetailInfo>> = getVideoDetailInfoList();
let videoInfoList: Array<Array<VideoInfo>> = getVideoInfoList();
let searchResultList: Array<SearchResult> = [
new SearchResult(labelList[0], audioInfoList[0], videoDetailInfoList[0], videoInfoList[0]),
new SearchResult(labelList[1], audioInfoList[1], videoDetailInfoList[1], videoInfoList[1]),
new SearchResult(labelList[2], audioInfoList[2], videoDetailInfoList[2], videoInfoList[2]),
];
return searchResultList;
}
function getLabelList(): Array<Array<string>> {
let labelList: Array<Array<string>> = [
['翻唱', '林俊杰', '合拍', '吉他弹唱', '女生', '歌曲教学'],
['手势舞', '翻唱', '舞蹈', '安与骑兵', '广场舞', '疯狂梗传'],
['伴奏', '五月天', '合唱', '林俊杰', '吉他弹唱', '钢琴']
];
return labelList;
}
function getAudioInfoList(): Array<Array<AudioInfo>> {
let audioInfoList: Array<Array<AudioInfo>> = [
[
new AudioInfo(1, '黑夜问白天', $r('app.media.app_icon'), '林俊杰', '02:03', '42.7万人使用', 'demo_video.mp4'),
new AudioInfo(2, '黑夜问白天TV', $r('app.media.app_icon'), '林俊杰', '00:32', '22.4万使用', 'demo_video.mp4'),
new AudioInfo(3, '黑夜问白天(演唱会)', $r('app.media.app_icon'), '林俊杰', '01:31', '35.6万使用', 'demo_video.mp4')
],
[
new AudioInfo(1, '哦想', $r('app.media.app_icon'), '安与骑兵', '01:04', '1.7万人使用', 'demo_video.mp4'),
new AudioInfo(2, '哦想(剪辑版)', $r('app.media.app_icon'), '安与骑兵', '00:30', '1685人使用', 'demo_video.mp4'),
new AudioInfo(3, '哦想Cover安与骑兵', $r('app.media.app_icon'), '听月@国酒香', '0104', '3309人使用', 'demo_video.mp4')
],
[
new AudioInfo(1, '我不愿让你一个人', $r('app.media.app_icon'), '五月天', '01:00', '3.3万人使用', 'demo_video.mp4'),
new AudioInfo(2, '我不愿让你一个人(剪辑版)', $r('app.media.app_icon'), '年岁并进', '00:35', '1.3万人使用', 'demo_video.mp4'),
new AudioInfo(3, '我不愿让你一个人', $r('app.media.app_icon'), '五月天', '01:00', '982人使用', 'demo_video.mp4')
]
];
return audioInfoList;
}
function getVideoDetailInfoList(): Array<Array<VideoDetailInfo>> {
let videoDetailInfoList: Array<Array<VideoDetailInfo>> = [
[
new VideoDetailInfo(1, '重拾快乐~', $r('app.media.app_icon'), '2021.10.12', '《黑夜问白天》林俊杰', '#林俊杰', '2.8w', '2188', '8487', '8062', 'demo_video.mp4', '韦德', $r('app.media.app_icon'), '贫穷让我们相遇', '3711'),
new VideoDetailInfo(2, '俊杰观察', $r('app.media.app_icon'), '2022.02.28', '林俊杰清唱功底有多强', '#林俊杰#黑夜问白天#清唱', '49.3w', '3.6w', '2.7w', '4.4w', 'demo_video.mp4', '小桃冰茶', $r('app.media.app_icon'), '可以没有伴奏,不能没有提词器', '7.5万'),
new VideoDetailInfo(3, '王巨星', $r('app.media.app_icon'), '2021.11.30', '好喜欢的歌啊啊啊啊', '#林俊杰', '65.5w', '1.5w', '2.3w', '2.8w', 'demo_video.mp4', 'LCCL', $r('app.media.app_icon'), '如果王巨星回复了我,我就好好生活', '2.4万')
],
[
new VideoDetailInfo(1, '青鸟艺术声乐培训', $r('app.media.app_icon'), '2022.06.10', '给高考准备的一首歌', '#青鸟艺术声乐培训#高考#小助手', '85.6w', '3.6w', '6.2w', '6.0w', 'demo_video.mp4', '小小的太阳', $r('app.media.app_icon'), '我的喉咙只适合做核酸', '4.5万'),
new VideoDetailInfo(2, 'Old马声乐小课堂', $r('app.media.app_icon'), '2022.11.16', '艺考选取曲子不能盲目跟风 挑选合适自己的作品最重要', '#音乐艺考生#声乐教学#无声卡演唱', '1.5w', '640', '1190', '2228', 'demo_video.mp4', 'zhongchuYYDS', $r('app.media.app_icon'), '感觉她咬字太流行了', '1486'),
new VideoDetailInfo(3, '女王', $r('app.media.app_icon'), '2022.06.12', '安于骑兵演唱的《哦想》', '#聆听天籁之音#音乐分享', '3042', '244', '1174', '1319', 'demo_video.mp4', '用户5295745367339', $r('app.media.app_icon'), '还是原唱好', '101')
],
[
new VideoDetailInfo(1, '一只喵', $r('app.media.app_icon'), '2023.05.29', '如果相识不能相恋 是不是还不如擦肩', '#五月天 #林俊杰 #我不愿让你一个人 #突然好想你', '21.4w', '1.7w', '2.7w', '3.2w', 'demo_video.mp4', '1', $r('app.media.app_icon'), '这四首歌放一起', '1.6万'),
new VideoDetailInfo(2, '碑海北', $r('app.media.app_icon'), '2021.11.23', '我不愿让你一个人', '#奔向浪漫', '45.5w', '4.0w', '1.8w', '9.0w', 'demo_video.mp4', 'veafew520', $r('app.media.app_icon'), '为什么看这样的视频会哭?', '1.3万'),
new VideoDetailInfo(3, '诺', $r('app.media.app_icon'), '2023.01.02', '懂你疼你更好的人', '#我不愿让你一个人', '14.4w', '5469', '9736', '1.4w', 'demo_video.mp4', '橘澜', $r('app.media.app_icon'), '不出意外的话这辈子都见不到了', '5554')
]
];
return videoDetailInfoList;
}
function getVideoInfoList(): Array<Array<VideoInfo>> {
let videoInfoList: Array<Array<VideoInfo>> = [
[
new VideoInfo('重拾快乐~', $r('app.media.app_icon'), '2.8w', '《黑夜问白天》林俊杰', $r('app.media.app_icon')),
new VideoInfo('王巨星', $r('app.media.app_icon'), '65.5w', '好喜欢的歌啊啊啊啊', $r('app.media.app_icon')),
new VideoInfo('林俊杰', $r('app.media.app_icon'), '108.2w', '今晚大家开心吗', $r('app.media.app_icon')),
new VideoInfo('俊杰观察', $r('app.media.app_icon'), '49.3w', '林俊杰清唱功底有多强?', $r('app.media.app_icon')),
new VideoInfo('心跳乱了节奏', $r('app.media.app_icon'), '8467', '大哥又是压轴!熬最深的夜,看年少青春', $r('app.media.app_icon')),
new VideoInfo('俊杰观察', $r('app.media.app_icon'), '17.2w', '在半空中真好...不会吵...被忽略的好歌!', $r('app.media.app_icon')),
new VideoInfo('音雨蓝', $r('app.media.app_icon'), '4.9w', '湖南女子学院校园操场上,小哥翻唱林俊杰《黑夜问白天》', $r('app.media.app_icon')),
new VideoInfo('会火大明星', $r('app.media.app_icon'), '3.3w', '没人可以拒绝黑夜问白天全程跟唱!', $r('app.media.app_icon')),
new VideoInfo('曹雨航', $r('app.media.app_icon'), '59.0w', '等再见不如说一次再见#林俊杰', $r('app.media.app_icon')),
new VideoInfo('音雨蓝', $r('app.media.app_icon'), '17.5w', '#大学生活#黑夜问白天翻唱', $r('app.media.app_icon'))
],
[
new VideoInfo('民谣小酒馆', $r('app.media.app_icon'), '1.6w', '清澈的嗓音,宛如天籁之音', $r('app.media.app_icon')),
new VideoInfo('Old马声乐小课堂', $r('app.media.app_icon'), '1.5w', '艺考选取曲子不能盲目跟风 挑选合适自己的作品最重要', $r('app.media.app_icon')),
new VideoInfo('女王', $r('app.media.app_icon'), '3043', '安于骑兵演唱的《哦想》', $r('app.media.app_icon')),
new VideoInfo('故里音乐', $r('app.media.app_icon'), '123', '有粉丝说想听#完整版必须安排上', $r('app.media.app_icon')),
new VideoInfo('倾听音乐', $r('app.media.app_icon'), '7543', '《哦,想》被小女孩和老师唱红了全网', $r('app.media.app_icon')),
new VideoInfo('安与骑兵', $r('app.media.app_icon'), '1.6w', '#安与骑兵 清唱《哦!想》', $r('app.media.app_icon')),
new VideoInfo('688音乐视频', $r('app.media.app_icon'), '1.0w', '第18集 女孩刚刚开口歌声已经是我醉了', $r('app.media.app_icon')),
new VideoInfo('忆路音乐', $r('app.media.app_icon'), '2.8w', '来听听原唱,哦了半天发现我这嗓子还是只适合做核酸', $r('app.media.app_icon')),
new VideoInfo('郭一橙', $r('app.media.app_icon'), '1870', '#真人真唱#广场舞', $r('app.media.app_icon')),
new VideoInfo('歌吧音乐', $r('app.media.app_icon'), '5.3w', '干净的声音,犹如天籁,生活明朗,万物可爱', $r('app.media.app_icon'))
],
[
new VideoInfo('五月天饭团', $r('app.media.app_icon'), '45.8w', '#五月天 五月天的歌里什么都有,唯独没有纠缠', $r('app.media.app_icon')),
new VideoInfo('碑海北', $r('app.media.app_icon'), '45.5w', '我不愿让你一个人', $r('app.media.app_icon')),
new VideoInfo('碑海北', $r('app.media.app_icon'), '33.7w', '一段健康的感情可以让你每晚平静入睡', $r('app.media.app_icon')),
new VideoInfo('一只喵', $r('app.media.app_icon'), '21.4w', '如果相识不能相恋 是不是还不如擦肩', $r('app.media.app_icon')),
new VideoInfo('良友音乐409', $r('app.media.app_icon'), '7788', '五月天的《我不愿让你一个人》', $r('app.media.app_icon')),
new VideoInfo('五月天饭团', $r('app.media.app_icon'), '4.5w', '#五月天 life版《我不愿让你一个人》', $r('app.media.app_icon')),
new VideoInfo('橘子调', $r('app.media.app_icon'), '2.1w', '五月天的歌#后来的我们', $r('app.media.app_icon')),
new VideoInfo('俊杰观察', $r('app.media.app_icon'), '7.1w', '也许未来你会找到懂你疼你更好的人', $r('app.media.app_icon')),
new VideoInfo('诺', $r('app.media.app_icon'), '14.4w', '#我不愿让你一个人 懂你疼你更好的人', $r('app.media.app_icon')),
new VideoInfo('孤思路', $r('app.media.app_icon'), '11.0w', '和@音乐人青峰(合拍)一起', $r('app.media.app_icon'))
]
];
return videoInfoList;
}

View File

@ -0,0 +1,139 @@
/*
* Copyright (c) 2023 Hunan OpenValley 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 media from '@ohos.multimedia.media';
import Logger from '../utils/Logger'
const TAG: string = '[AVPlayerModel]'
export default class AVPlayerModel {
private avPlayer: media.AVPlayer;
private count: number = 1;
private surfaceID: string = ''; // surfaceID用于播放画面显示具体的值需要通过Xcomponent接口获取相关文档链接见上面Xcomponent创建方法
private isSeek: boolean = true; // 用于区分模式是否支持seek操作
private context;
constructor(context) {
this.context = context;
}
// 注册avplayer回调函数
setAVPlayerCallback() {
// seek操作结果回调函数
this.avPlayer.on('seekDone', (seekDoneTime) => {
Logger.info(TAG, `AVPlayer seek succeeded, seek time is ${seekDoneTime}`);
})
// error回调监听函数,当avPlayer在操作过程中出现错误时调用reset接口触发重置流程
this.avPlayer.on('error', (err) => {
Logger.info(TAG, `Invoke avPlayer failed, code is ${err.code}, message is ${err.message}`);
this.avPlayer.reset(); // 调用reset重置资源触发idle状态
})
// 状态机变化回调函数
this.avPlayer.on('stateChange', async (state, reason) => {
switch (state) {
case 'idle': // 成功调用reset接口后触发该状态机上报
Logger.info(TAG, 'AVPlayer state idle called.');
this.avPlayer.release(); // 调用release接口销毁实例对象
break;
case 'initialized': // avplayer 设置播放源后触发该状态上报
Logger.info(TAG, 'AVPlayerstate initialized called.');
if (this.surfaceID) {
this.avPlayer.surfaceId = this.surfaceID; // 设置显示画面,当播放的资源为纯音频时无需设置
}
this.avPlayer.prepare().then(() => {
Logger.info(TAG, 'AVPlayer prepare succeeded.');
}, (err) => {
Logger.info(TAG, `Invoke prepare failed, code is ${err.code}, message is ${err.message}`);
});
break;
case 'prepared': // prepare调用成功后上报该状态机
Logger.info(TAG, 'AVPlayer state prepared called.');
this.avPlayer.play(); // 调用播放接口开始播放
break;
case 'playing': // play成功调用后触发该状态机上报
Logger.info(TAG, 'AVPlayer state playing called.');
if (this.count !== 0) {
if (this.isSeek) {
Logger.info(TAG, 'AVPlayer start to seek.');
} else {
// 当播放模式不支持seek操作时继续播放到结尾
Logger.info(TAG, 'AVPlayer wait to play end.');
}
} else {
this.avPlayer.pause(); // 调用暂停接口暂停播放
}
this.count++;
break;
case 'paused': // pause成功调用后触发该状态机上报
Logger.info(TAG, 'AVPlayer state paused called.');
this.avPlayer.loop = true;
break;
case 'completed': // 播放结束后触发该状态机上报
Logger.info(TAG, 'AVPlayer state completed called.');
this.avPlayer.play(); // 再次播放接口开始播放
break;
case 'stopped': // stop接口成功调用后触发该状态机上报
Logger.info(TAG, 'AVPlayer state stopped called.');
this.avPlayer.reset(); // 调用reset接口初始化avplayer状态
break;
case 'released':
Logger.info(TAG, 'AVPlayer state released called.');
break;
default:
Logger.info(TAG, 'AVPlayer state unknown called.');
break;
}
})
}
public play(){
if (this.avPlayer) {
this.avPlayer.play();
}
}
public paused(){
if (this.avPlayer) {
this.avPlayer.pause();
}
}
// 以下demo为使用资源管理接口获取打包在HAP内的媒体资源文件并通过fdSrc属性进行播放示例
async avPlayerFdSrcDemo(avName: string, surfaceID?: string) {
if (surfaceID) {
this.surfaceID = surfaceID;
}
// 创建avPlayer实例对象
this.avPlayer = await media.createAVPlayer();
// 创建状态机变化回调函数
this.setAVPlayerCallback();
// 通过UIAbilityContext的resourceManager成员的getRawFd接口获取媒体资源播放地址
// 返回类型为{fd,offset,length},fd为HAP包fd地址offset为媒体资源偏移量length为播放长度
let context = this.context;
let fileDescriptor = await context.resourceManager.getRawFd(avName);
this.isSeek = false; // 支持seek操作
// 为fdSrc赋值触发initialized状态机上报
this.avPlayer.fdSrc = fileDescriptor;
}
// 以下demo为通过url设置网络地址来实现播放直播码流的demo
async avPlayerLiveDemo() {
// 创建avPlayer实例对象
this.avPlayer = await media.createAVPlayer();
// 创建状态机变化回调函数
this.setAVPlayerCallback();
this.isSeek = false; // 不支持seek操作
this.avPlayer.url = 'http://xxx.xxx.xxx.xxx:xx/xx/index.m3u8'; // 播放hls网络直播码流
}
}

View File

@ -0,0 +1,301 @@
/*
* Copyright (c) 2023 Hunan OpenValley 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 camera from '@ohos.multimedia.camera'
import image from '@ohos.multimedia.image'
import mediaLibrary from '@ohos.multimedia.mediaLibrary'
import media from '@ohos.multimedia.media';
import deviceInfo from '@ohos.deviceInfo';
import type common from '@ohos.app.ability.common'
import MediaModel from './MediaModel'
import Logger from '../utils/Logger'
const TAG: string = '[CameraModel]'
const CAMERASIZE = {
WIDTH: 1920,
HEIGHT: 1080
}
/**
*
*/
export default class CameraModel {
private cameraInput: camera.CameraInput;
private previewOutput: camera.PreviewOutput;
private fileAsset: mediaLibrary.FileAsset;
private photoUri: string = '';
private mediaModel: MediaModel;
private fd: number = -1;
private receiver: image.ImageReceiver;
private context: any;
private cameraManager: camera.CameraManager;
private cameras: Array<camera.CameraDevice>;
private photoOutPut: camera.PhotoOutput;
private captureSession: camera.CaptureSession;
private cameraOutputCapability: camera.CameraOutputCapability;
private videoOutput: camera.VideoOutput;
private avRecorder: media.AVRecorder;
private avRecorderProfile: media.VideoRecorderProfile = {
audioBitrate: 48000,
audioChannels: 2,
audioCodec: media.CodecMimeType.AUDIO_AAC,
audioSampleRate: 48000,
fileFormat: media.ContainerFormatType.CFT_MPEG_4,
videoBitrate: 2000000,
videoCodec: media.CodecMimeType.VIDEO_MPEG4,
videoFrameWidth: 640,
videoFrameHeight: 480,
videoFrameRate: 30
}
private videoSourceType = 0;
constructor(context: common.Context) {
this.context = context
this.mediaModel = MediaModel.getMediaInstance(context)
// 服务端代码创建ImageReceiver
this.receiver = image.createImageReceiver(CAMERASIZE.WIDTH, CAMERASIZE.HEIGHT, 4, 8) // 4表示生成的图像格式8表示用户希望同时访问的最大图像数
Logger.info(TAG, `createImageReceiver`)
// 获取Surface ID
this.receiver.getReceivingSurfaceId((surfaceId) => {
Logger.info(TAG, `getReceivingSurfaceId surfaceId is ${surfaceId}`)
})
// 注册Surface的监听在surface的buffer准备好后触发
this.receiver.on('imageArrival', () => {
Logger.info(TAG, `imageArrival`)
// 去获取Surface中最新的buffer
this.receiver.readNextImage((err, image) => {
Logger.info(TAG, `readNextImage`)
if (err || image === undefined) {
Logger.error(TAG, `failed to get valid image`)
return
}
image.getComponent(4, (errMsg, img) => {
// 4表示图像类型为JPEG
// 消费component.byteBuffer例如将buffer内容保存成图片。
Logger.info(TAG, `getComponent`)
if (errMsg || img === undefined) {
Logger.info(TAG, `failed to get valid buffer`)
return
}
let buffer = new ArrayBuffer(4096)
if (img.byteBuffer) {
buffer = img.byteBuffer
} else {
Logger.error(TAG, `img.byteBuffer is undefined`)
}
})
})
})
}
/**
*
*/
async createCamera(surfaceId: string): Promise<void> {
Logger.info(TAG, `initCamera surfaceId:${surfaceId}`);
// await this.releaseCamera();
Logger.info(TAG, `deviceInfo.deviceType = ${deviceInfo.deviceType}`);
if (deviceInfo.deviceType === 'default') {
Logger.info(TAG, `deviceInfo.deviceType default 1 = ${deviceInfo.deviceType}`);
this.videoSourceType = 1;
Logger.info(TAG, `deviceInfo.deviceType default 2 = ${deviceInfo.deviceType}`);
} else {
Logger.info(TAG, `deviceInfo.deviceType other 1 = ${deviceInfo.deviceType}`);
this.videoSourceType = 0;
Logger.info(TAG, `deviceInfo.deviceType other 2 = ${deviceInfo.deviceType}`);
}
Logger.info(TAG, `getCameraManager begin`);
try {
Logger.info(TAG, `getCameraManager try begin`);
this.cameraManager = camera.getCameraManager(this.context);
Logger.info(TAG, `getCameraManager try end`);
} catch (e) {
Logger.info(TAG, `getCameraManager catch e:${JSON.stringify(e)}`);
}
Logger.info(TAG, `getCameraManager end`);
Logger.info(TAG, `getCameraManager ${JSON.stringify(this.cameraManager)}`);
this.cameras = this.cameraManager.getSupportedCameras();
Logger.info(TAG, `createCamera get cameras ${this.cameras.length}`);
if (this.cameras.length === 0) {
Logger.info(TAG, 'cannot get cameras');
return;
}
Logger.info(TAG, `createCamera cameras=${this.cameras}`);
let mCamera = this.cameras[0];
Logger.info(TAG, `createCamera mCamera=${mCamera}`);
this.cameraInput = this.cameraManager.createCameraInput(mCamera);
Logger.info(TAG, `createCamera cameraInput=${this.cameraInput}`);
this.cameraInput.open();
Logger.info(TAG, 'createCameraInput');
this.cameraOutputCapability = this.cameraManager.getSupportedOutputCapability(mCamera);
let previewProfile = this.cameraOutputCapability.previewProfiles[0];
this.previewOutput = this.cameraManager.createPreviewOutput(
previewProfile,
surfaceId
);
Logger.info(TAG, 'createPreviewOutput');
let rSurfaceId = await this.receiver.getReceivingSurfaceId();
let photoProfile = this.cameraOutputCapability.photoProfiles[0];
this.photoOutPut = this.cameraManager.createPhotoOutput(
photoProfile,
rSurfaceId
);
this.captureSession = this.cameraManager.createCaptureSession();
Logger.info(TAG, 'createCaptureSession');
this.captureSession.beginConfig();
Logger.info(TAG, 'beginConfig');
this.captureSession.addInput(this.cameraInput);
this.captureSession.addOutput(this.previewOutput);
this.captureSession.addOutput(this.photoOutPut);
await this.captureSession.commitConfig();
await this.captureSession.start();
Logger.info(TAG, 'captureSession start');
}
/**
*
*/
async startVideo(): Promise<void> {
Logger.info(TAG, 'startVideo begin');
Logger.info(TAG, 'startVideo 1');
await this.captureSession.stop();
Logger.info(TAG, 'startVideo 2');
this.captureSession.beginConfig();
Logger.info(TAG, 'startVideo 3');
if (this.videoOutput) {
try {
Logger.info(TAG, 'startVideo 4');
this.captureSession.removeOutput(this.videoOutput);
} catch (e) {
Logger.info(TAG, `startVideo catch e:${e}`);
}
}
if (this.videoOutput) {
try {
Logger.info(TAG, 'startVideo 5');
this.captureSession.removeOutput(this.videoOutput);
Logger.info(TAG, 'startVideo 6');
} catch (e) {
Logger.info(TAG, `startVideo catch e:${JSON.stringify(e)}`);
}
try {
Logger.info(TAG, 'startVideo release');
await this.videoOutput.release();
} catch (e) {
Logger.info(TAG, `startVideo catch e:${JSON.stringify(e)}`);
}
}
Logger.info(TAG, 'startVideo 7');
this.fileAsset = await this.mediaModel.createAndGetUri(mediaLibrary.MediaType.VIDEO);
Logger.info(TAG, `startVideo fileAsset:${this.fileAsset}`);
this.fd = await this.mediaModel.getFdPath(this.fileAsset);
Logger.info(TAG, `startVideo fd:${this.fd}`);
this.avRecorder = await media.createAVRecorder();
Logger.info(TAG, `startVideo into createAVRecorder:${this.avRecorder}`);
if (this.avRecorder != null) {
Logger.info(TAG, `startVideo createAVRecorder success:${this.avRecorder}`);
let videoConfig: media.VideoRecorderConfig = {
audioSourceType: 1,
videoSourceType: this.videoSourceType,
profile: this.avRecorderProfile,
url: `fd://${this.fd}`,
rotation: 0
}
Logger.info(TAG, `startVideo videoConfig:${JSON.stringify(videoConfig)}`);
try {
await this.avRecorder.prepare(videoConfig);
} catch (err) {
Logger.info(TAG, `startVideo err:${err}`);
}
Logger.info(TAG, `startVideo prepare`);
let videoId = await this.avRecorder.getInputSurface();
let videoProfile = this.cameraOutputCapability.videoProfiles[0];
Logger.info(TAG, `startVideo capability.videoProfiles[]=: ${JSON.stringify(this.cameraOutputCapability.videoProfiles)}`);
Logger.info(TAG, `startVideo videoProfile:${JSON.stringify(videoProfile)}`);
this.videoOutput = this.cameraManager.createVideoOutput(videoProfile, videoId);
Logger.info(TAG, `startVideo videoOutput:${this.videoOutput}`);
this.captureSession.addOutput(this.videoOutput);
Logger.info(TAG, `startVideo addOutput`);
await this.captureSession.commitConfig();
Logger.info(TAG, `startVideo commitConfig`);
await this.captureSession.start();
Logger.info(TAG, `startVideo commitConfig captureSession`);
await this.videoOutput.start();
Logger.info(TAG, `startVideo commitConfig videoOutput`);
await this.avRecorder.start();
Logger.info(TAG, 'startVideo end');
} else {
Logger.info(TAG, `startVideo createAVRecorder fail, error null`);
}
}
/**
*
*/
async stopVideo(): Promise<string> {
Logger.info(TAG, 'stopVideo called');
await this.avRecorder.stop();
await this.avRecorder.release();
await this.videoOutput.stop();
// 停止结束时复制录制的视频至沙箱cache目录中
let fileName = await this.copyVideo();
await this.fileAsset.close(this.fd);
return fileName;
}
/**
* video
*/
async copyVideo(): Promise<string> {
let url = this.fileAsset.uri;
Logger.info(TAG, `stopVideo uri:${url}`);
let fileName = await this.mediaModel.copyVideo(this.fd);
Logger.info(TAG, `stopVideo fileName:${fileName}`);
return fileName;
}
/**
*
*/
async releaseCamera(): Promise<void> {
Logger.info(TAG, `releaseCamera start`);
if (this.cameraInput) {
await this.cameraInput.close();
}
if (this.previewOutput) {
await this.previewOutput.release();
}
if (this.photoOutPut) {
await this.photoOutPut.release();
}
if (this.videoOutput) {
await this.videoOutput.release();
}
if (this.captureSession) {
await this.captureSession.release();
}
Logger.info(TAG, `releaseCamera end`);
}
}

View File

@ -0,0 +1,89 @@
/*
* Copyright (c) 2023 Hunan OpenValley 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 type common from '@ohos.app.ability.common'
import mediaLibrary from '@ohos.multimedia.mediaLibrary';
import fs from '@ohos.file.fs'
import DateTimeUtil from '../utils/DateTimeUtil';
import Logger from '../utils/Logger';
const TAG = '[MediaModel]';
export default class MediaModel {
private mediaLibraryTest: mediaLibrary.MediaLibrary = undefined;
private static mediaInstance: MediaModel = undefined;
constructor() {
this.mediaLibraryTest = mediaLibrary.getMediaLibrary(globalThis.abilityContext);
}
public static getMediaInstance(context: common.Context): MediaModel {
if (this.mediaInstance === undefined) {
this.mediaInstance = new MediaModel();
}
return this.mediaInstance;
}
async createAndGetUri(mediaType: mediaLibrary.MediaType): Promise<mediaLibrary.FileAsset> {
let result = {
prefix: 'VID_', suffix: '.mp4', directory: mediaLibrary.DirectoryType.DIR_VIDEO
}
let info = result;
Logger.info(TAG, `createAndGetUri info = ${info}`);
let dateTimeUtil = new DateTimeUtil();
let name = `${dateTimeUtil.getDate()}_${dateTimeUtil.getTime()}`;
let displayName = `${info.prefix}${name}${info.suffix}`;
Logger.info(TAG, `createAndGetUri displayName = ${displayName},mediaType = ${mediaType}`);
let publicPath = await this.mediaLibraryTest.getPublicDirectory(info.directory);
Logger.info(TAG, `createAndGetUri publicPath = ${publicPath}/${displayName}`);
let fileAsset = null;
try {
fileAsset = await this.mediaLibraryTest.createAsset(mediaType, displayName, publicPath);
} catch (err) {
Logger.info(TAG, `createAndGetUri err = ${err}`);
}
Logger.info(TAG, `createAndGetUri fileAsset = ${fileAsset}`);
return fileAsset;
}
async getFdPath(fileAsset: mediaLibrary.FileAsset): Promise<number> {
let fd = await fileAsset.open('Rw');
Logger.info(TAG, `fd = ${fd}`);
return fd;
}
/**
*
* @param fd
* @returns
*/
async copyVideo(fd: number): Promise<string> {
// 将录制视频存入沙箱路径
let mContext: common.Context = globalThis.abilityContext;
Logger.info(TAG, `this.fd = ${JSON.stringify(fd)}`);
// upload只可访问的沙箱路径/data/app/el2/100/base/com.samples.appsampled/haps/entry/cache/
Logger.info(TAG, `mContext.cacheDir = ${JSON.stringify(mContext.cacheDir)}`);
let fileName = new Date().getTime().toString();
let imagePath = `${mContext.cacheDir}/${fileName}.mp4`;
Logger.info(TAG, `this.imagePath = ${JSON.stringify(imagePath)}`);
try {
fs.copyFileSync(fd, imagePath);
return `${fileName}.mp4`;
} catch (err) {
Logger.info(TAG, `this.err = ${err}`);
}
return null;
}
}

View File

@ -0,0 +1,128 @@
/*
* Copyright (c) 2023 Hunan OpenValley 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 http from '@ohos.net.http';
import request from '@ohos.request';
import webSocket from '@ohos.net.webSocket';
import Logger from '../utils/Logger';
import Constant from '../utils/Constant';
const TAG: string = '[NetworkModel]';
export default class NetworkModel {
private httpRequest: http.HttpRequest = http.createHttp();
private mWebSocket: webSocket.WebSocket = webSocket.createWebSocket();
public async request(action: string, method: http.RequestMethod, extraData: Object, token?: string): Promise<http.HttpResponse> {
Logger.info(TAG, `request action->${JSON.stringify(action)}, method->${JSON.stringify(method)}, extraData->${JSON.stringify(extraData)},token->${JSON.stringify(token)}`)
let header = {
'Content-Type': 'application/json',
'X-Access-Token': token
}
let response = await this.httpRequest.request(
Constant.URL + action,
{
method: method,
header: header,
extraData: extraData,
expectDataType: http.HttpDataType.STRING,
usingCache: true,
priority: 1,
connectTimeout: 60000,
readTimeout: 60000,
usingProtocol: http.HttpProtocol.HTTP1_1,
usingProxy: false,
});
Logger.info(TAG, `request response->${JSON.stringify(response)}`)
return response;
}
public uploadFile(action: string, fileName: string, callback): void {
Logger.info(TAG, `upload file create action = ${action}, fileName = ${fileName}`)
Logger.info(TAG, `upload url = ${Constant.URL + action}`)
Logger.info(TAG, `upload token = ${globalThis.userInfo.token}`)
let uploadTask: request.UploadTask;
let uploadConfig = {
url: Constant.URL + action,
header: {
'X-Access-Token': globalThis.userInfo.token, 'Content-Type': 'multipart/form-data'
},
method: "POST",
files: [{
filename: fileName, name: "file", uri: `internal://cache/${fileName}`, type: "mp4"
}],
data: [{
name: 'biz', value: Constant.UPLOAD_URL
}],
};
Logger.info(TAG, 'upload uploadConfig,' + JSON.stringify(uploadConfig))
try {
Logger.info(TAG, 'upload start')
request.uploadFile(globalThis.abilityContext, uploadConfig).then((data) => {
uploadTask = data;
Logger.info(TAG, 'upload end 1')
uploadTask.on('complete', (taskState: Array<request.TaskState>) => {
Logger.info(TAG, 'upload complete ' + JSON.stringify(taskState))
callback(true)
});
Logger.info(TAG, 'upload end 2')
}).catch((err) => {
Logger.error(TAG, `Failed to request the upload. ${err}`);
});
} catch (err) {
Logger.error(TAG, `Failed to request the upload. Code: ${err.code}, message: ${err.message}`);
}
}
public async onMessage(id: string, token: string, callback): Promise<void> {
Logger.info(TAG, `onMessage on connect begin: URL= ${Constant.ACTION_ON_MESSAGE_URL + id}`);
// 连接websocket
this.mWebSocket.connect(Constant.ACTION_ON_MESSAGE_URL + id, (err, value) => {
if (!err) {
Logger.info(TAG, 'onMessage Connected successfully');
// 连接成功订阅消息
this.mWebSocket.on('message', (err, value) => {
Logger.info(TAG, `onMessage on message, message:${value}`);
if (!err) {
Logger.info(TAG, 'onMessage receive successfully');
callback(value);
} else {
Logger.info(TAG, `onMessage receive failed. Err: ${JSON.stringify(err)}`);
}
});
// 连接成功订阅错误信息出现错误则关闭webSocket
this.mWebSocket.on('error', (err) => {
Logger.info(TAG, `onMessage on error, error: ${JSON.stringify(err)}`);
this.mWebSocket.close((err, value) => {
if (!err) {
Logger.info(TAG, 'onMessage Connection closed successfully');
} else {
Logger.info(TAG, `onMessage Failed to close the connection. Err: ${JSON.stringify(err)}`);
}
});
});
} else {
Logger.info(TAG, `onMessage Connection failed. Err: ${JSON.stringify(err)}`);
}
});
Logger.info(TAG, `onMessage on connect end`);
}
}

View File

@ -0,0 +1,144 @@
/*
* Copyright (c) 2023 Hunan OpenValley 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 router from '@ohos.router';
import Logger from '../utils/Logger'
import MessagePage from '../component/MessageComponent'
import VideoComponent from '../component/VideoComponent'
import emitter from '@ohos.events.emitter';
import Constant from '../utils/Constant';
const TAG: string = '[Index]'
@Entry
@Component
struct Index {
@State selectDownIndex: number = 0; // 底部选择索引
/**
* 登录验证
*/
loginVerification(): boolean {
// 验证是否登录
if (globalThis.userInfo == null || globalThis.userInfo == undefined) {
return false;
}
return true;
}
pageTransition() {
// 禁止首页页面转场效果
PageTransitionEnter({ type: RouteType.None, duration: 0 })
PageTransitionExit({ type: RouteType.None, duration: 0 })
}
onPageShow() {
router.clear();
}
build() {
Column() {
Column() {
if (this.selectDownIndex === 0) {
VideoComponent()
} else if (this.selectDownIndex === 1) {
} else if (this.selectDownIndex === 2 && this.loginVerification()) {
MessagePage()
} else if (this.selectDownIndex === 3) {
}
}
.width('100%')
.height('92%')
// 底部操作栏
Row() {
Text($r('app.string.Home_page'))
.height('100%')
.fontColor(this.selectDownIndex === 0 ? $r('app.color.COLOR_FFFFFF') : $r('app.color.COLOR_CCF1F3F5'))
.fontSize(22)
.fontFamily($r('app.string.Font_family_medium'))
.margin({ left: 10 })
.onClick(e => {
this.selectDownIndex = 0;
Logger.info(TAG, `onClick this is ${this.selectDownIndex}`)
})
Text($r('app.string.Friend'))
.height('100%')
.fontColor(this.selectDownIndex === 1 ? $r('app.color.COLOR_FFFFFF') : $r('app.color.COLOR_CCF1F3F5'))
.fontSize(22)
.fontFamily($r('app.string.Font_family_medium'))
.margin({ left: 10 })
.onClick(e => {
this.selectDownIndex = 1;
Logger.info(TAG, `onClick this is ${this.selectDownIndex}`)
})
Image($r('app.media.app_icon'))
.id('index_main')
.width(80)
.height(40)
.objectFit(ImageFit.Contain)
.onClick(e => {
Logger.info(TAG, `onClick this is ${this.selectDownIndex}`)
// 跳转页面前暂停本地视频
emitter.emit({ eventId: Constant.EVENT_PAUSED_INDEX });
// 验证是否登录
if (!this.loginVerification()) {
router.pushUrl({ url: 'appsampled/pages/Login' })
return;
}
router.pushUrl({ url: 'appsampled/pages/CameraPage' })
})
Text($r('app.string.Message'))
.id('index_message')
.height('100%')
.fontColor(this.selectDownIndex === 2 ? $r('app.color.COLOR_FFFFFF') : $r('app.color.COLOR_CCF1F3F5'))
.fontSize(22)
.fontFamily($r('app.string.Font_family_medium'))
.margin({ right: 10 })
.onClick(e => {
this.selectDownIndex = 2;
Logger.info(TAG, `onClick this is ${this.selectDownIndex}`)
// 跳转页面前暂停本地视频
emitter.emit({ eventId: Constant.EVENT_PAUSED_INDEX });
// 验证是否登录
if (!this.loginVerification()) {
router.pushUrl({ url: 'appsampled/pages/Login' })
}
})
Text($r('app.string.Me'))
.height('100%')
.fontColor(this.selectDownIndex === 3 ? $r('app.color.COLOR_FFFFFF') : $r('app.color.COLOR_CCF1F3F5'))
.fontSize(22)
.fontFamily($r('app.string.Font_family_medium'))
.margin({ left: 10 })
.onClick(e => {
this.selectDownIndex = 3;
Logger.info(TAG, `onClick this is ${this.selectDownIndex}`)
})
}
.width('100%')
.height('8%')
.justifyContent(FlexAlign.SpaceAround)
}
.width('100%')
.height('100%')
.backgroundColor($r('app.color.COLOR_000000'))
}
}

View File

@ -0,0 +1,34 @@
/*
* Copyright (c) 2023 Hunan OpenValley 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.
*/
export default class Constant {
// URL
public static readonly URL: string = 'http://192.168.18.165:8080/jeecg-boot';
public static readonly UPLOAD_URL: string = 'appsampled';
public static readonly ACTION_LOGIN: string = '/sys/login';
public static readonly ACTION_UPLOAD: string = '/sys/common/upload';
public static readonly ACTION_ADD_FILE: string = '/harmony/video/add';
public static readonly ACTION_SEND_MESSAGE: string = '/sys/message/sysMessageTemplate/sendMsg';
public static readonly ACTION_ON_MESSAGE_URL: string = 'ws://192.168.18.47:8080/jeecg-boot/websocket/';
// EVENT ID
public static readonly EVENT_PAUSED_AUDIO: number = 1;
public static readonly EVENT_PAUSED_VIDEO: number = 2;
public static readonly EVENT_PAUSED_INDEX: number = 3;
public static readonly TEST_NAME_DEMO_VIDEO: string = 'demo_video.mp4';
public static readonly TEST_NAME_DEMO_AUDIO: string = 'demo_audio.mp3';
}

View File

@ -0,0 +1,74 @@
/*
* Copyright (c) 2023 Hunan OpenValley 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.
*/
/**
* @file
*/
const NINE = 9; // 这是数字9
export default class DateTimeUtil {
/**
*
*/
getTime(): string {
const DATETIME = new Date();
return this.concatTime(
DATETIME.getHours(),
DATETIME.getMinutes(),
DATETIME.getSeconds()
);
}
/**
*
*/
getDate(): string {
const DATETIME = new Date();
return this.concatDate(
DATETIME.getFullYear(),
DATETIME.getMonth() + 1,
DATETIME.getDate()
);
}
/**
* 0
* @param value-
*/
fill(value: number): string {
return (value > NINE ? '' : '0') + value;
}
/**
*
* @param year
* @param month
* @param date
*/
concatDate(year: number, month: number, date: number): string {
return `${year}${this.fill(month)}${this.fill(date)}`;
}
/**
*
* @param hours
* @param minutes
* @param seconds
*/
concatTime(hours: number, minutes: number, seconds: number): string {
return `${this.fill(hours)}${this.fill(minutes)}${this.fill(seconds)}`;
}
}

View File

@ -0,0 +1,45 @@
/*
* Copyright (c) 2023 Hunan OpenValley 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 hilog from '@ohos.hilog'
class Logger {
private domain: number
private prefix: string
private format: string = '%{public}s, %{public}s'
constructor(prefix: string) {
this.prefix = prefix
this.domain = 0xFF00
}
debug(...args: string[]) {
hilog.debug(this.domain, this.prefix, this.format, args)
}
info(...args: string[]) {
hilog.info(this.domain, this.prefix, this.format, args)
}
warn(...args: string[]) {
hilog.warn(this.domain, this.prefix, this.format, args)
}
error(...args: string[]) {
hilog.error(this.domain, this.prefix, this.format, args)
}
}
export default new Logger('[Sample_AppSampleD]')

View File

@ -0,0 +1,70 @@
/*
* Copyright (c) 2023 Hunan OpenValley 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.
*/
{
"module": {
"name": "entry",
"type": "entry",
"description": "$string:module_desc",
"mainElement": "EntryAbility",
"deviceTypes": [
"default"
],
"deliveryWithInstall": true,
"installationFree": false,
"pages": "$profile:main_pages",
"abilities": [
{
"name": "EntryAbility",
"srcEntry": "./ets/entryability/EntryAbility.ts",
"description": "$string:EntryAbility_desc",
"icon": "$media:app_icon",
"label": "$string:EntryAbility_label",
"startWindowIcon": "$media:app_icon",
"startWindowBackground": "$color:start_window_background",
"exported": true,
"skills": [
{
"entities": [
"entity.system.home"
],
"actions": [
"action.system.home"
]
}
]
}
],
"requestPermissions": [
{
"name": "ohos.permission.CAMERA"
},
{
"name": "ohos.permission.MICROPHONE"
},
{
"name": "ohos.permission.MEDIA_LOCATION"
},
{
"name": "ohos.permission.WRITE_MEDIA"
},
{
"name": "ohos.permission.READ_MEDIA"
},
{
"name": "ohos.permission.INTERNET"
}
]
}
}

View File

@ -0,0 +1,136 @@
{
"color": [
{
"name": "start_window_background",
"value": "#FFFFFF"
},
{
"name": "COLOR_FFFFFF",
"value": "#FFFFFF"
},
{
"name": "COLOR_80FFFFFF",
"value": "#80FFFFFF"
},
{
"name": "COLOR_CCFFFFFF",
"value": "#CCFFFFFF"
},
{
"name": "COLOR_E6FFFFFF",
"value": "#E6FFFFFF"
},
{
"name": "COLOR_000000",
"value": "#000000"
},
{
"name": "COLOR_33000000",
"value": "#33000000"
},
{
"name": "COLOR_5BA854",
"value": "#5BA854"
},
{
"name": "COLOR_E6000000",
"value": "#e6000000"
},
{
"name": "COLOR_99000000",
"value": "#99000000"
},
{
"name": "COLOR_007DFF",
"value": "#007DFF"
},
{
"name": "COLOR_66000000",
"value": "#66000000"
},
{
"name": "COLOR_0D000000",
"value": "#0d000000"
},
{
"name": "COLOR_FF000000",
"value": "#ff000000"
},
{
"name": "COLOR_CCF1F3F5",
"value": "#CCF1F3F5"
},
{
"name": "COLOR_99F1F3F5",
"value": "#99F1F3F5"
},
{
"name": "COLOR_FF785F",
"value": "#ff758f"
},
{
"name": "COLOR_FC2B55",
"value": "#fc2b55"
},
{
"name": "COLOR_57A9FE",
"value": "#58a9fe"
},
{
"name": "COLOR_FF689F",
"value": "#ff689f"
},
{
"name": "COLOR_393939",
"value": "#393939"
},
{
"name": "COLOR_3DA0F1",
"value": "#3DA0F1"
},
{
"name": "COLOR_1E1E1E",
"value": "#1e1e1e"
},
{
"name": "COLOR_AE4EF7",
"value": "#ae4ef7"
},
{
"name": "COLOR_168CF6",
"value": "#168cf6"
},
{
"name": "COLOR_FE2B54",
"value": "#fe2b54"
},
{
"name": "COLOR_E3163D",
"value": "#E3163D"
},
{
"name": "COLOR_5A5B63",
"value": "#5a5b63"
},
{
"name": "COLOR_D7B837",
"value": "#d7b837"
},
{
"name": "COLOR_99393939",
"value": "#99393939"
},
{
"name": "COLOR_151724",
"value": "#151724"
},
{
"name": "COLOR_EEC934",
"value": "#EEC934"
},
{
"name": "COLOR_669F9B9B",
"value": "#669F9B9B"
}
]
}

View File

@ -0,0 +1,240 @@
{
"string": [
{
"name": "module_desc",
"value": "module description"
},
{
"name": "EntryAbility_desc",
"value": "description"
},
{
"name": "EntryAbility_label",
"value": "appsampled"
},
{
"name": "Recommend",
"value": "recommend"
},
{
"name": "Font_family_medium",
"value": "HarmonyOS Sans SC-Medium"
},
{
"name": "Font_family_regular",
"value": "HarmonyOS Sans SC-Regular"
},
{
"name": "Home_page",
"value": "home page"
},
{
"name": "Message",
"value": "message"
},
{
"name": "LoginByPhone",
"value": "login by phone"
},
{
"name": "Input_phone",
"value": "please input phone"
},
{
"name": "Input_password",
"value": "please input password"
},
{
"name": "Login",
"value": "login"
},
{
"name": "Video",
"value": "video"
},
{
"name": "Next",
"value": "Next"
},
{
"name": "Stroll",
"value": "stroll"
},
{
"name": "Experience",
"value": "experience"
},
{
"name": "Attention",
"value": "attention"
},
{
"name": "Store",
"value": "store"
},
{
"name": "Friend",
"value": "friend"
},
{
"name": "Me",
"value": "me"
},
{
"name": "UserNick",
"value": "@xiaoming"
},
{
"name": "TikContent",
"value": "It's a Lovely Day Today#sunny day#clouds"
},
{
"name": "Num",
"value": "%sW"
},
{
"name": "NewFriend",
"value": "New Friend"
},
{
"name": "No_new_notice",
"value": "No new notice"
},
{
"name": "Interactive_message",
"value": "Interactive message"
},
{
"name": "Interactive_message_content",
"value": "Ming liked your video"
},
{
"name": "Greet",
"value": "greet"
},
{
"name": "Send_Message",
"value": "Send Message"
},
{
"name": "Search",
"value": "search"
},
{
"name": "Clear_all_search_record",
"value": "Clear all search record"
},
{
"name": "Synthesize",
"value": "synthesize"
},
{
"name": "Music",
"value": "music"
},
{
"name": "User",
"value": "user"
},
{
"name": "Commodity",
"value": "commodity"
},
{
"name": "Live_streaming",
"value": "live streaming"
},
{
"name": "All",
"value": "all"
},
{
"name": "Special",
"value": "special"
},
{
"name": "Album",
"value": "album"
},
{
"name": "Word",
"value": "word"
},
{
"name": "Subsection",
"value": "subsection"
},
{
"name": "Photo",
"value": "photo"
},
{
"name": "Everyday",
"value": "everyday"
},
{
"name": "Wen",
"value": "wen"
},
{
"name": "Send_everyday",
"value": "send everyday"
},
{
"name": "Select_music",
"value": "select music"
},
{
"name": "Return_edit",
"value": "Return Edit"
},
{
"name": "Topic",
"value": "topic"
},
{
"name": "Where_are_you",
"value": "where are you"
},
{
"name": "Add_applet",
"value": "Add applet"
},
{
"name": "Publicly_visible",
"value": "Publicly visible"
},
{
"name": "Advanced_setup",
"value": "advanced setup"
},
{
"name": "Well_Number_Friend",
"value": "# Friend"
},
{
"name": "Add_work_description",
"value": "Add work description"
},
{
"name": "Select_cover",
"value": "select cover"
},
{
"name": "Save_Draft",
"value": "Save Draft"
},
{
"name": "Publish",
"value": "publish"
},
{
"name": "Publish_Success",
"value": "Publish Success"
},
{
"name": "Connection_timesout",
"value": "The connection times out. Please check the network status"
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

View File

@ -0,0 +1,10 @@
{
"src": [
"pages/Index",
"appsampled/pages/Login",
"appsampled/pages/ChatPage",
"appsampled/pages/SearchPage",
"appsampled/pages/CameraPage",
"appsampled/pages/PublishPage"
]
}

View File

@ -0,0 +1,240 @@
{
"string": [
{
"name": "module_desc",
"value": "module description"
},
{
"name": "EntryAbility_desc",
"value": "description"
},
{
"name": "EntryAbility_label",
"value": "AppSampleD"
},
{
"name": "Recommend",
"value": "recommend"
},
{
"name": "Font_family_medium",
"value": "HarmonyOS Sans SC-Medium"
},
{
"name": "Font_family_regular",
"value": "HarmonyOS Sans SC-Regular"
},
{
"name": "Home_page",
"value": "home page"
},
{
"name": "Message",
"value": "message"
},
{
"name": "LoginByPhone",
"value": "login by phone"
},
{
"name": "Input_phone",
"value": "please input phone"
},
{
"name": "Input_password",
"value": "please input password"
},
{
"name": "Login",
"value": "login"
},
{
"name": "Video",
"value": "video"
},
{
"name": "Next",
"value": "Next"
},
{
"name": "Stroll",
"value": "stroll"
},
{
"name": "Experience",
"value": "experience"
},
{
"name": "Attention",
"value": "attention"
},
{
"name": "Store",
"value": "store"
},
{
"name": "Friend",
"value": "friend"
},
{
"name": "Me",
"value": "me"
},
{
"name": "UserNick",
"value": "@xiaoming"
},
{
"name": "TikContent",
"value": "It's a Lovely Day Today#sunny day#clouds"
},
{
"name": "Num",
"value": "%sW"
},
{
"name": "NewFriend",
"value": "New Friend"
},
{
"name": "No_new_notice",
"value": "No new notice"
},
{
"name": "Interactive_message",
"value": "Interactive message"
},
{
"name": "Interactive_message_content",
"value": "Ming liked your video"
},
{
"name": "Greet",
"value": "greet"
},
{
"name": "Send_Message",
"value": "Send Message"
},
{
"name": "Search",
"value": "search"
},
{
"name": "Clear_all_search_record",
"value": "Clear all search record"
},
{
"name": "Synthesize",
"value": "synthesize"
},
{
"name": "Music",
"value": "music"
},
{
"name": "User",
"value": "user"
},
{
"name": "Commodity",
"value": "commodity"
},
{
"name": "Live_streaming",
"value": "live streaming"
},
{
"name": "All",
"value": "all"
},
{
"name": "Special",
"value": "special"
},
{
"name": "Album",
"value": "album"
},
{
"name": "Word",
"value": "word"
},
{
"name": "Subsection",
"value": "subsection"
},
{
"name": "Photo",
"value": "photo"
},
{
"name": "Everyday",
"value": "everyday"
},
{
"name": "Wen",
"value": "wen"
},
{
"name": "Send_everyday",
"value": "send everyday"
},
{
"name": "Select_music",
"value": "select music"
},
{
"name": "Return_edit",
"value": "Return Edit"
},
{
"name": "Topic",
"value": "topic"
},
{
"name": "Where_are_you",
"value": "where are you"
},
{
"name": "Add_applet",
"value": "Add applet"
},
{
"name": "Publicly_visible",
"value": "Publicly visible"
},
{
"name": "Advanced_setup",
"value": "advanced setup"
},
{
"name": "Well_Number_Friend",
"value": "# Friend"
},
{
"name": "Add_work_description",
"value": "Add work description"
},
{
"name": "Select_cover",
"value": "select cover"
},
{
"name": "Save_Draft",
"value": "Save as Draft"
},
{
"name": "Publish",
"value": "publish"
},
{
"name": "Publish_Success",
"value": "Publish Success"
},
{
"name": "Connection_timesout",
"value": "The connection times out. Please check the network status"
}
]
}

View File

@ -0,0 +1,240 @@
{
"string": [
{
"name": "module_desc",
"value": "模块描述"
},
{
"name": "EntryAbility_desc",
"value": "description"
},
{
"name": "EntryAbility_label",
"value": "仿应用"
},
{
"name": "Recommend",
"value": "推荐"
},
{
"name": "Font_family_medium",
"value": "HarmonyOS Sans SC-Medium"
},
{
"name": "Font_family_regular",
"value": "HarmonyOS Sans SC-Regular"
},
{
"name": "Home_page",
"value": "首页"
},
{
"name": "Message",
"value": "消息"
},
{
"name": "LoginByPhone",
"value": "手机号密码登录"
},
{
"name": "Input_phone",
"value": "请输入手机号"
},
{
"name": "Input_password",
"value": "请输入密码"
},
{
"name": "Login",
"value": "登录"
},
{
"name": "Video",
"value": "视频"
},
{
"name": "Next",
"value": "下一步"
},
{
"name": "Stroll",
"value": "逛逛"
},
{
"name": "Experience",
"value": "经验"
},
{
"name": "Attention",
"value": "关注"
},
{
"name": "Store",
"value": "商城"
},
{
"name": "Friend",
"value": "朋友"
},
{
"name": "Me",
"value": "我"
},
{
"name": "UserNick",
"value": "@小明"
},
{
"name": "TikContent",
"value": "今天天气真好#晴天#白云"
},
{
"name": "Num",
"value": "%s万"
},
{
"name": "NewFriend",
"value": "新朋友"
},
{
"name": "No_new_notice",
"value": "没有新通知"
},
{
"name": "Interactive_message",
"value": "互动消息"
},
{
"name": "Interactive_message_content",
"value": "xiaoming点赞了你的视频"
},
{
"name": "Greet",
"value": "跟 Ta 打个招呼"
},
{
"name": "Send_Message",
"value": "发送消息"
},
{
"name": "Search",
"value": "搜索"
},
{
"name": "Clear_all_search_record",
"value": "清楚全部搜索记录"
},
{
"name": "Synthesize",
"value": "综合"
},
{
"name": "Music",
"value": "音乐"
},
{
"name": "User",
"value": "用户"
},
{
"name": "Commodity",
"value": "商品"
},
{
"name": "Live_streaming",
"value": "直播"
},
{
"name": "All",
"value": "全部"
},
{
"name": "Special",
"value": "特效"
},
{
"name": "Album",
"value": "相册"
},
{
"name": "Word",
"value": "文字"
},
{
"name": "Subsection",
"value": "分段"
},
{
"name": "Photo",
"value": "照片"
},
{
"name": "Everyday",
"value": "日常"
},
{
"name": "Wen",
"value": "文"
},
{
"name": "Send_everyday",
"value": "发日常"
},
{
"name": "Select_music",
"value": "选择音乐"
},
{
"name": "Return_edit",
"value": "返回编辑"
},
{
"name": "Topic",
"value": "# 话题"
},
{
"name": "Where_are_you",
"value": "你在哪里"
},
{
"name": "Add_applet",
"value": "添加小程序"
},
{
"name": "Publicly_visible",
"value": "公开可见"
},
{
"name": "Advanced_setup",
"value": "高级设置"
},
{
"name": "Well_Number_Friend",
"value": "# 朋友"
},
{
"name": "Add_work_description",
"value": "添加作品描述"
},
{
"name": "Select_cover",
"value": "选封面"
},
{
"name": "Save_Draft",
"value": "存草稿"
},
{
"name": "Publish",
"value": "发布"
},
{
"name": "Publish_Success",
"value": "发布成功"
},
{
"name": "Connection_timesout",
"value": "连接超时,请检查网络状态"
}
]
}

View File

@ -0,0 +1,49 @@
/*
* Copyright (c) 2023 Hunan OpenValley 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 hilog from '@ohos.hilog';
import { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium'
export default function abilityTest() {
describe('ActsAbilityTest', function () {
// Defines a test suite. Two parameters are supported: test suite name and test suite function.
beforeAll(function () {
// Presets an action, which is performed only once before all test cases of the test suite start.
// This API supports only one parameter: preset action function.
})
beforeEach(function () {
// Presets an action, which is performed before each unit test case starts.
// The number of execution times is the same as the number of test cases defined by **it**.
// This API supports only one parameter: preset action function.
})
afterEach(function () {
// Presets a clear action, which is performed after each unit test case ends.
// The number of execution times is the same as the number of test cases defined by **it**.
// This API supports only one parameter: clear action function.
})
afterAll(function () {
// Presets a clear action, which is performed after all test cases of the test suite end.
// This API supports only one parameter: clear action function.
})
it('assertContain',0, function () {
// Defines a test case. This API supports three parameters: test case name, filter parameter, and test case function.
hilog.info(0x0000, 'testTag', '%{public}s', 'it begin');
let a = 'abc'
let b = 'b'
// Defines a variety of assertion methods, which are used to declare expected boolean conditions.
expect(a).assertContain(b)
expect(a).assertEqual(a)
})
})
}

View File

@ -0,0 +1,221 @@
/*
* Copyright (c) 2023 Hunan OpenValley 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 { describe, beforeAll, beforeEach, afterEach, afterAll, it, expect } from '@ohos/hypium';
import hilog from '@ohos.hilog';
import { Driver, ON, MatchPattern } from '@ohos.UiTest';
import abilityDelegatorRegistry from '@ohos.app.ability.abilityDelegatorRegistry';
import { getString } from '../util/ResourceUtil';
const TAG = '[Sample_AppSampleD]';
const DOMAIN = 0xF811;
const BUNDLE = 'AppSampleD';
const delegator = abilityDelegatorRegistry.getAbilityDelegator();
let driver = Driver.create();
export default function IndexTest() {
describe('IndexTest', function () {
// Defines a test suite. Two parameters are supported: test suite name and test suite function.
beforeAll(async function (done) {
// Presets an action, which is performed only once before all test cases of the test suite start.
// This API supports only one parameter: preset action function.
// 启动Ability
delegator.executeShellCommand('aa start -a EntryAbility -b com.samples.appsamppled');
await driver.delayMs(2000);
done()
})
beforeEach(function () {
// Presets an action, which is performed before each unit test case starts.
// The number of execution times is the same as the number of test cases defined by **it**.
// This API supports only one parameter: preset action function.
})
afterEach(function () {
// Presets a clear action, which is performed after each unit test case ends.
// The number of execution times is the same as the number of test cases defined by **it**.
// This API supports only one parameter: clear action function.
})
afterAll(function () {
// Presets a clear action, which is performed after all test cases of the test suite end.
// This API supports only one parameter: clear action function.
})
it('Video', 0, async function (done) {
hilog.info(DOMAIN, TAG, BUNDLE + 'Video begin');
await driver.delayMs(1000);
await checkAndClickById('video_action','Video');
await driver.delayMs(500);
await checkAndClickById('video_action','Video');
await driver.delayMs(1000);
await checkAndClickById('search','Video');
await driver.delayMs(500);
await driver.delayMs(1000);
hilog.info(DOMAIN, TAG, BUNDLE + 'Video end');
done()
})
it('Search', 0, async function (done) {
hilog.info(DOMAIN, TAG, BUNDLE + 'Search begin');
await driver.delayMs(1000);
await checkAndClickById('searchItem_1','Search');
await driver.delayMs(500);
await checkAndClickById('musicID_1','Search');
await driver.delayMs(2000);
await checkAndClickById('musicID_2','Search');
await driver.delayMs(2000);
await checkAndClickById('musicID_2','Search');
await driver.delayMs(2000);
await checkAndClickById('titleID_2','Search');
await driver.delayMs(500);
await checkAndClickById('searchBack','Search');
await driver.delayMs(500);
await checkAndClickById('searchBack','Search');
await driver.delayMs(500);
await driver.delayMs(1000);
hilog.info(DOMAIN, TAG, BUNDLE + 'Search end');
done()
})
it('Message', 0, async function (done) {
hilog.info(DOMAIN, TAG, BUNDLE + 'Message begin');
await driver.delayMs(1000);
await checkAndClickById('index_message','Message');
await driver.delayMs(1000);
await checkAndClickById('login','Message');
await driver.delayMs(5000);
await checkAndClickById('index_message','Message');
await driver.delayMs(500);
await checkAndClickById('userID_1','Message');
await driver.delayMs(500);
await checkAndInputById('chatInput','Hello!','Message');
await driver.delayMs(500);
await checkAndClickById('msgSend','Message');
await driver.delayMs(500);
await checkAndInputById('chatInput','How are you?','Message');
await driver.delayMs(500);
await checkAndClickById('msgSend','Message');
await driver.delayMs(500);
await checkAndClickById('chatBack','Message');
await driver.delayMs(500);
await driver.delayMs(1000);
hilog.info(DOMAIN, TAG, BUNDLE + 'Message end');
done()
})
it('Post_videos', 0, async function (done) {
hilog.info(DOMAIN, TAG, BUNDLE + 'Post_videos begin');
await driver.delayMs(1000);
await checkAndClickById('index_main','Post_videos');
await driver.delayMs(1000);
// 授权
await checkAndClickPermission(getString($r('app.string.allow')), "Post_videos");
await checkAndClickPermission(getString($r('app.string.allow')), "Post_videos");
await checkAndClickPermission(getString($r('app.string.allow')), "Post_videos");
await driver.delayMs(1000);
await checkAndClickById('startVideo','Post_videos');
await driver.delayMs(5000);
await checkAndClickById('stopVideo','Post_videos');
await driver.delayMs(2000);
await checkAndClickById('next','Post_videos');
await driver.delayMs(2000);
await checkAndInputById('textArea','This is my video','Post_videos');
await driver.delayMs(2000);
await checkAndClickById('upload','Post_videos');
await driver.delayMs(500);
await driver.delayMs(1000);
hilog.info(DOMAIN, TAG, BUNDLE + 'Post_videos end');
done()
})
})
/**
* 根据id拿到组件并点击
* @param id
*/
async function checkAndClickById(id: string, log: string) {
hilog.info(DOMAIN, TAG, BUNDLE + `${log} id:${id}`);
await driver.assertComponentExist(ON.id(id));
let res = await driver.findComponent(ON.id(id));
await res.click();
}
/**
* 根据text拿到组件并点击
* @param text
*/
async function checkAndClickByText(text: string, log: string) {
hilog.info(DOMAIN, TAG, BUNDLE + `${log} text:${text}`);
await driver.assertComponentExist(ON.text(text));
let res = await driver.findComponent(ON.text(text));
await res.click();
}
/**
* 根据id拿到组件并输入消息
* @param id
* @param msg
*/
async function checkAndInputById(id:string,msg:string,log:string){
hilog.info(DOMAIN, TAG, BUNDLE + `${log} id:${id}`);
await driver.assertComponentExist(ON.id(id));
let res = await driver.findComponent(ON.id(id));
await res.inputText(msg);
}
/**
* 根据Text验证对应权限
* @param text
* @param log
*/
async function checkAndClickPermission(text: string, log: string) {
hilog.info(DOMAIN, TAG, BUNDLE + `${log} text:${text}`);
await driver.assertComponentExist(ON.text(getString($r('app.string.whether')) + text, MatchPattern.CONTAINS));
let res = await driver.findComponent(ON.text(text, MatchPattern.EQUALS));
await res.click();
}
}

View File

@ -0,0 +1,21 @@
/*
* Copyright (c) 2023 Hunan OpenValley 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 IndexTest from './Index.test'
import abilityTest from './Ability.test'
export default function testsuite() {
abilityTest()
IndexTest()
}

View File

@ -0,0 +1,62 @@
/*
* Copyright (c) 2023 Hunan OpenValley 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 UIAbility from '@ohos.app.ability.UIAbility';
import AbilityDelegatorRegistry from '@ohos.app.ability.abilityDelegatorRegistry';
import hilog from '@ohos.hilog';
import { Hypium } from '@ohos/hypium';
import testsuite from '../test/List.test';
import window from '@ohos.window';
export default class TestAbility extends UIAbility {
onCreate(want, launchParam) {
hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onCreate');
hilog.info(0x0000, 'testTag', '%{public}s', 'want param:' + JSON.stringify(want) ?? '');
hilog.info(0x0000, 'testTag', '%{public}s', 'launchParam:'+ JSON.stringify(launchParam) ?? '');
var abilityDelegator: any
abilityDelegator = AbilityDelegatorRegistry.getAbilityDelegator()
var abilityDelegatorArguments: any
abilityDelegatorArguments = AbilityDelegatorRegistry.getArguments()
hilog.info(0x0000, 'testTag', '%{public}s', 'start run testcase!!!');
Hypium.hypiumTest(abilityDelegator, abilityDelegatorArguments, testsuite)
}
onDestroy() {
hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onDestroy');
}
onWindowStageCreate(windowStage: window.WindowStage) {
hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onWindowStageCreate');
windowStage.loadContent('testability/pages/Index', (err, data) => {
if (err.code) {
hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');
return;
}
hilog.info(0x0000, 'testTag', 'Succeeded in loading the content. Data: %{public}s',
JSON.stringify(data) ?? '');
});
}
onWindowStageDestroy() {
hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onWindowStageDestroy');
}
onForeground() {
hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onForeground');
}
onBackground() {
hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility onBackground');
}
}

View File

@ -0,0 +1,48 @@
/*
* Copyright (c) 2023 Hunan OpenValley 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 hilog from '@ohos.hilog';
@Entry
@Component
struct Index {
aboutToAppear() {
hilog.info(0x0000, 'testTag', '%{public}s', 'TestAbility index aboutToAppear');
}
@State message: string = 'Hello World'
build() {
Row() {
Column() {
Text(this.message)
.fontSize(50)
.fontWeight(FontWeight.Bold)
Button() {
Text('next page')
.fontSize(20)
.fontWeight(FontWeight.Bold)
}.type(ButtonType.Capsule)
.margin({
top: 20
})
.backgroundColor('#0D9FFB')
.width('35%')
.height('5%')
.onClick(()=>{
})
}
.width('100%')
}
.height('100%')
}
}

View File

@ -0,0 +1,63 @@
/*
* Copyright (c) 2023 Hunan OpenValley 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 hilog from '@ohos.hilog';
import TestRunner from '@ohos.application.testRunner';
import AbilityDelegatorRegistry from '@ohos.app.ability.abilityDelegatorRegistry';
var abilityDelegator = undefined
var abilityDelegatorArguments = undefined
async function onAbilityCreateCallback() {
hilog.info(0x0000, 'testTag', '%{public}s', 'onAbilityCreateCallback');
}
async function addAbilityMonitorCallback(err: any) {
hilog.info(0x0000, 'testTag', 'addAbilityMonitorCallback : %{public}s', JSON.stringify(err) ?? '');
}
export default class OpenHarmonyTestRunner implements TestRunner {
constructor() {
}
onPrepare() {
hilog.info(0x0000, 'testTag', '%{public}s', 'OpenHarmonyTestRunner OnPrepare ');
}
async onRun() {
hilog.info(0x0000, 'testTag', '%{public}s', 'OpenHarmonyTestRunner onRun run');
abilityDelegatorArguments = AbilityDelegatorRegistry.getArguments()
abilityDelegator = AbilityDelegatorRegistry.getAbilityDelegator()
var testAbilityName = abilityDelegatorArguments.bundleName + '.TestAbility'
let lMonitor = {
abilityName: testAbilityName,
onAbilityCreate: onAbilityCreateCallback,
};
abilityDelegator.addAbilityMonitor(lMonitor, addAbilityMonitorCallback)
var cmd = 'aa start -d 0 -a TestAbility' + ' -b ' + abilityDelegatorArguments.bundleName
var debug = abilityDelegatorArguments.parameters['-D']
if (debug == 'true')
{
cmd += ' -D'
}
hilog.info(0x0000, 'testTag', 'cmd : %{public}s', cmd);
abilityDelegator.executeShellCommand(cmd,
(err: any, d: any) => {
hilog.info(0x0000, 'testTag', 'executeShellCommand : err : %{public}s', JSON.stringify(err) ?? '');
hilog.info(0x0000, 'testTag', 'executeShellCommand : data : %{public}s', d.stdResult ?? '');
hilog.info(0x0000, 'testTag', 'executeShellCommand : data : %{public}s', d.exitCode ?? '');
})
hilog.info(0x0000, 'testTag', '%{public}s', 'OpenHarmonyTestRunner onRun end');
}
}

View File

@ -0,0 +1,29 @@
/*
* Copyright (c) 2023 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import AbilityDelegatorRegistry from '@ohos.app.ability.abilityDelegatorRegistry';
const delegator = AbilityDelegatorRegistry.getAbilityDelegator();
export function getString(resource: Resource): string {
let manage = delegator.getAppContext().resourceManager
return manage.getStringSync(resource)
}
export async function getStringArray(resource: Resource): Promise<Array<string>> {
let manage = delegator.getAppContext().resourceManager
let menuList: Array<string> = await manage.getStringArrayValue(resource);
return menuList;
}

View File

@ -0,0 +1,50 @@
/*
* Copyright (c) 2023 Hunan OpenValley 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.
*/
{
"module": {
"name": "entry_test",
"type": "feature",
"description": "$string:module_test_desc",
"mainElement": "TestAbility",
"deviceTypes": [
"default"
],
"deliveryWithInstall": true,
"installationFree": false,
"pages": "$profile:test_pages",
"abilities": [
{
"name": "TestAbility",
"srcEntry": "./ets/testability/TestAbility.ets",
"description": "$string:TestAbility_desc",
"icon": "$media:app_icon",
"label": "$string:TestAbility_label",
"exported": true,
"startWindowIcon": "$media:app_icon",
"startWindowBackground": "$color:start_window_background",
"skills": [
{
"actions": [
"action.system.home"
],
"entities": [
"entity.system.home"
]
}
]
}
]
}
}

View File

@ -0,0 +1,8 @@
{
"color": [
{
"name": "start_window_background",
"value": "#FFFFFF"
}
]
}

View File

@ -0,0 +1,24 @@
{
"string": [
{
"name": "module_test_desc",
"value": "test ability description"
},
{
"name": "TestAbility_desc",
"value": "the test ability"
},
{
"name": "TestAbility_label",
"value": "test label"
},
{
"name": "allow",
"value": "允许"
},
{
"name": "whether",
"value": "是否"
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

View File

@ -0,0 +1,5 @@
{
"src": [
"testability/pages/Index"
]
}

View File

@ -0,0 +1,20 @@
/*
* Copyright (c) 2023 Hunan OpenValley 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.
*/
{
"hvigorVersion": "2.0.0",
"dependencies": {
"@ohos/hvigor-ohos-plugin": "2.0.0"
}
}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,2 @@
// Script for compiling build behavior. It is built in the build plug-in and cannot be modified currently.
export { appTasks } from '@ohos/hvigor-ohos-plugin';

61
sample/AppSampleD/hvigorw Normal file
View File

@ -0,0 +1,61 @@
# Copyright (c) 2023 Hunan OpenValley 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.
#!/bin/bash
# ----------------------------------------------------------------------------
# Hvigor startup script, version 1.0.0
#
# Required ENV vars:
# ------------------
# NODE_HOME - location of a Node home dir
# or
# Add /usr/local/nodejs/bin to the PATH environment variable
# ----------------------------------------------------------------------------
HVIGOR_APP_HOME=$(dirname $(readlink -f $0))
HVIGOR_WRAPPER_SCRIPT=${HVIGOR_APP_HOME}/hvigor/hvigor-wrapper.js
warn() {
echo ""
echo -e "\033[1;33m`date '+[%Y-%m-%d %H:%M:%S]'`$@\033[0m"
}
error() {
echo ""
echo -e "\033[1;31m`date '+[%Y-%m-%d %H:%M:%S]'`$@\033[0m"
}
fail() {
error "$@"
exit 1
}
# Determine node to start hvigor wrapper script
if [ -n "${NODE_HOME}" ];then
EXECUTABLE_NODE="${NODE_HOME}/bin/node"
if [ ! -x "$EXECUTABLE_NODE" ];then
fail "ERROR: NODE_HOME is set to an invalid directory,check $NODE_HOME\n\nPlease set NODE_HOME in your environment to the location where your nodejs installed"
fi
else
EXECUTABLE_NODE="node"
which ${EXECUTABLE_NODE} > /dev/null 2>&1 || fail "ERROR: NODE_HOME is not set and not 'node' command found in your path"
fi
# Check hvigor wrapper script
if [ ! -r "$HVIGOR_WRAPPER_SCRIPT" ];then
fail "ERROR: Couldn't find hvigor/hvigor-wrapper.js in ${HVIGOR_APP_HOME}"
fi
# start hvigor-wrapper script
exec "${EXECUTABLE_NODE}" \
"${HVIGOR_WRAPPER_SCRIPT}" "$@"

View File

@ -0,0 +1,70 @@
:: Copyright (c) 2023 Hunan OpenValley 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.
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Hvigor startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
set WRAPPER_MODULE_PATH=%APP_HOME%\hvigor\hvigor-wrapper.js
set NODE_EXE=node.exe
goto start
:start
@rem Find node.exe
if defined NODE_HOME goto findNodeFromNodeHome
%NODE_EXE% --version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto execute
echo.
echo ERROR: NODE_HOME is not set and no 'node' command could be found in your PATH.
echo.
echo Please set the NODE_HOME variable in your environment to match the
echo location of your NodeJs installation.
goto fail
:findNodeFromNodeHome
set NODE_HOME=%NODE_HOME:"=%
set NODE_EXE_PATH=%NODE_HOME%/%NODE_EXE%
if exist "%NODE_EXE_PATH%" goto execute
echo.
echo ERROR: NODE_HOME is not set and no 'node' command could be found in your PATH.
echo.
echo Please set the NODE_HOME variable in your environment to match the
echo location of your NodeJs installation.
goto fail
:execute
@rem Execute hvigor
"%NODE_EXE%" %WRAPPER_MODULE_PATH% %*
:fail
exit /b 1

View File

@ -0,0 +1,26 @@
/*
* Copyright (c) 2023 Hunan OpenValley 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.
*/
{
"license": "",
"devDependencies": {
"@ohos/hypium": "1.0.6"
},
"author": "",
"name": "appsampled",
"description": "Please describe the basic information.",
"main": "",
"version": "1.0.0",
"dependencies": {}
}