添加视频转音频,md5修改, 视频加水印,视频打码,视频去原声,长图拼接(待完善)
|
|
@ -7,6 +7,7 @@ export class EventConstants {
|
|||
static readonly MineRefreshEvent = "MineRefreshEvent"
|
||||
static readonly MediaActionEvent = "MediaActionEvent"
|
||||
static readonly JumpToRecordEvent = "JumpToRecordEvent"
|
||||
static readonly JumpToToolsEvent = "JumpToToolsEvent"
|
||||
static readonly DownloadHistoryRefreshEvent = "DownloadHistoryRefreshEvent"
|
||||
static readonly MaterialListRefreshEvent = "MaterialListRefreshEvent"
|
||||
|
||||
|
|
|
|||
|
|
@ -42,7 +42,12 @@ export class RouterUrls {
|
|||
/**
|
||||
* 添加水印页
|
||||
*/
|
||||
static readonly ADD_WATER_MARKER_PAGE = "pages/main/home/tools/AddWaterMarkerPage"
|
||||
static readonly ADD_WATERMARK_PAGE = "pages/main/home/tools/AddWatermarkPage"
|
||||
|
||||
/**
|
||||
* 视频去水印页
|
||||
*/
|
||||
static readonly REMOVE_WATERMARK_PAGE = "pages/main/home/tools/RemoveWatermarkPage"
|
||||
|
||||
/**
|
||||
* MD5去重页
|
||||
|
|
@ -77,7 +82,12 @@ export class RouterUrls {
|
|||
/**
|
||||
* 视频转音频页
|
||||
*/
|
||||
static readonly TAKE_AUDIO_PAGE = "pages/main/home/tools/TakeAudioPage"
|
||||
static readonly VIDEO_TO_AUDIO_PAGE = "pages/main/home/tools/VideoToAudioPage"
|
||||
|
||||
/**
|
||||
* 长图拼接页
|
||||
*/
|
||||
static readonly IMAGE_MERGE_PAGE = "pages/main/home/tools/ImageMergePage"
|
||||
|
||||
/**
|
||||
* 素材详情页
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { ComponentContent } from '@kit.ArkUI';
|
||||
import { AppUtil, DisplayUtil, FileUtil, FormatUtil, NumberUtil, StrUtil, WindowUtil } from '@pura/harmony-utils';
|
||||
import { AppUtil, DisplayUtil, FileUtil, FormatUtil } from '@pura/harmony-utils';
|
||||
import { DialogCallback } from '../callback/DialogCallback';
|
||||
|
||||
export enum DownloadStatus {
|
||||
|
|
@ -29,7 +29,7 @@ function defaultBuilder(option: DownloadDialogOption) {
|
|||
option.status === DownloadStatus.VIDEO_DOWNLOADING ? '视频下载中' :
|
||||
option.status === DownloadStatus.AUDIO_DOWNLOADING ? '音频下载中' : '处理中') +
|
||||
(option.totalCount > 1 ? ` ${option.index + 1}/${option.totalCount}` : ''))
|
||||
.fontColor($r('app.color.color_90ffffff'))
|
||||
.fontColor($r('app.color.color_212226'))
|
||||
.fontSize(16)
|
||||
.visibility(option.status === DownloadStatus.COMPLETED ? Visibility.None : Visibility.Visible)
|
||||
|
||||
|
|
@ -44,8 +44,8 @@ function defaultBuilder(option: DownloadDialogOption) {
|
|||
Progress({ value: option.progress, total: option.totalSize, type: ProgressType.Linear })
|
||||
.width('100%')
|
||||
.style({ strokeWidth: 12, strokeRadius: 6 })
|
||||
.color('#FC4F54')
|
||||
.colorBlend($r('app.color.color_10ffffff'))
|
||||
.color($r('app.color.color_466afd'))
|
||||
// .colorBlend('#F1F2F6')
|
||||
.borderRadius(6)
|
||||
|
||||
Text(FormatUtil.getFormatPercentage(option.progress / option.totalSize, 1))
|
||||
|
|
@ -56,14 +56,14 @@ function defaultBuilder(option: DownloadDialogOption) {
|
|||
.fontSize(10)
|
||||
.borderRadius(10)
|
||||
.borderWidth(1)
|
||||
.borderColor($r('app.color.color_80ffffff'))
|
||||
.borderColor(Color.White)
|
||||
.backgroundColor($r("app.color.color_466afd"))
|
||||
.translate({ x: (AppUtil.getUIContext().px2vp(DisplayUtil.getWidth()) * 0.8 - 80) * option.progress / option.totalSize })
|
||||
}
|
||||
|
||||
Text(`${FileUtil.getFormatFileSize(option.progress)}/${option.totalSize !== 0 ?
|
||||
FileUtil.getFormatFileSize(option.totalSize) : '获取中'}`)
|
||||
.fontColor($r('app.color.color_999999'))
|
||||
.fontColor($r('app.color.color_727686'))
|
||||
.fontSize(12)
|
||||
.margin({ top: 16 })
|
||||
.visibility(option.status === DownloadStatus.PROCESSING ? Visibility.Hidden : Visibility.Visible)
|
||||
|
|
@ -72,8 +72,8 @@ function defaultBuilder(option: DownloadDialogOption) {
|
|||
Button('取消下载', { type: ButtonType.Capsule, stateEffect: true })
|
||||
.width(110)
|
||||
.height(36)
|
||||
.backgroundColor($r('app.color.color_333333'))
|
||||
.fontColor($r('app.color.color_50ffffff'))
|
||||
.backgroundColor('#F1F2F6')
|
||||
.fontColor('#80859B')
|
||||
.fontSize(15)
|
||||
.onClick(() => {
|
||||
if (option.callback?.cancel) {
|
||||
|
|
@ -85,11 +85,8 @@ function defaultBuilder(option: DownloadDialogOption) {
|
|||
Button('后台下载', { type: ButtonType.Capsule, stateEffect: true })
|
||||
.width(110)
|
||||
.height(36)
|
||||
.linearGradient({
|
||||
colors: [['#F62C6C', 0.0], ['#FC4F54', 1.0]],
|
||||
direction: GradientDirection.Right
|
||||
})
|
||||
.fontColor($r('app.color.color_90ffffff'))
|
||||
.backgroundColor($r('app.color.color_466afd'))
|
||||
.fontColor(Color.White)
|
||||
.fontSize(15)
|
||||
.margin({ left: 10 })
|
||||
.onClick(() => {
|
||||
|
|
@ -106,10 +103,10 @@ function defaultBuilder(option: DownloadDialogOption) {
|
|||
.visibility(option.status === DownloadStatus.COMPLETED ? Visibility.None : Visibility.Visible)
|
||||
|
||||
Column() {
|
||||
Text(option.isAudio ? '已保存到本地' : '已保存到系统相册中').fontColor($r('app.color.color_90ffffff')).fontSize(16)
|
||||
Text(option.isAudio ? '已保存到本地' : '已保存到系统相册中').fontColor($r('app.color.color_466afd')).fontSize(16)
|
||||
|
||||
Text(option.isAudio ? '文件管理/我的手机/Download/素材魔方' : '文件管理/我的手机/Download/图库')
|
||||
.fontColor($r('app.color.color_999999'))
|
||||
.fontColor($r('app.color.color_727686'))
|
||||
.fontSize(12)
|
||||
.margin({ top: 10 })
|
||||
|
||||
|
|
@ -117,8 +114,8 @@ function defaultBuilder(option: DownloadDialogOption) {
|
|||
Button('取消', { type: ButtonType.Capsule, stateEffect: true })
|
||||
.width(110)
|
||||
.height(36)
|
||||
.backgroundColor($r('app.color.color_333333'))
|
||||
.fontColor($r('app.color.color_50ffffff'))
|
||||
.backgroundColor('#F1F2F6')
|
||||
.fontColor('#80859B')
|
||||
.fontSize(15)
|
||||
.onClick(() => {
|
||||
if (option.callback?.cancel) {
|
||||
|
|
@ -132,11 +129,8 @@ function defaultBuilder(option: DownloadDialogOption) {
|
|||
Button('前往查看', { type: ButtonType.Capsule, stateEffect: true })
|
||||
.width(110)
|
||||
.height(36)
|
||||
.linearGradient({
|
||||
colors: [['#F62C6C', 0.0], ['#FC4F54', 1.0]],
|
||||
direction: GradientDirection.Right
|
||||
})
|
||||
.fontColor($r('app.color.color_90ffffff'))
|
||||
.backgroundColor($r('app.color.color_466afd'))
|
||||
.fontColor(Color.White)
|
||||
.fontSize(15)
|
||||
.onClick(() => {
|
||||
if (option.callback?.confirm) {
|
||||
|
|
@ -153,7 +147,7 @@ function defaultBuilder(option: DownloadDialogOption) {
|
|||
}
|
||||
.width('80%')
|
||||
.borderRadius(10)
|
||||
.backgroundColor($r('app.color.color_222222'))
|
||||
.backgroundColor(Color.White)
|
||||
.padding(20)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import { SaveUtils } from '../utils/SaveUtils';
|
|||
import { LoginManager } from '../manager/LoginGlobalManager';
|
||||
import { Want } from '@kit.AbilityKit';
|
||||
import { WXApi } from '../utils/wechat/WXApiEventHandlerImpl';
|
||||
import { Constants } from '../common/Constants';
|
||||
|
||||
@CustomDialog
|
||||
export struct JoinWxGroupCourseDialog {
|
||||
|
|
@ -15,22 +16,22 @@ export struct JoinWxGroupCourseDialog {
|
|||
isPlayback: boolean = true
|
||||
|
||||
images: Array<Resource> = [
|
||||
$r('app.media.ic_wx_group_tip1'),
|
||||
$r("app.media.ic_wx_group_tip2"),
|
||||
$r("app.media.ic_wx_group_tip3"),
|
||||
$r("app.media.ic_wx_group_tip4"),
|
||||
$r('app.media.ic_wx_group_tip5')
|
||||
$r('app.media.ic_join_wx_group_tip1'),
|
||||
$r('app.media.ic_join_wx_group_tip2'),
|
||||
$r("app.media.ic_join_wx_group_tip3"),
|
||||
$r("app.media.ic_join_wx_group_tip4"),
|
||||
$r("app.media.ic_join_wx_group_tip5"),
|
||||
];
|
||||
|
||||
steps: Array<string> = ['第一步', '第二步', '第三步', '第四步', '第五步']
|
||||
|
||||
qrCodePath = 'https://cdn.batiao8.com/kct/mp/kcsp_qrcode.png'
|
||||
qrCodePath = 'https://cdn.batiao8.com/kct/mp/scmf_qrcode.png'
|
||||
|
||||
@State currentIndex: number = 0
|
||||
|
||||
downloadImage() {
|
||||
try {
|
||||
const cachePath = FileUtil.getCacheDirPath() + FileUtil.separator + 'kcsp_wx_group_qrcode.jpg';
|
||||
const cachePath = FileUtil.getCacheDirPath() + FileUtil.separator + 'scmf_wx_group_qrcode.jpg';
|
||||
if (FileUtil.accessSync(cachePath)) {
|
||||
FileUtil.unlink(cachePath)
|
||||
}
|
||||
|
|
@ -43,7 +44,7 @@ export struct JoinWxGroupCourseDialog {
|
|||
SaveUtils.saveImageVideoToAlbumDialog([cachePath], false)
|
||||
.then((saved) => {
|
||||
if (saved) {
|
||||
PasteboardUtil.setDataTextSync(LoginManager.getUserInfo()!!.user_id)
|
||||
PasteboardUtil.setDataTextSync(`${LoginManager.getUserInfo()!!.user_id}|${Constants.APP_ID}`)
|
||||
ToastUtils.show('ID复制成功')
|
||||
this.jumpToWxScan()
|
||||
this.controller.close()
|
||||
|
|
@ -78,11 +79,11 @@ export struct JoinWxGroupCourseDialog {
|
|||
|
||||
build() {
|
||||
RelativeContainer() {
|
||||
Image($r('app.media.ic_wx_group_tip_bg')).width('100%').height(320)
|
||||
Image($r('app.media.ic_join_wx_group_tip_bg')).width('100%').height(320)
|
||||
|
||||
Text(this.isPlayback ? '添加直播回放助手流程' : '添加视频助手流程')
|
||||
.width('auto')
|
||||
.fontColor(Color.White)
|
||||
.fontColor($r('app.color.color_1a1a1a'))
|
||||
.fontSize(16)
|
||||
.fontWeight(FontWeight.Medium)
|
||||
.margin({ top: 16 })
|
||||
|
|
@ -95,10 +96,17 @@ export struct JoinWxGroupCourseDialog {
|
|||
List({space: 16}) {
|
||||
ForEach(this.steps, (item: string, index) => {
|
||||
ListItem() {
|
||||
Stack() {
|
||||
if (index === this.currentIndex) {
|
||||
Image($r('app.media.ic_join_wx_group_tip_indicator')).width(44).height(10)
|
||||
.margin({top: 10, left: 5})
|
||||
}
|
||||
Text(item)
|
||||
.fontColor(index == this.currentIndex ? Color.White : $r('app.color.color_bebebe'))
|
||||
.fontSize(index == this.currentIndex ? 16 : 14)
|
||||
.fontWeight(index == this.currentIndex ? FontWeight.Medium : FontWeight.Normal)
|
||||
.fontColor(index === this.currentIndex ? $r('app.color.color_466afd') : '#858D9F')
|
||||
.fontSize(index === this.currentIndex ? 16 : 14)
|
||||
.fontWeight(index === this.currentIndex ? FontWeight.Medium : FontWeight.Normal)
|
||||
.fontFamily(index === this.currentIndex ? 'almmsht' : '')
|
||||
}
|
||||
}
|
||||
.onClick(() => {
|
||||
this.swiperController.changeIndex(index, true)
|
||||
|
|
@ -137,9 +145,9 @@ export struct JoinWxGroupCourseDialog {
|
|||
|
||||
Row() {
|
||||
Button('取消', { type: ButtonType.Capsule, stateEffect: false })
|
||||
.fontColor($r('app.color.color_50ffffff'))
|
||||
.fontColor($r('app.color.color_1a1a1a'))
|
||||
.fontSize(15)
|
||||
.backgroundColor($r('app.color.color_333333'))
|
||||
.backgroundColor($r('app.color.color_eeeeee'))
|
||||
.width(126)
|
||||
.height(46)
|
||||
.onClick(() => {
|
||||
|
|
@ -149,11 +157,7 @@ export struct JoinWxGroupCourseDialog {
|
|||
Button('前往微信扫码加群', { type: ButtonType.Capsule, stateEffect: false })
|
||||
.fontColor(Color.White)
|
||||
.fontSize(15)
|
||||
.backgroundColor(Color.Transparent)
|
||||
.linearGradient({
|
||||
colors: [['#F62C6C', 0.0], ['#FC4F54', 1.0]],
|
||||
direction: GradientDirection.Right
|
||||
})
|
||||
.backgroundColor($r('app.color.color_466afd'))
|
||||
.layoutWeight(1)
|
||||
.height(46)
|
||||
.onClick(() => {
|
||||
|
|
@ -164,7 +168,7 @@ export struct JoinWxGroupCourseDialog {
|
|||
this.downloadImage()
|
||||
})
|
||||
}
|
||||
.backgroundColor($r('app.color.color_222222'))
|
||||
.backgroundColor(Color.White)
|
||||
.alignRules({
|
||||
top: {anchor: 'swiper', align: VerticalAlign.Bottom}
|
||||
})
|
||||
|
|
|
|||
|
|
@ -4,12 +4,12 @@ import { ComponentContent } from '@kit.ArkUI';
|
|||
function defaultBuilder(text: string) {
|
||||
Column() {
|
||||
LoadingProgress()
|
||||
.color(Color.White)
|
||||
.color($r('app.color.color_466afd'))
|
||||
.width(50)
|
||||
.height(50)
|
||||
|
||||
Text(text)
|
||||
.fontColor(Color.White)
|
||||
.fontColor($r('app.color.color_466afd'))
|
||||
.fontSize(12)
|
||||
.maxLines(1)
|
||||
.textOverflow({ overflow: TextOverflow.Ellipsis })
|
||||
|
|
@ -22,7 +22,7 @@ function defaultBuilder(text: string) {
|
|||
.height(124)
|
||||
.justifyContent(FlexAlign.Center)
|
||||
.borderRadius(6)
|
||||
.backgroundColor($r('app.color.color_222222'))
|
||||
.backgroundColor(Color.White)
|
||||
.padding({left: 10, right: 10})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -52,11 +52,11 @@ export class MediaEntity {
|
|||
initFileName(): string {
|
||||
if (!this.name) {
|
||||
if (this instanceof VideoMaterial) {
|
||||
this.name = `kcsp_${systemDateTime.getTime() + RandomUtil.getRandomInt(1000, 2000)}.mp4`
|
||||
this.name = `scmf_${systemDateTime.getTime() + RandomUtil.getRandomInt(1000, 2000)}.mp4`
|
||||
} else if (this instanceof AudioMaterial) {
|
||||
this.name = `kcsp_${systemDateTime.getTime() + RandomUtil.getRandomInt(1000, 2000)}.mp3`
|
||||
this.name = `scmf_${systemDateTime.getTime() + RandomUtil.getRandomInt(1000, 2000)}.mp3`
|
||||
} else if (this instanceof ImageMaterial) {
|
||||
this.name = `kcsp_${systemDateTime.getTime() + RandomUtil.getRandomInt(1000, 2000)}.jpeg`
|
||||
this.name = `scmf_${systemDateTime.getTime() + RandomUtil.getRandomInt(1000, 2000)}.jpeg`
|
||||
}
|
||||
}
|
||||
return this.name
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { ArrayList } from "@kit.ArkTS";
|
||||
import { LoginManager } from "../manager/LoginGlobalManager";
|
||||
import { ArrayList } from '@kit.ArkTS';
|
||||
import { LoginManager } from '../manager/LoginGlobalManager';
|
||||
|
||||
export class MenuEntity {
|
||||
icon: Resource | null = null;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,32 @@
|
|||
import { ArrayList } from '@kit.ArkTS';
|
||||
|
||||
export class ToolMenuEntity {
|
||||
icon: Resource | null = null;
|
||||
title: string = "";
|
||||
alias: string = "";
|
||||
desc: string = "";
|
||||
count: string = "";
|
||||
colors: Array<string> = [];
|
||||
|
||||
constructor(icon: Resource, title: string, alias: string, desc: string, count: string, colors: Array<string>) {
|
||||
this.icon = icon;
|
||||
this.title = title;
|
||||
this.alias = alias;
|
||||
this.desc = desc;
|
||||
this.count = count
|
||||
this.colors = colors
|
||||
}
|
||||
}
|
||||
|
||||
export function toolsList(): ArrayList<ToolMenuEntity> {
|
||||
let list = new ArrayList<ToolMenuEntity>()
|
||||
list.add(new ToolMenuEntity($r("app.media.ic_tool_icon4"), "MD5修改", "resetMD5", '修改视频MD5', '0.2', ['#BCFFDE', '#EEFFF7']))
|
||||
list.add(new ToolMenuEntity($r("app.media.ic_tool_icon5"), "视频转文字", "videoToText", '文案轻松提取', '0.3', ['#DFE8FF', '#F8FAFF']))
|
||||
list.add(new ToolMenuEntity($r("app.media.ic_tool_icon6"), "视频转音频", "videoToAudio", '提取背景音乐', '1.2', ['#E9E3FF', '#F9F7FF']))
|
||||
list.add(new ToolMenuEntity($r("app.media.ic_tool_icon7"), "语音转文字", "audioToText", '内容轻松记录', '1.1', ['#FFE1E1', '#FFF3F3']))
|
||||
list.add(new ToolMenuEntity($r("app.media.ic_tool_icon8"), "视频加水印", "addWatermark", '提高原创识别度', '0.5', ['#C2EFFF', '#E3F8FF']))
|
||||
list.add(new ToolMenuEntity($r("app.media.ic_tool_icon9"), "长图拼接", "longImageMerge", '多张图形成一张', '0.4', ['#FFF4C6', '#FDFAEF']))
|
||||
list.add(new ToolMenuEntity($r("app.media.ic_tool_icon10"), "视频打码", "removeWatermark", '敏感信息无处漏', '0.1', ['#DFE8FF', '#F8FAFF']))
|
||||
list.add(new ToolMenuEntity($r("app.media.ic_tool_icon11"), "视频去原声", "removeAudio", '一键去背景音乐', '0.7', ['#F0DDFF', '#FAFAFE']))
|
||||
return list;
|
||||
}
|
||||
|
|
@ -44,6 +44,11 @@ export class Api {
|
|||
*/
|
||||
static readonly USER_DESTROY = '/api/user/destroy';
|
||||
|
||||
/**
|
||||
* 退出登陆
|
||||
*/
|
||||
static readonly USER_LOGOUT = '/api/user/logout';
|
||||
|
||||
/**
|
||||
* 用户账号列表
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -147,6 +147,14 @@ class ApiService {
|
|||
return AxiosRequest.post<HttpResult>(Api.USER_DESTROY)
|
||||
}
|
||||
|
||||
/**
|
||||
* 退出登陆
|
||||
* @returns
|
||||
*/
|
||||
logout(): Promise<HttpResult> {
|
||||
return AxiosRequest.post<HttpResult>(Api.USER_LOGOUT)
|
||||
}
|
||||
|
||||
/**
|
||||
* 解绑账号
|
||||
* @returns
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import { ConfigManager } from '../../manager/UserConfigManager';
|
|||
import { EventReportGlobalManager } from '../../manager/EventReportGlobalManager';
|
||||
import { PasteboardUtils } from '../../utils/PasteboardUtils';
|
||||
import { MaterialPage } from './material/MaterialPage';
|
||||
import { ToolsPage } from './mine/tool/ToolsPage';
|
||||
|
||||
@Entry
|
||||
@ComponentV2
|
||||
|
|
@ -51,6 +52,7 @@ struct MainPage {
|
|||
aboutToDisappear(): void {
|
||||
AppUtil.getContext().eventHub.off(EventConstants.LoginSuccessEvent);
|
||||
AppUtil.getContext().eventHub.off(EventConstants.JumpToRecordEvent);
|
||||
AppUtil.getContext().eventHub.off(EventConstants.JumpToToolsEvent);
|
||||
}
|
||||
|
||||
onPageShow(): void {
|
||||
|
|
@ -71,6 +73,9 @@ struct MainPage {
|
|||
this.tabController.changeIndex(3)
|
||||
this.currentIndex = 1
|
||||
})
|
||||
AppUtil.getContext().eventHub.on(EventConstants.JumpToToolsEvent, () => {
|
||||
this.tabController.changeIndex(2)
|
||||
})
|
||||
}
|
||||
|
||||
checkPasteboard() {
|
||||
|
|
@ -112,7 +117,7 @@ struct MainPage {
|
|||
.tabBar(this.tabBuilder(this.titles[1], 1, $r('app.media.ic_material_select'), $r('app.media.ic_material_default')))
|
||||
|
||||
TabContent() {
|
||||
|
||||
ToolsPage()
|
||||
}
|
||||
.tabBar(this.tabBuilder(this.titles[2], 2, $r('app.media.ic_tool_select'), $r('app.media.ic_tool_default')))
|
||||
|
||||
|
|
|
|||
|
|
@ -340,20 +340,22 @@ export struct HomePage {
|
|||
.onClick(() => {
|
||||
switch (item.alias) {
|
||||
case 'videoToAudio': {
|
||||
this.getUIContext().getRouter().pushUrl({url: RouterUrls.TAKE_AUDIO_PAGE})
|
||||
this.getUIContext().getRouter().pushUrl({url: RouterUrls.VIDEO_TO_AUDIO_PAGE})
|
||||
break
|
||||
}
|
||||
case 'addWatermark': {
|
||||
this.getUIContext().getRouter().pushUrl({url: RouterUrls.ADD_WATER_MARKER_PAGE})
|
||||
this.getUIContext().getRouter().pushUrl({url: RouterUrls.ADD_WATERMARK_PAGE})
|
||||
break
|
||||
}
|
||||
case 'videoToText': {
|
||||
break
|
||||
}
|
||||
case 'longImageMerge': {
|
||||
this.getUIContext().getRouter().pushUrl({url: RouterUrls.IMAGE_MERGE_PAGE})
|
||||
break
|
||||
}
|
||||
case 'moreTools': {
|
||||
AppUtil.getContext().eventHub.emit(EventConstants.JumpToToolsEvent);
|
||||
break
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -380,6 +380,7 @@ struct TakeMaterialPage {
|
|||
parseUrl(url: string) {
|
||||
if (StrUtil.isNotEmpty(this.inputText)) {
|
||||
this.viewModel.getMaterialInfo(url);
|
||||
KeyboardUtil.hide()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -499,7 +500,6 @@ struct TakeMaterialPage {
|
|||
.backgroundColor($r('app.color.color_466afd'))
|
||||
.onClick(() => {
|
||||
if (StrUtil.isNotEmpty(this.inputText)) {
|
||||
KeyboardUtil.hide()
|
||||
this.parseUrl(this.inputText)
|
||||
EventReportGlobalManager.eventReport(EventConstants.GET_MATERIAL, "material-button", this.inputText)
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ struct MaterialDetailPage {
|
|||
|
||||
download() {
|
||||
LoadingDialog.show(this.getUIContext())
|
||||
let outputPath = FileUtil.getCacheDirPath() + FileUtil.separator + `kcsp_${systemDateTime.getTime()}.jpeg`
|
||||
let outputPath = FileUtil.getCacheDirPath() + FileUtil.separator + `scmf_${systemDateTime.getTime()}.jpeg`
|
||||
let config: request.agent.Config = {
|
||||
action: request.agent.Action.DOWNLOAD,
|
||||
url: this.material!!.pic!!.url,
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ struct AddAudioPage {
|
|||
// 复制音频文件到缓存目录下
|
||||
FileUtil.copyFileSync(audioFile.fd, cacheAudioPath)
|
||||
|
||||
let outputPath = FileUtil.getCacheDirPath() + FileUtil.separator + `kcsp_${systemDateTime.getTime()}.mp4`
|
||||
let outputPath = FileUtil.getCacheDirPath() + FileUtil.separator + `scmf_${systemDateTime.getTime()}.mp4`
|
||||
let cmd = `ffmpeg -i ${cacheVideoPath} -stream_loop -1 -i ${cacheAudioPath} -c:v copy -c:a aac -shortest -map 0:v -map 1:a ${outputPath}`
|
||||
MP4Parser.ffmpegCmd(cmd, {
|
||||
callBackResult: (code: number) => {
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ import { avSessionManager } from '../../../../manager/AVSessionManager'
|
|||
|
||||
@Entry
|
||||
@ComponentV2
|
||||
struct AddWaterMarkerPage {
|
||||
struct AddWatermarkPage {
|
||||
@Local uri?: string
|
||||
@Local currentTime: number = 0
|
||||
@Local durationTime: number = 0
|
||||
|
|
@ -29,7 +29,7 @@ struct AddWaterMarkerPage {
|
|||
@Local isSuccess: boolean = false
|
||||
@Local playerSize: media.PixelMapParams = { width: 0, height: 0 }
|
||||
|
||||
@Local showWaterMaker: boolean = false
|
||||
@Local showWatermark: boolean = false
|
||||
@Local textContent: string = ''
|
||||
@Local imagePath: string = ''
|
||||
|
||||
|
|
@ -37,10 +37,10 @@ struct AddWaterMarkerPage {
|
|||
private videoSize: media.PixelMapParams = { width: 0, height: 0 }
|
||||
private rect: RectPosition = { x: 0, y: 0, width: 0, height: 0 }
|
||||
|
||||
addWaterMarker() {
|
||||
addWatermark() {
|
||||
LoadingDialog.show(this.getUIContext())
|
||||
this.isSuccess = false
|
||||
let cacheVideoPath = FileUtil.getCacheDirPath() + FileUtil.separator + `kcsp_${systemDateTime.getTime()}.mp4`
|
||||
let cacheVideoPath = FileUtil.getCacheDirPath() + FileUtil.separator + `scmf_${systemDateTime.getTime()}.mp4`
|
||||
if (FileUtil.accessSync(cacheVideoPath)) {
|
||||
FileUtil.unlinkSync(cacheVideoPath)
|
||||
}
|
||||
|
|
@ -58,7 +58,7 @@ struct AddWaterMarkerPage {
|
|||
this.getUIContext().getComponentSnapshot().get(StrUtil.isNotEmpty(this.textContent) ? 'textWaterMarker' : 'imageWaterMarker')
|
||||
.then(async (image: image.PixelMap) => {
|
||||
let imagePath = await ImageUtil.savePixelMap(image, FileUtil.getCacheDirPath(), `cache_${systemDateTime.getTime()}.png`)
|
||||
let outputPath = FileUtil.getCacheDirPath() + FileUtil.separator + `kcsp_${systemDateTime.getTime()}.mp4`
|
||||
let outputPath = FileUtil.getCacheDirPath() + FileUtil.separator + `scmf_${systemDateTime.getTime()}.mp4`
|
||||
let cmd = `ffmpeg -i ${cacheVideoPath} -i ${imagePath} -filter_complex [1:v]scale=${Math.round(imageWidth)}:${Math.round(imageHeight)}[wm];[0:v][wm]overlay=${imageX}:${imageY} -c:v h264 -pix_fmt yuv420p -y ${outputPath}`
|
||||
MP4Parser.ffmpegCmd(cmd, {
|
||||
callBackResult: (code: number) => {
|
||||
|
|
@ -93,7 +93,7 @@ struct AddWaterMarkerPage {
|
|||
this.isSuccess = false
|
||||
this.uri = uris[0]
|
||||
|
||||
this.showWaterMaker = false
|
||||
this.showWatermark = false
|
||||
this.textContent = ''
|
||||
this.imagePath = ''
|
||||
|
||||
|
|
@ -101,7 +101,7 @@ struct AddWaterMarkerPage {
|
|||
.then((size) => {
|
||||
this.videoSize = size
|
||||
if (size.width && size.height) {
|
||||
const ratio = (DisplayUtil.getWidth() - 180) / size.width
|
||||
const ratio = (DisplayUtil.getWidth() - 300) / size.width
|
||||
this.playerSize = {width: Math.ceil(size.width * ratio), height: Math.ceil(size.height * ratio)}
|
||||
}
|
||||
})
|
||||
|
|
@ -168,37 +168,28 @@ struct AddWaterMarkerPage {
|
|||
|
||||
build() {
|
||||
Column() {
|
||||
TitleBar({ title: '加水印' })
|
||||
TitleBar({ title: '视频加水印' })
|
||||
|
||||
Column() {
|
||||
Row() {
|
||||
Text('上传视频').fontColor($r('app.color.color_90ffffff')).fontSize(16).fontWeight(FontWeight.Medium)
|
||||
Text('(仅支持mp4格式)').fontColor($r('app.color.color_50ffffff')).fontSize(12)
|
||||
}.alignSelf(ItemAlign.Start)
|
||||
|
||||
RelativeContainer() {
|
||||
Stack() {
|
||||
Image($r('app.media.ic_add_video')).width(44).height(44)
|
||||
Stack() {
|
||||
Column() {
|
||||
Image($r('app.media.ic_add_video')).width(40).height(40)
|
||||
Text('请上传视频').fontColor($r('app.color.color_466afd')).fontSize(15).fontWeight(FontWeight.Medium).margin({ top: 8})
|
||||
}
|
||||
.width(140)
|
||||
.height(140)
|
||||
.borderRadius(10)
|
||||
.backgroundColor($r('app.color.color_333333'))
|
||||
.alignRules({
|
||||
start: { anchor: '__container__', align: HorizontalAlign.Start },
|
||||
top: { anchor: '__container__', align: VerticalAlign.Top },
|
||||
end: { anchor: '__container__', align: HorizontalAlign.End },
|
||||
bottom: { anchor: '__container__', align: VerticalAlign.Bottom }
|
||||
})
|
||||
}
|
||||
.width('100%')
|
||||
.aspectRatio(1)
|
||||
.borderRadius(20)
|
||||
.backgroundColor(Color.White)
|
||||
.shadow({radius: 10, color: '#1a9399a1'})
|
||||
.onClick(() => {
|
||||
this.selectVideo()
|
||||
})
|
||||
}
|
||||
.height(220)
|
||||
.margin({ top: 12 })
|
||||
.borderRadius(8)
|
||||
.backgroundColor($r('app.color.color_222222'))
|
||||
}.margin({ left: 16, top: 16, right: 16 })
|
||||
.width('100%')
|
||||
.height('auto')
|
||||
.padding({left: 32, right: 32})
|
||||
.margin({top: 40})
|
||||
.visibility(this.uri ? Visibility.None : Visibility.Visible)
|
||||
|
||||
Column() {
|
||||
|
|
@ -305,7 +296,7 @@ struct AddWaterMarkerPage {
|
|||
bottom: { anchor: 'video', align: VerticalAlign.Bottom }
|
||||
})
|
||||
|
||||
if (this.showWaterMaker && this.uri && !this.isSuccess) {
|
||||
if (this.showWatermark && this.uri && !this.isSuccess) {
|
||||
WaterMarkerView({
|
||||
content: this.textContent,
|
||||
imagePath: this.imagePath,
|
||||
|
|
@ -313,7 +304,7 @@ struct AddWaterMarkerPage {
|
|||
this.rect = rect
|
||||
},
|
||||
onClose: () => {
|
||||
this.showWaterMaker = false
|
||||
this.showWatermark = false
|
||||
this.textContent = ''
|
||||
this.imagePath = ''
|
||||
}
|
||||
|
|
@ -332,25 +323,36 @@ struct AddWaterMarkerPage {
|
|||
|
||||
Row() {
|
||||
Column(){
|
||||
Image($r('app.media.ic_text_water_marker')).width(50).height(50)
|
||||
Text('文字').fontColor($r('app.color.color_90ffffff')).fontSize(14).margin({ top: 8 })
|
||||
Image($r('app.media.ic_watermark_icon1')).width(26).height(26)
|
||||
Text('水印').fontColor($r('app.color.color_212226')).fontSize(12).margin({ top: 8 })
|
||||
}
|
||||
.layoutWeight(1)
|
||||
.onClick(() => {
|
||||
if (!this.showWaterMaker) {
|
||||
|
||||
})
|
||||
|
||||
Column(){
|
||||
Image($r('app.media.ic_watermark_icon2')).width(26).height(26)
|
||||
Text('文字').fontColor($r('app.color.color_212226')).fontSize(12).margin({ top: 8 })
|
||||
}
|
||||
.layoutWeight(1)
|
||||
.onClick(() => {
|
||||
if (!this.showWatermark) {
|
||||
this.controller.stop()
|
||||
EditTextDialog.show(this.getUIContext(), {title: '添加水印', hintText: '请输入文字', confirm: (text) => {
|
||||
this.textContent = text
|
||||
this.showWaterMaker = true
|
||||
this.showWatermark = true
|
||||
}})
|
||||
}
|
||||
})
|
||||
|
||||
Column(){
|
||||
Image($r('app.media.ic_image_water_marker')).width(50).height(50)
|
||||
Text('图片').fontColor($r('app.color.color_90ffffff')).fontSize(14).margin({ top: 8 })
|
||||
Image($r('app.media.ic_watermark_icon3')).width(26).height(26)
|
||||
Text('图片').fontColor($r('app.color.color_212226')).fontSize(12).margin({ top: 8 })
|
||||
}
|
||||
.margin({ left: 50 })
|
||||
.layoutWeight(1)
|
||||
.onClick(() => {
|
||||
if (!this.showWaterMaker) {
|
||||
if (!this.showWatermark) {
|
||||
this.controller.stop()
|
||||
PhotoHelper.selectEasy({
|
||||
MIMEType: photoAccessHelper.PhotoViewMIMETypes.IMAGE_TYPE,
|
||||
|
|
@ -363,34 +365,70 @@ struct AddWaterMarkerPage {
|
|||
if (uris.length != 0) {
|
||||
this.isSuccess = false
|
||||
this.imagePath = uris[0]
|
||||
this.showWaterMaker = true
|
||||
this.showWatermark = true
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
.margin({ top: 20 })
|
||||
.width('90%')
|
||||
.height(82)
|
||||
.margin({ top: 20, bottom: 20 })
|
||||
.borderRadius(10)
|
||||
.backgroundColor(Color.White)
|
||||
}
|
||||
.layoutWeight(1)
|
||||
.visibility(this.uri ? Visibility.Visible : Visibility.None)
|
||||
|
||||
Blank().layoutWeight(1).visibility(this.uri ? Visibility.None : Visibility.Visible)
|
||||
|
||||
Stack() {
|
||||
Button('确认处理', { type: ButtonType.Capsule, stateEffect: true })
|
||||
.width('100%')
|
||||
.height(46)
|
||||
.fontColor(Color.White)
|
||||
.fontSize(15)
|
||||
.fontWeight(FontWeight.Medium)
|
||||
.backgroundColor($r('app.color.color_466afd'))
|
||||
.onClick(() => {
|
||||
if (this.uri) {
|
||||
this.addWatermark()
|
||||
} else {
|
||||
ToastUtils.show('请上传视频')
|
||||
}
|
||||
})
|
||||
.visibility(!this.isSuccess ? Visibility.Visible : Visibility.None)
|
||||
|
||||
Row() {
|
||||
Text(this.isSuccess ? '重新上传' : '取消').fontColor($r('app.color.color_90ffffff'))
|
||||
.fontSize(17)
|
||||
.margin({ left: 16 })
|
||||
.onClick(() => {
|
||||
this.controller.stop()
|
||||
if (this.isSuccess) {
|
||||
this.selectVideo()
|
||||
} else {
|
||||
this.getUIContext().getRouter().back()
|
||||
Button({ type: ButtonType.Capsule, stateEffect: true }) {
|
||||
Row() {
|
||||
Image($r('app.media.ic_reupload')).width(20).height(20)
|
||||
Text('重新上传').fontColor($r('app.color.color_466afd')).fontSize(15).fontWeight(FontWeight.Medium)
|
||||
}
|
||||
})
|
||||
Blank().layoutWeight(1)
|
||||
Text(this.isSuccess ? '保存' : '确定')
|
||||
.fontColor($r("app.color.color_466afd"))
|
||||
.fontSize(17)
|
||||
.margin({ right: 16 })
|
||||
}
|
||||
.height(46)
|
||||
.layoutWeight(1)
|
||||
.borderWidth(1)
|
||||
.borderColor($r('app.color.color_466afd'))
|
||||
.backgroundColor(Color.Transparent)
|
||||
.onClick(() => {
|
||||
this.controller.stop()
|
||||
this.selectVideo()
|
||||
})
|
||||
|
||||
Blank().width(9)
|
||||
|
||||
Button({ type: ButtonType.Capsule, stateEffect: true }) {
|
||||
Row() {
|
||||
Image($r('app.media.ic_download3')).width(20).height(20)
|
||||
Text('保存').fontColor(Color.White).fontSize(15).fontWeight(FontWeight.Medium)
|
||||
}
|
||||
}
|
||||
.height(46)
|
||||
.layoutWeight(1)
|
||||
.backgroundColor($r('app.color.color_466afd'))
|
||||
.onClick(() => {
|
||||
this.controller.stop()
|
||||
if (this.isSuccess) {
|
||||
SaveUtils.saveImageVideoToAlbumDialog([this.uri!!])
|
||||
.then((saved) => {
|
||||
if (saved) {
|
||||
|
|
@ -403,20 +441,12 @@ struct AddWaterMarkerPage {
|
|||
.catch((e: BusinessError) => {
|
||||
ToastUtils.show('保存失败:' + e.message)
|
||||
})
|
||||
|
||||
} else {
|
||||
if (this.showWaterMaker) {
|
||||
this.addWaterMarker()
|
||||
} else {
|
||||
ToastUtils.show('请添加水印')
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
.margin({ top: 20, bottom: 30 })
|
||||
.visibility(this.isSuccess ? Visibility.Visible : Visibility.None)
|
||||
}
|
||||
.layoutWeight(1)
|
||||
.visibility(this.uri ? Visibility.Visible : Visibility.None)
|
||||
.padding({left: 16, top: 9, right: 16, bottom: 30 })
|
||||
.backgroundColor(Color.White)
|
||||
}
|
||||
.width('100%')
|
||||
.height('100%')
|
||||
|
|
@ -35,7 +35,7 @@ struct ClipVideoPage {
|
|||
clipVideo() {
|
||||
LoadingDialog.show(this.getUIContext())
|
||||
this.isSuccess = false
|
||||
let cacheVideoPath = FileUtil.getCacheDirPath() + FileUtil.separator + `kcsp_${systemDateTime.getTime()}.mp4`
|
||||
let cacheVideoPath = FileUtil.getCacheDirPath() + FileUtil.separator + `scmf_${systemDateTime.getTime()}.mp4`
|
||||
if (FileUtil.accessSync(cacheVideoPath)) {
|
||||
FileUtil.unlinkSync(cacheVideoPath)
|
||||
}
|
||||
|
|
@ -68,7 +68,7 @@ struct ClipVideoPage {
|
|||
clipY = clipHeight === originPlayerSize.height ? 0 : (originPlayerSize.height!! - this.playerSize.height!!) / 2 * (this.videoSize.height!!) / originPlayerSize.height!!
|
||||
}
|
||||
|
||||
let outputPath = FileUtil.getCacheDirPath() + FileUtil.separator + `kcsp_${systemDateTime.getTime()}.mp4`
|
||||
let outputPath = FileUtil.getCacheDirPath() + FileUtil.separator + `scmf_${systemDateTime.getTime()}.mp4`
|
||||
let cmd = `ffmpeg -i ${cacheVideoPath} -vf \"crop=${Math.ceil(clipWidth)}:${Math.ceil(clipHeight)}:${Math.ceil(clipX)}:${Math.ceil(clipY)}\" -c:v h264 -pix_fmt yuv420p -y ${outputPath}`
|
||||
MP4Parser.ffmpegCmd(cmd, {
|
||||
callBackResult: (code: number) => {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,251 @@
|
|||
import { PhotoHelper } from '@pura/picker_utils'
|
||||
import { TitleBar } from '../../../../view/TitleBar'
|
||||
import { photoAccessHelper } from '@kit.MediaLibraryKit'
|
||||
import { BusinessError, systemDateTime } from '@kit.BasicServicesKit'
|
||||
import { AppUtil, FileUtil } from '@pura/harmony-utils'
|
||||
import { ToastUtils } from '../../../../utils/ToastUtils'
|
||||
import { fileIo } from '@kit.CoreFileKit'
|
||||
import { SaveUtils } from '../../../../utils/SaveUtils'
|
||||
import { LoadingDialog } from '../../../../dialog/LoadingDialog'
|
||||
import { DownloadDialog, DownloadStatus } from '../../../../dialog/DownloadDialog'
|
||||
import { EventConstants } from '../../../../common/EventConstants'
|
||||
import { TipDialog } from '../../../../dialog/TipDialog'
|
||||
import { avSessionManager } from '../../../../manager/AVSessionManager'
|
||||
|
||||
@Entry
|
||||
@ComponentV2
|
||||
struct ImageMergePage {
|
||||
@Local uri?: string = undefined
|
||||
@Local selectedImage?: string = undefined
|
||||
@Local imageUris: Array<string> = []
|
||||
@Local currentTime: number = 0
|
||||
@Local durationTime: number = 0
|
||||
@Local isPlaying: boolean = false
|
||||
@Local isSuccess: boolean = false
|
||||
|
||||
private selectedImages: Array<string> = []
|
||||
|
||||
mergeImage() {
|
||||
|
||||
}
|
||||
|
||||
selectPhotos() {
|
||||
PhotoHelper.select({
|
||||
MIMEType: photoAccessHelper.PhotoViewMIMETypes.IMAGE_TYPE,
|
||||
maxSelectNumber: 9,
|
||||
preselectedUris: this.selectedImages,
|
||||
isOriginalSupported: true,
|
||||
})
|
||||
.then((result: photoAccessHelper.PhotoSelectResult) => {
|
||||
if (result.photoUris.length != 0) {
|
||||
this.isSuccess = false
|
||||
this.selectedImages = result.photoUris
|
||||
this.imageUris = result.photoUris
|
||||
this.selectedImage = result.photoUris[0]
|
||||
}
|
||||
})
|
||||
.catch((e: BusinessError) => {
|
||||
ToastUtils.show(e.message)
|
||||
})
|
||||
}
|
||||
|
||||
showDownloadDialog() {
|
||||
DownloadDialog.show(this.getUIContext(), { status: DownloadStatus.COMPLETED, totalSize: 0, progress: 0, totalCount: 1, index: 0, callback: {
|
||||
confirm: () => {
|
||||
AppUtil.getContext().eventHub.emit(EventConstants.JumpToRecordEvent, 0)
|
||||
this.getUIContext().getRouter().back()
|
||||
}
|
||||
} })
|
||||
}
|
||||
|
||||
onBackPress(): boolean | void {
|
||||
if (this.isSuccess) {
|
||||
TipDialog.show(this.getUIContext(), {title:'温馨提示', content:'图片尚未保存,是否确定退出?', callback: {
|
||||
confirm: () => {
|
||||
this.getUIContext().getRouter().back()
|
||||
}
|
||||
}})
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
build() {
|
||||
Column() {
|
||||
TitleBar({ title: '长图拼接' })
|
||||
|
||||
Stack() {
|
||||
Stack() {
|
||||
Stack() {
|
||||
Column() {
|
||||
Image($r('app.media.ic_add_image')).width(40).height(40)
|
||||
Text('请上传图片').fontColor($r('app.color.color_466afd')).fontSize(15).fontWeight(FontWeight.Medium).margin({ top: 8})
|
||||
}
|
||||
}
|
||||
.width('100%')
|
||||
.height('100%')
|
||||
.onClick(() => {
|
||||
this.selectPhotos()
|
||||
})
|
||||
.visibility(this.imageUris.length !== 0 ? Visibility.None : Visibility.Visible)
|
||||
|
||||
Image(this.selectedImage).width('100%').height('100%')
|
||||
.borderRadius(20)
|
||||
.visibility(this.imageUris.length === 0 ? Visibility.None : Visibility.Visible)
|
||||
}
|
||||
.width('100%')
|
||||
.aspectRatio(1)
|
||||
.borderRadius(20)
|
||||
.backgroundColor(Color.White)
|
||||
.shadow({radius: 10, color: '#1a9399a1'})
|
||||
}
|
||||
.width('100%')
|
||||
.height('auto')
|
||||
.padding({left: 32, right: 32})
|
||||
.margin({top: 40})
|
||||
|
||||
Blank().layoutWeight(1)
|
||||
|
||||
Scroll() {
|
||||
List({space: 8}) {
|
||||
ForEach(this.imageUris, (item: string, index) => {
|
||||
ListItem() {
|
||||
RelativeContainer() {
|
||||
Stack() {
|
||||
Image(item).width('100%').height('100%').borderRadius(6)
|
||||
Text(`${index + 1}`)
|
||||
.width(20)
|
||||
.height(20)
|
||||
.textAlign(TextAlign.Center)
|
||||
.fontColor(Color.White)
|
||||
.fontSize(14)
|
||||
.borderRadius(10)
|
||||
.backgroundColor('#99000000')
|
||||
}
|
||||
.width(80)
|
||||
.height(80)
|
||||
.margin({top: 11, right: 11})
|
||||
|
||||
Image($r('app.media.ic_delete_image')).width(22).height(22)
|
||||
.alignRules({
|
||||
right: {anchor: '__container__', align: HorizontalAlign.End}
|
||||
})
|
||||
.onClick(() => {
|
||||
this.imageUris.splice(index, 1)
|
||||
if (this.imageUris.length === 0) {
|
||||
this.selectedImage = undefined
|
||||
} else {
|
||||
if (item !== this.selectedImage) {
|
||||
this.selectedImage = this.imageUris[0]
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
.height('100%')
|
||||
.aspectRatio(1)
|
||||
}
|
||||
.onClick(() => {
|
||||
this.selectedImage = item
|
||||
})
|
||||
})
|
||||
|
||||
if (this.imageUris.length > 0 && this.imageUris.length < 9) {
|
||||
ListItem() {
|
||||
Stack() {
|
||||
Column() {
|
||||
Image($r('app.media.ic_add_image')).width(24).height(24)
|
||||
Text('请上传图片').fontColor($r('app.color.color_466afd')).fontSize(10).margin({top: 4})
|
||||
}
|
||||
}
|
||||
.width(80)
|
||||
.height(80)
|
||||
.borderRadius(6)
|
||||
.backgroundColor(Color.White)
|
||||
.margin({top: 11, right: 11})
|
||||
.onClick(() => {
|
||||
this.selectPhotos()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
.width('100%')
|
||||
.scrollBar(BarState.Off)
|
||||
.listDirection(Axis.Horizontal)
|
||||
.padding({left: 32, right: 32})
|
||||
}
|
||||
.width('100%')
|
||||
.height(92)
|
||||
.scrollBar(BarState.Off)
|
||||
.scrollable(ScrollDirection.Horizontal)
|
||||
.margin({bottom: 20})
|
||||
|
||||
|
||||
Stack() {
|
||||
Button('确认处理', { type: ButtonType.Capsule, stateEffect: true })
|
||||
.width('100%')
|
||||
.height(46)
|
||||
.fontColor(Color.White)
|
||||
.fontSize(15)
|
||||
.fontWeight(FontWeight.Medium)
|
||||
.backgroundColor($r('app.color.color_466afd'))
|
||||
.onClick(() => {
|
||||
if (this.imageUris) {
|
||||
this.mergeImage()
|
||||
} else {
|
||||
ToastUtils.show('请上传图片')
|
||||
}
|
||||
})
|
||||
.visibility(!this.isSuccess ? Visibility.Visible : Visibility.None)
|
||||
|
||||
Row() {
|
||||
Button({ type: ButtonType.Capsule, stateEffect: true }) {
|
||||
Row() {
|
||||
Image($r('app.media.ic_reupload')).width(20).height(20)
|
||||
Text('重新上传').fontColor($r('app.color.color_466afd')).fontSize(15).fontWeight(FontWeight.Medium)
|
||||
}
|
||||
}
|
||||
.height(46)
|
||||
.layoutWeight(1)
|
||||
.borderWidth(1)
|
||||
.borderColor($r('app.color.color_466afd'))
|
||||
.backgroundColor(Color.Transparent)
|
||||
.onClick(() => {
|
||||
this.selectPhotos()
|
||||
})
|
||||
|
||||
Blank().width(9)
|
||||
|
||||
Button({ type: ButtonType.Capsule, stateEffect: true }) {
|
||||
Row() {
|
||||
Image($r('app.media.ic_download3')).width(20).height(20)
|
||||
Text('保存').fontColor(Color.White).fontSize(15).fontWeight(FontWeight.Medium)
|
||||
}
|
||||
}
|
||||
.height(46)
|
||||
.layoutWeight(1)
|
||||
.backgroundColor($r('app.color.color_466afd'))
|
||||
.onClick(() => {
|
||||
SaveUtils.saveImageVideoToAlbumDialog([this.uri!!])
|
||||
.then((saved) => {
|
||||
if (saved) {
|
||||
this.imageUris = []
|
||||
this.showDownloadDialog()
|
||||
} else {
|
||||
ToastUtils.show('保存失败')
|
||||
}
|
||||
})
|
||||
.catch((e: BusinessError) => {
|
||||
ToastUtils.show('保存失败:' + e.message)
|
||||
})
|
||||
})
|
||||
}
|
||||
.visibility(this.isSuccess ? Visibility.Visible : Visibility.None)
|
||||
}
|
||||
.padding({left: 16, top: 9, right: 16, bottom: 30 })
|
||||
.backgroundColor(Color.White)
|
||||
}
|
||||
.width('100%')
|
||||
.height('100%')
|
||||
.backgroundColor($r('app.color.window_background'))
|
||||
}
|
||||
}
|
||||
|
|
@ -25,7 +25,7 @@ struct MD5ResetPage {
|
|||
modifyMD5() {
|
||||
LoadingDialog.show(this.getUIContext())
|
||||
this.isSuccess = false
|
||||
let outputPath = FileUtil.getCacheDirPath() + FileUtil.separator + `kcsp_${systemDateTime.getTime()}.mp4`
|
||||
let outputPath = FileUtil.getCacheDirPath() + FileUtil.separator + `scmf_${systemDateTime.getTime()}.mp4`
|
||||
if (FileUtil.accessSync(outputPath)) {
|
||||
FileUtil.unlinkSync(outputPath)
|
||||
}
|
||||
|
|
@ -115,38 +115,21 @@ struct MD5ResetPage {
|
|||
Column() {
|
||||
TitleBar({ title: 'MD5去重' })
|
||||
|
||||
Column() {
|
||||
Row() {
|
||||
Text('上传视频').fontColor($r('app.color.color_90ffffff')).fontSize(16).fontWeight(FontWeight.Medium)
|
||||
Text('(仅支持mp4格式)').fontColor($r('app.color.color_50ffffff')).fontSize(12)
|
||||
}.alignSelf(ItemAlign.Start)
|
||||
|
||||
RelativeContainer() {
|
||||
Stack() {
|
||||
Image($r('app.media.ic_add_video')).width(44).height(44)
|
||||
Stack() {
|
||||
Stack() {
|
||||
Column() {
|
||||
Image($r('app.media.ic_add_video')).width(40).height(40)
|
||||
Text('请上传视频').fontColor($r('app.color.color_466afd')).fontSize(15).fontWeight(FontWeight.Medium).margin({ top: 8})
|
||||
}
|
||||
.width(140)
|
||||
.height(140)
|
||||
.borderRadius(10)
|
||||
.backgroundColor($r('app.color.color_333333'))
|
||||
.alignRules({
|
||||
start: { anchor: '__container__', align: HorizontalAlign.Start },
|
||||
top: { anchor: '__container__', align: VerticalAlign.Top },
|
||||
end: { anchor: '__container__', align: HorizontalAlign.End },
|
||||
bottom: { anchor: '__container__', align: VerticalAlign.Bottom }
|
||||
})
|
||||
}
|
||||
.width('100%')
|
||||
.height('100%')
|
||||
.onClick(() => {
|
||||
this.selectVideo()
|
||||
})
|
||||
}
|
||||
.height(220)
|
||||
.margin({ top: 12 })
|
||||
.borderRadius(8)
|
||||
.backgroundColor($r('app.color.color_222222'))
|
||||
}.margin({ left: 16, top: 16, right: 16 })
|
||||
.visibility(this.uri ? Visibility.None : Visibility.Visible)
|
||||
|
||||
Column() {
|
||||
RelativeContainer() {
|
||||
Video({
|
||||
src: this.uri, // 设置视频源
|
||||
|
|
@ -155,7 +138,8 @@ struct MD5ResetPage {
|
|||
})
|
||||
.width('100%')
|
||||
.height('100%')
|
||||
.backgroundColor($r('app.color.window_background'))
|
||||
.borderRadius(20)
|
||||
.backgroundColor(Color.White)
|
||||
.controls(false) // 设置是否显示默认控制条
|
||||
.autoPlay(false) // 设置是否自动播放
|
||||
.loop(false) // 设置是否循环播放
|
||||
|
|
@ -237,28 +221,77 @@ struct MD5ResetPage {
|
|||
}
|
||||
.opacity(0.8)
|
||||
.width("100%")
|
||||
.borderRadius({bottomLeft: 20, bottomRight: 20})
|
||||
.backgroundColor('#1A000000')
|
||||
.padding({ left: 30, right: 30 })
|
||||
.alignRules({
|
||||
bottom: { anchor: '__container__', align: VerticalAlign.Bottom }
|
||||
})
|
||||
}
|
||||
.layoutWeight(1)
|
||||
.width('100%')
|
||||
.height('100%')
|
||||
.visibility(this.uri ? Visibility.Visible : Visibility.None)
|
||||
}
|
||||
.width('100%')
|
||||
.aspectRatio(1)
|
||||
.borderRadius(20)
|
||||
.backgroundColor(Color.White)
|
||||
.shadow({radius: 10, color: '#1a9399a1'})
|
||||
}
|
||||
.width('100%')
|
||||
.height('auto')
|
||||
.padding({left: 32, right: 32})
|
||||
.margin({top: 40})
|
||||
|
||||
Row() {
|
||||
Text(this.isSuccess ? '重新上传' : '取消').fontColor($r('app.color.color_90ffffff')).fontSize(17).margin({ left: 16 })
|
||||
Blank().layoutWeight(1)
|
||||
|
||||
Stack() {
|
||||
Button('确认处理', { type: ButtonType.Capsule, stateEffect: true })
|
||||
.width('100%')
|
||||
.height(46)
|
||||
.fontColor(Color.White)
|
||||
.fontSize(15)
|
||||
.fontWeight(FontWeight.Medium)
|
||||
.backgroundColor($r('app.color.color_466afd'))
|
||||
.onClick(() => {
|
||||
this.controller.stop()
|
||||
if (this.isSuccess) {
|
||||
this.selectVideo()
|
||||
if (this.uri) {
|
||||
this.modifyMD5()
|
||||
} else {
|
||||
this.getUIContext().getRouter().back()
|
||||
ToastUtils.show('请上传视频')
|
||||
}
|
||||
})
|
||||
Blank().layoutWeight(1)
|
||||
Text(this.isSuccess ? '保存' : '确定').fontColor($r("app.color.color_466afd")).fontSize(17).margin({ right: 16 })
|
||||
.visibility(!this.isSuccess ? Visibility.Visible : Visibility.None)
|
||||
|
||||
Row() {
|
||||
Button({ type: ButtonType.Capsule, stateEffect: true }) {
|
||||
Row() {
|
||||
Image($r('app.media.ic_reupload')).width(20).height(20)
|
||||
Text('重新上传').fontColor($r('app.color.color_466afd')).fontSize(15).fontWeight(FontWeight.Medium)
|
||||
}
|
||||
}
|
||||
.height(46)
|
||||
.layoutWeight(1)
|
||||
.borderWidth(1)
|
||||
.borderColor($r('app.color.color_466afd'))
|
||||
.backgroundColor(Color.Transparent)
|
||||
.onClick(() => {
|
||||
this.controller.stop()
|
||||
this.selectVideo()
|
||||
})
|
||||
|
||||
Blank().width(9)
|
||||
|
||||
Button({ type: ButtonType.Capsule, stateEffect: true }) {
|
||||
Row() {
|
||||
Image($r('app.media.ic_download3')).width(20).height(20)
|
||||
Text('保存').fontColor(Color.White).fontSize(15).fontWeight(FontWeight.Medium)
|
||||
}
|
||||
}
|
||||
.height(46)
|
||||
.layoutWeight(1)
|
||||
.backgroundColor($r('app.color.color_466afd'))
|
||||
.onClick(() => {
|
||||
this.controller.stop()
|
||||
if (this.isSuccess) {
|
||||
SaveUtils.saveImageVideoToAlbumDialog([this.uri!!])
|
||||
.then((saved) => {
|
||||
if (saved) {
|
||||
|
|
@ -271,16 +304,12 @@ struct MD5ResetPage {
|
|||
.catch((e: BusinessError) => {
|
||||
ToastUtils.show('保存失败:' + e.message)
|
||||
})
|
||||
|
||||
} else {
|
||||
this.modifyMD5()
|
||||
}
|
||||
})
|
||||
}
|
||||
.margin({ top: 140, bottom: 30 })
|
||||
.visibility(this.isSuccess ? Visibility.Visible : Visibility.None)
|
||||
}
|
||||
.layoutWeight(1)
|
||||
.visibility(this.uri ? Visibility.Visible : Visibility.None)
|
||||
.padding({left: 16, top: 9, right: 16, bottom: 30 })
|
||||
.backgroundColor(Color.White)
|
||||
}
|
||||
.width('100%')
|
||||
.height('100%')
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ struct RemoveAudioPage {
|
|||
@Local isPlaying: boolean = false
|
||||
@Local isSuccess: boolean = false
|
||||
|
||||
mirrorVideo() {
|
||||
removeAudio() {
|
||||
LoadingDialog.show(this.getUIContext())
|
||||
this.isSuccess = false
|
||||
let cachePath = FileUtil.getCacheDirPath() + FileUtil.separator + `cache_${systemDateTime.getTime()}.mp4`
|
||||
|
|
@ -34,7 +34,7 @@ struct RemoveAudioPage {
|
|||
// 复制文件到缓存目录下
|
||||
FileUtil.copyFileSync(file.fd, cachePath)
|
||||
|
||||
let outputPath = FileUtil.getCacheDirPath() + FileUtil.separator + `kcsp_${systemDateTime.getTime()}.mp4`
|
||||
let outputPath = FileUtil.getCacheDirPath() + FileUtil.separator + `scmf_${systemDateTime.getTime()}.mp4`
|
||||
let cmd = `ffmpeg -i ${cachePath} -an -c:v copy ${outputPath}`
|
||||
MP4Parser.ffmpegCmd(cmd, {
|
||||
callBackResult: (code: number) => {
|
||||
|
|
@ -119,40 +119,23 @@ struct RemoveAudioPage {
|
|||
|
||||
build() {
|
||||
Column() {
|
||||
TitleBar({ title: '去音乐' })
|
||||
TitleBar({ title: '视频去原声' })
|
||||
|
||||
Column() {
|
||||
Row() {
|
||||
Text('上传视频').fontColor($r('app.color.color_90ffffff')).fontSize(16).fontWeight(FontWeight.Medium)
|
||||
Text('(仅支持mp4格式)').fontColor($r('app.color.color_50ffffff')).fontSize(12)
|
||||
}.alignSelf(ItemAlign.Start)
|
||||
|
||||
RelativeContainer() {
|
||||
Stack() {
|
||||
Image($r('app.media.ic_add_video')).width(44).height(44)
|
||||
Stack() {
|
||||
Stack() {
|
||||
Column() {
|
||||
Image($r('app.media.ic_add_video')).width(40).height(40)
|
||||
Text('请上传视频').fontColor($r('app.color.color_466afd')).fontSize(15).fontWeight(FontWeight.Medium).margin({ top: 8})
|
||||
}
|
||||
.width(140)
|
||||
.height(140)
|
||||
.borderRadius(10)
|
||||
.backgroundColor($r('app.color.color_333333'))
|
||||
.alignRules({
|
||||
start: { anchor: '__container__', align: HorizontalAlign.Start },
|
||||
top: { anchor: '__container__', align: VerticalAlign.Top },
|
||||
end: { anchor: '__container__', align: HorizontalAlign.End },
|
||||
bottom: { anchor: '__container__', align: VerticalAlign.Bottom }
|
||||
})
|
||||
}
|
||||
.width('100%')
|
||||
.height('100%')
|
||||
.onClick(() => {
|
||||
this.selectVideo()
|
||||
})
|
||||
}
|
||||
.height(220)
|
||||
.margin({ top: 12 })
|
||||
.borderRadius(8)
|
||||
.backgroundColor($r('app.color.color_222222'))
|
||||
}.margin({ left: 16, top: 16, right: 16 })
|
||||
.visibility(this.uri ? Visibility.None : Visibility.Visible)
|
||||
|
||||
Column() {
|
||||
RelativeContainer() {
|
||||
Video({
|
||||
src: this.uri, // 设置视频源
|
||||
|
|
@ -161,7 +144,8 @@ struct RemoveAudioPage {
|
|||
})
|
||||
.width('100%')
|
||||
.height('100%')
|
||||
.backgroundColor($r('app.color.window_background'))
|
||||
.borderRadius(20)
|
||||
.backgroundColor(Color.White)
|
||||
.controls(false) // 设置是否显示默认控制条
|
||||
.autoPlay(false) // 设置是否自动播放
|
||||
.loop(false) // 设置是否循环播放
|
||||
|
|
@ -243,28 +227,77 @@ struct RemoveAudioPage {
|
|||
}
|
||||
.opacity(0.8)
|
||||
.width("100%")
|
||||
.borderRadius({bottomLeft: 20, bottomRight: 20})
|
||||
.backgroundColor('#1A000000')
|
||||
.padding({ left: 30, right: 30 })
|
||||
.alignRules({
|
||||
bottom: { anchor: '__container__', align: VerticalAlign.Bottom }
|
||||
})
|
||||
}
|
||||
.layoutWeight(1)
|
||||
.width('100%')
|
||||
.height('100%')
|
||||
.visibility(this.uri ? Visibility.Visible : Visibility.None)
|
||||
}
|
||||
.width('100%')
|
||||
.aspectRatio(1)
|
||||
.borderRadius(20)
|
||||
.backgroundColor(Color.White)
|
||||
.shadow({radius: 10, color: '#1a9399a1'})
|
||||
}
|
||||
.width('100%')
|
||||
.height('auto')
|
||||
.padding({left: 32, right: 32})
|
||||
.margin({top: 40})
|
||||
|
||||
Row() {
|
||||
Text(this.isSuccess ? '重新上传' : '取消').fontColor($r('app.color.color_90ffffff')).fontSize(17).margin({ left: 16 })
|
||||
Blank().layoutWeight(1)
|
||||
|
||||
Stack() {
|
||||
Button('确认处理', { type: ButtonType.Capsule, stateEffect: true })
|
||||
.width('100%')
|
||||
.height(46)
|
||||
.fontColor(Color.White)
|
||||
.fontSize(15)
|
||||
.fontWeight(FontWeight.Medium)
|
||||
.backgroundColor($r('app.color.color_466afd'))
|
||||
.onClick(() => {
|
||||
this.controller.stop()
|
||||
if (this.isSuccess) {
|
||||
this.selectVideo()
|
||||
if (this.uri) {
|
||||
this.removeAudio()
|
||||
} else {
|
||||
this.getUIContext().getRouter().back()
|
||||
ToastUtils.show('请上传视频')
|
||||
}
|
||||
})
|
||||
Blank().layoutWeight(1)
|
||||
Text(this.isSuccess ? '保存' : '确定').fontColor($r("app.color.color_466afd")).fontSize(17).margin({ right: 16 })
|
||||
.visibility(!this.isSuccess ? Visibility.Visible : Visibility.None)
|
||||
|
||||
Row() {
|
||||
Button({ type: ButtonType.Capsule, stateEffect: true }) {
|
||||
Row() {
|
||||
Image($r('app.media.ic_reupload')).width(20).height(20)
|
||||
Text('重新上传').fontColor($r('app.color.color_466afd')).fontSize(15).fontWeight(FontWeight.Medium)
|
||||
}
|
||||
}
|
||||
.height(46)
|
||||
.layoutWeight(1)
|
||||
.borderWidth(1)
|
||||
.borderColor($r('app.color.color_466afd'))
|
||||
.backgroundColor(Color.Transparent)
|
||||
.onClick(() => {
|
||||
this.controller.stop()
|
||||
this.selectVideo()
|
||||
})
|
||||
|
||||
Blank().width(9)
|
||||
|
||||
Button({ type: ButtonType.Capsule, stateEffect: true }) {
|
||||
Row() {
|
||||
Image($r('app.media.ic_download3')).width(20).height(20)
|
||||
Text('保存').fontColor(Color.White).fontSize(15).fontWeight(FontWeight.Medium)
|
||||
}
|
||||
}
|
||||
.height(46)
|
||||
.layoutWeight(1)
|
||||
.backgroundColor($r('app.color.color_466afd'))
|
||||
.onClick(() => {
|
||||
this.controller.stop()
|
||||
if (this.isSuccess) {
|
||||
SaveUtils.saveImageVideoToAlbumDialog([this.uri!!])
|
||||
.then((saved) => {
|
||||
if (saved) {
|
||||
|
|
@ -277,16 +310,12 @@ struct RemoveAudioPage {
|
|||
.catch((e: BusinessError) => {
|
||||
ToastUtils.show('保存失败:' + e.message)
|
||||
})
|
||||
|
||||
} else {
|
||||
this.mirrorVideo()
|
||||
}
|
||||
})
|
||||
}
|
||||
.margin({ top: 140, bottom: 30 })
|
||||
.visibility(this.isSuccess ? Visibility.Visible : Visibility.None)
|
||||
}
|
||||
.layoutWeight(1)
|
||||
.visibility(this.uri ? Visibility.Visible : Visibility.None)
|
||||
.padding({left: 16, top: 9, right: 16, bottom: 30 })
|
||||
.backgroundColor(Color.White)
|
||||
}
|
||||
.width('100%')
|
||||
.height('100%')
|
||||
|
|
|
|||
|
|
@ -0,0 +1,400 @@
|
|||
import { PhotoHelper } from '@pura/picker_utils'
|
||||
import { TitleBar } from '../../../../view/TitleBar'
|
||||
import { photoAccessHelper } from '@kit.MediaLibraryKit'
|
||||
import { BusinessError, systemDateTime } from '@kit.BasicServicesKit'
|
||||
import { AppUtil, DisplayUtil, FileUtil, ImageUtil, StrUtil } from '@pura/harmony-utils'
|
||||
import { ToastUtils } from '../../../../utils/ToastUtils'
|
||||
import { fileIo } from '@kit.CoreFileKit'
|
||||
import { SaveUtils } from '../../../../utils/SaveUtils'
|
||||
import { LoadingDialog } from '../../../../dialog/LoadingDialog'
|
||||
import { DownloadDialog, DownloadStatus } from '../../../../dialog/DownloadDialog'
|
||||
import { EventConstants } from '../../../../common/EventConstants'
|
||||
import { RectPosition } from '../../../../view/RectCropView'
|
||||
import { media } from '@kit.MediaKit'
|
||||
import { MediaUtils } from '../../../../utils/MediaUtils'
|
||||
import { MP4Parser } from '@ohos/mp4parser'
|
||||
import { TipDialog } from '../../../../dialog/TipDialog'
|
||||
import { WaterMarkerView } from '../../../../view/WaterMarkerView'
|
||||
import { EditTextDialog } from '../../../../dialog/EditTextDialog'
|
||||
import { image } from '@kit.ImageKit'
|
||||
import { avSessionManager } from '../../../../manager/AVSessionManager'
|
||||
import { SelectBoundsView } from '../../../../view/SelectBoundsView'
|
||||
|
||||
@Entry
|
||||
@ComponentV2
|
||||
struct RemoveWatermarkPage {
|
||||
@Local uri?: string
|
||||
@Local currentTime: number = 0
|
||||
@Local durationTime: number = 0
|
||||
@Local isPlaying: boolean = false
|
||||
@Local isSuccess: boolean = false
|
||||
@Local playerSize: media.PixelMapParams = { width: 0, height: 0 }
|
||||
|
||||
@Local showBound: boolean = false
|
||||
|
||||
private controller: VideoController = new VideoController()
|
||||
private videoSize: media.PixelMapParams = { width: 0, height: 0 }
|
||||
private rect: RectPosition = { x: 0, y: 0, width: 0, height: 0 }
|
||||
|
||||
addWatermark() {
|
||||
LoadingDialog.show(this.getUIContext())
|
||||
this.isSuccess = false
|
||||
let cacheVideoPath = FileUtil.getCacheDirPath() + FileUtil.separator + `scmf_${systemDateTime.getTime()}.mp4`
|
||||
if (FileUtil.accessSync(cacheVideoPath)) {
|
||||
FileUtil.unlinkSync(cacheVideoPath)
|
||||
}
|
||||
|
||||
let file = FileUtil.openSync(this.uri!!, fileIo.OpenMode.READ_ONLY)
|
||||
// 复制文件到缓存目录下
|
||||
FileUtil.copyFileSync(file.fd, cacheVideoPath)
|
||||
|
||||
let rectX = (vp2px(this.rect.x) * this.videoSize.width!!) / this.playerSize.width!!
|
||||
let rectY = (vp2px(this.rect.y) * this.videoSize.height!!) / this.playerSize.height!!
|
||||
|
||||
let rectWidth = (vp2px(this.rect.width * this.videoSize.width!!) / this.playerSize.width!!)
|
||||
let rectHeight = (vp2px(this.rect.height * this.videoSize.height!!) / this.playerSize.height!!)
|
||||
|
||||
let outputPath = FileUtil.getCacheDirPath() + FileUtil.separator + `scmf_${systemDateTime.getTime()}.mp4`
|
||||
let cmd = `ffmpeg -i ${cacheVideoPath} -filter_complex "[0:v]crop=${Math.round(rectWidth)}:${Math.round(rectHeight)}:${rectX}:${rectY},avgblur=15:15[fg]; [0:v][fg]overlay=${rectX}:${rectY}" -c:v h264 -pix_fmt yuv420p -y ${outputPath}`
|
||||
MP4Parser.ffmpegCmd(cmd, {
|
||||
callBackResult: (code: number) => {
|
||||
if (code === 0) {
|
||||
this.uri = FileUtil.getUriFromPath(outputPath)
|
||||
this.isSuccess = true
|
||||
this.isPlaying = false
|
||||
ToastUtils.show('处理成功')
|
||||
} else {
|
||||
ToastUtils.show('处理失败')
|
||||
}
|
||||
LoadingDialog.dismiss()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
selectVideo() {
|
||||
PhotoHelper.selectEasy({
|
||||
MIMEType: photoAccessHelper.PhotoViewMIMETypes.VIDEO_TYPE,
|
||||
maxSelectNumber: 1,
|
||||
isPhotoTakingSupported: false,
|
||||
isEditSupported: false,
|
||||
isOriginalSupported: false
|
||||
})
|
||||
.then((uris) => {
|
||||
if (uris.length != 0) {
|
||||
this.isSuccess = false
|
||||
this.uri = uris[0]
|
||||
this.showBound = false
|
||||
MediaUtils.getVideoSize(this.uri)
|
||||
.then((size) => {
|
||||
this.videoSize = size
|
||||
if (size.width && size.height) {
|
||||
const ratio = (DisplayUtil.getWidth() - 300) / size.width
|
||||
this.playerSize = {width: Math.ceil(size.width * ratio), height: Math.ceil(size.height * ratio)}
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
showDownloadDialog() {
|
||||
DownloadDialog.show(this.getUIContext(), {
|
||||
status: DownloadStatus.COMPLETED,
|
||||
totalSize: 0,
|
||||
progress: 0,
|
||||
totalCount: 1,
|
||||
index: 0,
|
||||
callback: {
|
||||
confirm: () => {
|
||||
AppUtil.getContext().eventHub.emit(EventConstants.JumpToRecordEvent, 0)
|
||||
this.getUIContext().getRouter().back()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
formatTime(time: number): string {
|
||||
let minute: number = 0
|
||||
let second: number = 0
|
||||
if (time > 60) {
|
||||
minute = Math.trunc(time / 60)
|
||||
second = time % 60
|
||||
if (minute < 10) {
|
||||
if (second < 10) {
|
||||
return `0${minute}:0${second}`
|
||||
} else {
|
||||
return `0${minute}:${second}`
|
||||
}
|
||||
} else {
|
||||
if (second < 10) {
|
||||
return `${minute}:0${second}`
|
||||
} else {
|
||||
return `${minute}:${second}`
|
||||
}
|
||||
}
|
||||
} else {
|
||||
second = time
|
||||
if (second < 10) {
|
||||
return `00:0${second}`
|
||||
} else {
|
||||
return `00:${second}`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onBackPress(): boolean | void {
|
||||
if (this.isSuccess) {
|
||||
TipDialog.show(this.getUIContext(), {title:'温馨提示', content:'视频尚未保存,是否确定退出?', callback: {
|
||||
confirm: () => {
|
||||
this.getUIContext().getRouter().back()
|
||||
}
|
||||
}})
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
build() {
|
||||
Column() {
|
||||
TitleBar({ title: '视频去水印' })
|
||||
|
||||
Stack() {
|
||||
Stack() {
|
||||
Column() {
|
||||
Image($r('app.media.ic_add_video')).width(40).height(40)
|
||||
Text('请上传视频').fontColor($r('app.color.color_466afd')).fontSize(15).fontWeight(FontWeight.Medium).margin({ top: 8})
|
||||
}
|
||||
}
|
||||
.width('100%')
|
||||
.aspectRatio(1)
|
||||
.borderRadius(20)
|
||||
.backgroundColor(Color.White)
|
||||
.shadow({radius: 10, color: '#1a9399a1'})
|
||||
.onClick(() => {
|
||||
this.selectVideo()
|
||||
})
|
||||
}
|
||||
.width('100%')
|
||||
.height('auto')
|
||||
.padding({left: 32, right: 32})
|
||||
.margin({top: 40})
|
||||
.visibility(this.uri ? Visibility.None : Visibility.Visible)
|
||||
|
||||
Column() {
|
||||
RelativeContainer() {
|
||||
Video({
|
||||
src: this.uri, // 设置视频源
|
||||
controller: this.controller, //设置视频控制器,可以控制视频的播放状态
|
||||
posterOptions: { showFirstFrame: true }
|
||||
})
|
||||
.id('video')
|
||||
.width(this.playerSize ? px2vp(this.playerSize.width) : '100%')
|
||||
.height(this.playerSize ? px2vp(this.playerSize.height) : '100%')
|
||||
.backgroundColor($r('app.color.window_background'))
|
||||
.controls(false) // 设置是否显示默认控制条
|
||||
.autoPlay(false) // 设置是否自动播放
|
||||
.loop(false) // 设置是否循环播放
|
||||
.objectFit(ImageFit.Cover) // 设置视频填充模式
|
||||
.alignRules({
|
||||
left: { anchor: '__container__', align: HorizontalAlign.Start },
|
||||
top: { anchor: '__container__', align: VerticalAlign.Top },
|
||||
right: { anchor: '__container__', align: HorizontalAlign.End },
|
||||
bottom: { anchor: '__container__', align: VerticalAlign.Bottom }
|
||||
})
|
||||
.onPrepared((event) => {
|
||||
if (event) {
|
||||
this.durationTime = event.duration
|
||||
}
|
||||
})
|
||||
.onUpdate((event) => {
|
||||
if (event) {
|
||||
this.currentTime = event.time
|
||||
}
|
||||
})
|
||||
.onStart(() => {
|
||||
this.isPlaying = true
|
||||
})
|
||||
.onPause(() => {
|
||||
this.isPlaying = false
|
||||
avSessionManager.deactivate()
|
||||
})
|
||||
.onStop(() => {
|
||||
this.isPlaying = false
|
||||
avSessionManager.deactivate()
|
||||
})
|
||||
.onFinish(() => {
|
||||
this.isPlaying = false
|
||||
avSessionManager.deactivate()
|
||||
})
|
||||
.onError(() => {
|
||||
this.isPlaying = false
|
||||
avSessionManager.deactivate()
|
||||
})
|
||||
.onDisAppear(() => {
|
||||
avSessionManager.deactivate()
|
||||
})
|
||||
|
||||
Image($r('app.media.ic_play_video'))
|
||||
.width(50)
|
||||
.height(50)
|
||||
.visibility(this.isPlaying ? Visibility.None : Visibility.Visible)
|
||||
.onClick(async () => {
|
||||
await avSessionManager.activate()
|
||||
this.controller.start()
|
||||
})
|
||||
.alignRules({
|
||||
left: { anchor: 'video', align: HorizontalAlign.Start },
|
||||
top: { anchor: 'video', align: VerticalAlign.Top },
|
||||
right: { anchor: 'video', align: HorizontalAlign.End },
|
||||
bottom: { anchor: 'video', align: VerticalAlign.Bottom }
|
||||
})
|
||||
|
||||
Row() {
|
||||
Image(this.isPlaying ? $r('app.media.ic_player_controls_pause') : $r('app.media.ic_player_controls_play'))
|
||||
.width(20)
|
||||
.height(20)
|
||||
.margin({ right: 20 })
|
||||
.onClick(async () => {
|
||||
if (this.isPlaying) {
|
||||
this.controller.pause()
|
||||
} else {
|
||||
await avSessionManager.activate()
|
||||
this.controller.start()
|
||||
}
|
||||
})
|
||||
Text(this.formatTime(this.currentTime)).width(35).fontColor(Color.White).fontSize(12)
|
||||
Slider({
|
||||
value: this.currentTime,
|
||||
min: 0,
|
||||
max: this.durationTime
|
||||
})
|
||||
.blockColor(Color.White)
|
||||
.trackColor($r('app.color.color_60ffffff'))
|
||||
.onChange((value: number, mode: SliderChangeMode) => {
|
||||
this.controller.setCurrentTime(value); // 设置视频播放的进度跳转到value处
|
||||
})
|
||||
.layoutWeight(1)
|
||||
Text(this.formatTime(this.durationTime)).width(35).fontColor(Color.White).fontSize(12)
|
||||
}
|
||||
.opacity(0.8)
|
||||
.width(this.playerSize ? px2vp(this.playerSize.width) : "100%")
|
||||
.alignRules({
|
||||
left: { anchor: 'video', align: HorizontalAlign.Start },
|
||||
right: { anchor: 'video', align: HorizontalAlign.End },
|
||||
bottom: { anchor: 'video', align: VerticalAlign.Bottom }
|
||||
})
|
||||
|
||||
if (this.showBound && this.uri && !this.isSuccess) {
|
||||
SelectBoundsView({
|
||||
onRectChange: (rect) => {
|
||||
this.rect = rect
|
||||
},
|
||||
onClose: () => {
|
||||
this.showBound = false
|
||||
}
|
||||
})
|
||||
.width(this.playerSize ? px2vp(this.playerSize.width) : '100%')
|
||||
.height(this.playerSize ? px2vp(this.playerSize.height) : '100%')
|
||||
.alignRules({
|
||||
left: { anchor: 'video', align: HorizontalAlign.Start },
|
||||
top: { anchor: 'video', align: VerticalAlign.Top },
|
||||
right: { anchor: 'video', align: HorizontalAlign.End },
|
||||
bottom: { anchor: 'video', align: VerticalAlign.Bottom }
|
||||
})
|
||||
}
|
||||
}
|
||||
.layoutWeight(1)
|
||||
|
||||
Stack() {
|
||||
Column(){
|
||||
Image($r('app.media.ic_remove_watermark')).width(26).height(26)
|
||||
Text('马赛克').fontColor($r('app.color.color_212226')).fontSize(12).margin({ top: 8 })
|
||||
}
|
||||
.onClick(() => {
|
||||
if (!this.showBound) {
|
||||
this.controller.stop()
|
||||
this.showBound = true
|
||||
}
|
||||
})
|
||||
}
|
||||
.width(82)
|
||||
.height(82)
|
||||
.margin({ top: 20, bottom: 20 })
|
||||
.borderRadius(10)
|
||||
.backgroundColor(Color.White)
|
||||
}
|
||||
.layoutWeight(1)
|
||||
.visibility(this.uri ? Visibility.Visible : Visibility.None)
|
||||
|
||||
Blank().layoutWeight(1).visibility(this.uri ? Visibility.None : Visibility.Visible)
|
||||
|
||||
Stack() {
|
||||
Button('确认处理', { type: ButtonType.Capsule, stateEffect: true })
|
||||
.width('100%')
|
||||
.height(46)
|
||||
.fontColor(Color.White)
|
||||
.fontSize(15)
|
||||
.fontWeight(FontWeight.Medium)
|
||||
.backgroundColor($r('app.color.color_466afd'))
|
||||
.onClick(() => {
|
||||
if (this.uri) {
|
||||
this.addWatermark()
|
||||
} else {
|
||||
ToastUtils.show('请上传视频')
|
||||
}
|
||||
})
|
||||
.visibility(!this.isSuccess ? Visibility.Visible : Visibility.None)
|
||||
|
||||
Row() {
|
||||
Button({ type: ButtonType.Capsule, stateEffect: true }) {
|
||||
Row() {
|
||||
Image($r('app.media.ic_reupload')).width(20).height(20)
|
||||
Text('重新上传').fontColor($r('app.color.color_466afd')).fontSize(15).fontWeight(FontWeight.Medium)
|
||||
}
|
||||
}
|
||||
.height(46)
|
||||
.layoutWeight(1)
|
||||
.borderWidth(1)
|
||||
.borderColor($r('app.color.color_466afd'))
|
||||
.backgroundColor(Color.Transparent)
|
||||
.onClick(() => {
|
||||
this.controller.stop()
|
||||
this.selectVideo()
|
||||
})
|
||||
|
||||
Blank().width(9)
|
||||
|
||||
Button({ type: ButtonType.Capsule, stateEffect: true }) {
|
||||
Row() {
|
||||
Image($r('app.media.ic_download3')).width(20).height(20)
|
||||
Text('保存').fontColor(Color.White).fontSize(15).fontWeight(FontWeight.Medium)
|
||||
}
|
||||
}
|
||||
.height(46)
|
||||
.layoutWeight(1)
|
||||
.backgroundColor($r('app.color.color_466afd'))
|
||||
.onClick(() => {
|
||||
this.controller.stop()
|
||||
SaveUtils.saveImageVideoToAlbumDialog([this.uri!!])
|
||||
.then((saved) => {
|
||||
if (saved) {
|
||||
this.uri = undefined
|
||||
this.showDownloadDialog()
|
||||
} else {
|
||||
ToastUtils.show('保存失败')
|
||||
}
|
||||
})
|
||||
.catch((e: BusinessError) => {
|
||||
ToastUtils.show('保存失败:' + e.message)
|
||||
})
|
||||
})
|
||||
}
|
||||
.visibility(this.isSuccess ? Visibility.Visible : Visibility.None)
|
||||
}
|
||||
.padding({left: 16, top: 9, right: 16, bottom: 30 })
|
||||
.backgroundColor(Color.White)
|
||||
}
|
||||
.width('100%')
|
||||
.height('100%')
|
||||
.backgroundColor($r('app.color.window_background'))
|
||||
}
|
||||
}
|
||||
|
|
@ -1,287 +0,0 @@
|
|||
import { PhotoHelper } from '@pura/picker_utils'
|
||||
import { TitleBar } from '../../../../view/TitleBar'
|
||||
import { photoAccessHelper } from '@kit.MediaLibraryKit'
|
||||
import { BusinessError, systemDateTime } from '@kit.BasicServicesKit'
|
||||
import { AppUtil, FileUtil } from '@pura/harmony-utils'
|
||||
import { ToastUtils } from '../../../../utils/ToastUtils'
|
||||
import { fileIo } from '@kit.CoreFileKit'
|
||||
import { SaveUtils } from '../../../../utils/SaveUtils'
|
||||
import { MP4Parser } from '@ohos/mp4parser'
|
||||
import { LoadingDialog } from '../../../../dialog/LoadingDialog'
|
||||
import { DownloadDialog, DownloadStatus } from '../../../../dialog/DownloadDialog'
|
||||
import { EventConstants } from '../../../../common/EventConstants'
|
||||
import { avSessionManager } from '../../../../manager/AVSessionManager'
|
||||
|
||||
@Entry
|
||||
@ComponentV2
|
||||
struct TakeAudioPage {
|
||||
private controller: VideoController = new VideoController()
|
||||
@Local uri?: string
|
||||
@Local currentTime: number = 0
|
||||
@Local durationTime: number = 0
|
||||
@Local isPlaying: boolean = false
|
||||
@Local isSuccess: boolean = false
|
||||
|
||||
takeAudio() {
|
||||
LoadingDialog.show(this.getUIContext())
|
||||
this.isSuccess = false
|
||||
let cachePath = FileUtil.getCacheDirPath() + FileUtil.separator + `cache_${systemDateTime.getTime()}.mp4`
|
||||
if (FileUtil.accessSync(cachePath)) {
|
||||
FileUtil.unlinkSync(cachePath)
|
||||
}
|
||||
let file = FileUtil.openSync(this.uri!!, fileIo.OpenMode.READ_ONLY)
|
||||
// 复制文件到缓存目录下
|
||||
FileUtil.copyFileSync(file.fd, cachePath)
|
||||
|
||||
let outputPath = FileUtil.getCacheDirPath() + FileUtil.separator + `kcsp_${systemDateTime.getTime()}.mp3`
|
||||
let cmd = `ffmpeg -i ${cachePath} -vn -c:a mp3 ${outputPath}`
|
||||
MP4Parser.ffmpegCmd(cmd, {
|
||||
callBackResult: (code: number) => {
|
||||
if (code === 0) {
|
||||
SaveUtils.saveAudioToMusic([outputPath])
|
||||
.then(() => {
|
||||
this.uri = undefined
|
||||
this.isSuccess = true
|
||||
this.isPlaying = false
|
||||
this.showDownloadDialog()
|
||||
})
|
||||
.catch((e: BusinessError) => {
|
||||
ToastUtils.show('提取失败:' + e.message)
|
||||
})
|
||||
} else {
|
||||
ToastUtils.show('提取失败')
|
||||
}
|
||||
LoadingDialog.dismiss()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
selectVideo() {
|
||||
PhotoHelper.selectEasy({
|
||||
MIMEType: photoAccessHelper.PhotoViewMIMETypes.VIDEO_TYPE,
|
||||
maxSelectNumber: 1,
|
||||
isPhotoTakingSupported: false,
|
||||
isEditSupported: false,
|
||||
isOriginalSupported: false
|
||||
})
|
||||
.then((uris) => {
|
||||
if (uris.length != 0) {
|
||||
this.isSuccess = false
|
||||
this.uri = uris[0]
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
showDownloadDialog() {
|
||||
DownloadDialog.show(this.getUIContext(), { status: DownloadStatus.COMPLETED, isAudio: true, totalSize: 0, progress: 0, totalCount: 1, index: 0, callback: {
|
||||
confirm: () => {
|
||||
AppUtil.getContext().eventHub.emit(EventConstants.JumpToRecordEvent, 2)
|
||||
this.getUIContext().getRouter().back()
|
||||
}
|
||||
} })
|
||||
}
|
||||
|
||||
formatTime(time: number): string {
|
||||
let minute: number = 0
|
||||
let second: number = 0
|
||||
if (time > 60) {
|
||||
minute = Math.trunc(time / 60)
|
||||
second = time % 60
|
||||
if (minute < 10) {
|
||||
if (second < 10) {
|
||||
return `0${minute}:0${second}`
|
||||
} else {
|
||||
return `0${minute}:${second}`
|
||||
}
|
||||
} else {
|
||||
if (second < 10) {
|
||||
return `${minute}:0${second}`
|
||||
} else {
|
||||
return `${minute}:${second}`
|
||||
}
|
||||
}
|
||||
} else {
|
||||
second = time
|
||||
if (second < 10) {
|
||||
return `00:0${second}`
|
||||
} else {
|
||||
return `00:${second}`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
build() {
|
||||
Column() {
|
||||
TitleBar({ title: '视频转音频' })
|
||||
|
||||
Column() {
|
||||
Row() {
|
||||
Text('上传视频').fontColor($r('app.color.color_90ffffff')).fontSize(16).fontWeight(FontWeight.Medium)
|
||||
Text('(仅支持mp4格式)').fontColor($r('app.color.color_50ffffff')).fontSize(12)
|
||||
}.alignSelf(ItemAlign.Start)
|
||||
|
||||
RelativeContainer() {
|
||||
Stack() {
|
||||
Stack() {
|
||||
Image($r('app.media.ic_add_video')).width(44).height(44)
|
||||
}
|
||||
.width(140)
|
||||
.height(140)
|
||||
.borderRadius(10)
|
||||
.backgroundColor($r('app.color.color_333333'))
|
||||
.margin({top: 40})
|
||||
.onClick(() => {
|
||||
this.selectVideo()
|
||||
})
|
||||
.visibility(this.uri ? Visibility.None : Visibility.Visible)
|
||||
|
||||
RelativeContainer() {
|
||||
Video({
|
||||
src: this.uri, // 设置视频源
|
||||
controller: this.controller, //设置视频控制器,可以控制视频的播放状态
|
||||
posterOptions: { showFirstFrame: true }
|
||||
})
|
||||
.width('100%')
|
||||
.height('100%')
|
||||
.borderRadius(12)
|
||||
.backgroundColor($r('app.color.window_background'))
|
||||
.controls(false) // 设置是否显示默认控制条
|
||||
.autoPlay(false) // 设置是否自动播放
|
||||
.loop(false) // 设置是否循环播放
|
||||
.objectFit(ImageFit.Contain) // 设置视频填充模式
|
||||
.onPrepared((event) => {
|
||||
if (event) {
|
||||
this.durationTime = event.duration
|
||||
}
|
||||
})
|
||||
.onUpdate((event) => {
|
||||
if (event) {
|
||||
this.currentTime = event.time
|
||||
}
|
||||
})
|
||||
.onStart(() => {
|
||||
this.isPlaying = true
|
||||
})
|
||||
.onPause(() => {
|
||||
this.isPlaying = false
|
||||
avSessionManager.deactivate()
|
||||
})
|
||||
.onStop(() => {
|
||||
this.isPlaying = false
|
||||
avSessionManager.deactivate()
|
||||
})
|
||||
.onFinish(() => {
|
||||
this.isPlaying = false
|
||||
avSessionManager.deactivate()
|
||||
})
|
||||
.onError(() => {
|
||||
this.isPlaying = false
|
||||
avSessionManager.deactivate()
|
||||
})
|
||||
.onDisAppear(() => {
|
||||
avSessionManager.deactivate()
|
||||
})
|
||||
|
||||
Image($r('app.media.ic_play_video'))
|
||||
.width(50)
|
||||
.height(50)
|
||||
.visibility(this.isPlaying ? Visibility.None : Visibility.Visible)
|
||||
.onClick(async () => {
|
||||
await avSessionManager.activate()
|
||||
this.controller.start()
|
||||
})
|
||||
.alignRules({
|
||||
left: { anchor: '__container__', align: HorizontalAlign.Start },
|
||||
top: { anchor: '__container__', align: VerticalAlign.Top },
|
||||
right: { anchor: '__container__', align: HorizontalAlign.End },
|
||||
bottom: { anchor: '__container__', align: VerticalAlign.Bottom },
|
||||
})
|
||||
|
||||
Row() {
|
||||
Image(this.isPlaying ? $r('app.media.ic_player_controls_pause') : $r('app.media.ic_player_controls_play'))
|
||||
.width(20)
|
||||
.height(20)
|
||||
.margin({ right: 20 })
|
||||
.onClick(async () => {
|
||||
if (this.isPlaying) {
|
||||
this.controller.pause()
|
||||
} else {
|
||||
await avSessionManager.activate()
|
||||
this.controller.start()
|
||||
}
|
||||
})
|
||||
Text(this.formatTime(this.currentTime)).width(35).fontColor(Color.White).fontSize(12)
|
||||
Slider({
|
||||
value: this.currentTime,
|
||||
min: 0,
|
||||
max: this.durationTime
|
||||
})
|
||||
.blockColor(Color.White)
|
||||
.trackColor($r('app.color.color_60ffffff'))
|
||||
.onChange((value: number, mode: SliderChangeMode) => {
|
||||
this.controller.setCurrentTime(value); // 设置视频播放的进度跳转到value处
|
||||
})
|
||||
.layoutWeight(1)
|
||||
Text(this.formatTime(this.durationTime)).width(35).fontColor(Color.White).fontSize(12)
|
||||
}
|
||||
.opacity(0.8)
|
||||
.width("100%")
|
||||
.padding({ left: 20, right: 20 })
|
||||
.alignRules({
|
||||
bottom: { anchor: '__container__', align: VerticalAlign.Bottom }
|
||||
})
|
||||
}
|
||||
.height(350)
|
||||
.margin({top: 50})
|
||||
.visibility(this.uri ? Visibility.Visible : Visibility.None)
|
||||
}
|
||||
.alignRules({
|
||||
start: { anchor: '__container__', align: HorizontalAlign.Start },
|
||||
end: { anchor: '__container__', align: HorizontalAlign.End }
|
||||
})
|
||||
.id('layout_content')
|
||||
|
||||
Image($r('app.media.ic_reupload_video')).width(20).height(20)
|
||||
.alignRules({
|
||||
right: {anchor: '__container__', align: HorizontalAlign.End}
|
||||
})
|
||||
.margin({top: 20})
|
||||
.onClick(() => {
|
||||
this.controller.stop()
|
||||
this.selectVideo()
|
||||
})
|
||||
.visibility(this.uri ? Visibility.Visible : Visibility.None)
|
||||
|
||||
Button('确认提取', {type: ButtonType.Capsule ,stateEffect:true})
|
||||
.width('100%')
|
||||
.height(42)
|
||||
.fontColor($r('app.color.color_90ffffff'))
|
||||
.fontSize(16)
|
||||
.linearGradient({
|
||||
colors: [['#F62C6C', 0.0], ['#FC4F54', 1.0]],
|
||||
direction: GradientDirection.Right
|
||||
})
|
||||
.alignRules({
|
||||
top: {anchor: 'layout_content', align: VerticalAlign.Bottom}
|
||||
})
|
||||
.margin({top: 40})
|
||||
.onClick(() => {
|
||||
if (this.uri) {
|
||||
this.takeAudio()
|
||||
} else {
|
||||
ToastUtils.show('请先上传视频')
|
||||
}
|
||||
})
|
||||
}
|
||||
.height('auto')
|
||||
.margin({ top: 12 })
|
||||
.borderRadius(8)
|
||||
.backgroundColor($r('app.color.color_222222'))
|
||||
.padding({left: 20, right: 20, bottom: 30})
|
||||
}.margin({ left: 16, top: 16, right: 16 })
|
||||
}
|
||||
.width('100%')
|
||||
.height('100%')
|
||||
.backgroundColor($r('app.color.window_background'))
|
||||
}
|
||||
}
|
||||
|
|
@ -28,7 +28,7 @@ struct VideoMirrorPage {
|
|||
mirrorVideo() {
|
||||
LoadingDialog.show(this.getUIContext())
|
||||
this.isSuccess = false
|
||||
let cacheVideoPath = FileUtil.getCacheDirPath() + FileUtil.separator + `kcsp_${systemDateTime.getTime()}.mp4`
|
||||
let cacheVideoPath = FileUtil.getCacheDirPath() + FileUtil.separator + `scmf_${systemDateTime.getTime()}.mp4`
|
||||
if (FileUtil.accessSync(cacheVideoPath)) {
|
||||
FileUtil.unlinkSync(cacheVideoPath)
|
||||
}
|
||||
|
|
@ -37,7 +37,7 @@ struct VideoMirrorPage {
|
|||
// 复制文件到缓存目录下
|
||||
FileUtil.copyFileSync(file.fd, cacheVideoPath)
|
||||
|
||||
let outputPath = FileUtil.getCacheDirPath() + FileUtil.separator + `kcsp_${systemDateTime.getTime()}.mp4`
|
||||
let outputPath = FileUtil.getCacheDirPath() + FileUtil.separator + `scmf_${systemDateTime.getTime()}.mp4`
|
||||
let cmd = `ffmpeg -i ${cacheVideoPath} -vf ${this.orientation === 1 ? "hflip" : "vflip"} -c:v h264 -pix_fmt yuv420p -y ${outputPath}`
|
||||
MP4Parser.ffmpegCmd(cmd, {
|
||||
callBackResult: (code: number) => {
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ struct VideoReversePage {
|
|||
videoReverse() {
|
||||
LoadingDialog.show(this.getUIContext())
|
||||
this.isSuccess = false
|
||||
let cacheVideoPath = FileUtil.getCacheDirPath() + FileUtil.separator + `kcsp_${systemDateTime.getTime()}.mp4`
|
||||
let cacheVideoPath = FileUtil.getCacheDirPath() + FileUtil.separator + `scmf_${systemDateTime.getTime()}.mp4`
|
||||
if (FileUtil.accessSync(cacheVideoPath)) {
|
||||
FileUtil.unlinkSync(cacheVideoPath)
|
||||
}
|
||||
|
|
@ -35,7 +35,7 @@ struct VideoReversePage {
|
|||
// 复制文件到缓存目录下
|
||||
FileUtil.copyFileSync(file.fd, cacheVideoPath)
|
||||
|
||||
let outputPath = FileUtil.getCacheDirPath() + FileUtil.separator + `kcsp_${systemDateTime.getTime()}.mp4`
|
||||
let outputPath = FileUtil.getCacheDirPath() + FileUtil.separator + `scmf_${systemDateTime.getTime()}.mp4`
|
||||
let cmd = `ffmpeg -i ${cacheVideoPath} -vf reverse -af areverse -c:v h264 -pix_fmt yuv420p -y ${outputPath}`
|
||||
MP4Parser.ffmpegCmd(cmd, {
|
||||
callBackResult: (code: number) => {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,313 @@
|
|||
import { PhotoHelper } from '@pura/picker_utils'
|
||||
import { TitleBar } from '../../../../view/TitleBar'
|
||||
import { photoAccessHelper } from '@kit.MediaLibraryKit'
|
||||
import { BusinessError, systemDateTime } from '@kit.BasicServicesKit'
|
||||
import { AppUtil, FileUtil } from '@pura/harmony-utils'
|
||||
import { ToastUtils } from '../../../../utils/ToastUtils'
|
||||
import { fileIo } from '@kit.CoreFileKit'
|
||||
import { SaveUtils } from '../../../../utils/SaveUtils'
|
||||
import { MP4Parser } from '@ohos/mp4parser'
|
||||
import { LoadingDialog } from '../../../../dialog/LoadingDialog'
|
||||
import { DownloadDialog, DownloadStatus } from '../../../../dialog/DownloadDialog'
|
||||
import { EventConstants } from '../../../../common/EventConstants'
|
||||
import { avSessionManager } from '../../../../manager/AVSessionManager'
|
||||
|
||||
@Entry
|
||||
@ComponentV2
|
||||
struct VideoToAudioPage {
|
||||
private controller: VideoController = new VideoController()
|
||||
@Local videoUri?: string
|
||||
@Local currentTime: number = 0
|
||||
@Local durationTime: number = 0
|
||||
@Local isPlaying: boolean = false
|
||||
@Local isSuccess: boolean = false
|
||||
@Local audioUri?: string
|
||||
|
||||
videoToAudio() {
|
||||
LoadingDialog.show(this.getUIContext())
|
||||
this.isSuccess = false
|
||||
let cachePath = FileUtil.getCacheDirPath() + FileUtil.separator + `cache_${systemDateTime.getTime()}.mp4`
|
||||
if (FileUtil.accessSync(cachePath)) {
|
||||
FileUtil.unlinkSync(cachePath)
|
||||
}
|
||||
let file = FileUtil.openSync(this.videoUri!!, fileIo.OpenMode.READ_ONLY)
|
||||
// 复制文件到缓存目录下
|
||||
FileUtil.copyFileSync(file.fd, cachePath)
|
||||
|
||||
let outputPath = FileUtil.getCacheDirPath() + FileUtil.separator + `scmf_${systemDateTime.getTime()}.mp3`
|
||||
let cmd = `ffmpeg -i ${cachePath} -vn -c:a mp3 ${outputPath}`
|
||||
MP4Parser.ffmpegCmd(cmd, {
|
||||
callBackResult: (code: number) => {
|
||||
if (code === 0) {
|
||||
this.audioUri = outputPath
|
||||
this.isSuccess = true
|
||||
this.isPlaying = false
|
||||
ToastUtils.show('处理成功')
|
||||
} else {
|
||||
ToastUtils.show('处理失败')
|
||||
}
|
||||
LoadingDialog.dismiss()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
selectVideo() {
|
||||
PhotoHelper.selectEasy({
|
||||
MIMEType: photoAccessHelper.PhotoViewMIMETypes.VIDEO_TYPE,
|
||||
maxSelectNumber: 1,
|
||||
isPhotoTakingSupported: false,
|
||||
isEditSupported: false,
|
||||
isOriginalSupported: false
|
||||
})
|
||||
.then((uris) => {
|
||||
if (uris.length != 0) {
|
||||
this.isSuccess = false
|
||||
this.videoUri = uris[0]
|
||||
this.audioUri = undefined
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
showDownloadDialog() {
|
||||
DownloadDialog.show(this.getUIContext(), { status: DownloadStatus.COMPLETED, isAudio: true, totalSize: 0, progress: 0, totalCount: 1, index: 0, callback: {
|
||||
confirm: () => {
|
||||
AppUtil.getContext().eventHub.emit(EventConstants.JumpToRecordEvent, 2)
|
||||
this.getUIContext().getRouter().back()
|
||||
}
|
||||
} })
|
||||
}
|
||||
|
||||
formatTime(time: number): string {
|
||||
let minute: number = 0
|
||||
let second: number = 0
|
||||
if (time > 60) {
|
||||
minute = Math.trunc(time / 60)
|
||||
second = time % 60
|
||||
if (minute < 10) {
|
||||
if (second < 10) {
|
||||
return `0${minute}:0${second}`
|
||||
} else {
|
||||
return `0${minute}:${second}`
|
||||
}
|
||||
} else {
|
||||
if (second < 10) {
|
||||
return `${minute}:0${second}`
|
||||
} else {
|
||||
return `${minute}:${second}`
|
||||
}
|
||||
}
|
||||
} else {
|
||||
second = time
|
||||
if (second < 10) {
|
||||
return `00:0${second}`
|
||||
} else {
|
||||
return `00:${second}`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
build() {
|
||||
Column() {
|
||||
TitleBar({ title: '视频转音频' })
|
||||
|
||||
Stack() {
|
||||
Stack() {
|
||||
Stack() {
|
||||
Column() {
|
||||
Image($r('app.media.ic_add_video')).width(40).height(40)
|
||||
Text('请上传视频').fontColor($r('app.color.color_466afd')).fontSize(15).fontWeight(FontWeight.Medium).margin({ top: 8})
|
||||
}
|
||||
}
|
||||
.width('100%')
|
||||
.height('100%')
|
||||
.onClick(() => {
|
||||
this.selectVideo()
|
||||
})
|
||||
.visibility(this.videoUri ? Visibility.None : Visibility.Visible)
|
||||
|
||||
RelativeContainer() {
|
||||
Video({
|
||||
src: this.videoUri, // 设置视频源
|
||||
controller: this.controller, //设置视频控制器,可以控制视频的播放状态
|
||||
posterOptions: { showFirstFrame: true }
|
||||
})
|
||||
.width('100%')
|
||||
.height('100%')
|
||||
.borderRadius(20)
|
||||
.backgroundColor(Color.White)
|
||||
.controls(false) // 设置是否显示默认控制条
|
||||
.autoPlay(false) // 设置是否自动播放
|
||||
.loop(false) // 设置是否循环播放
|
||||
.objectFit(ImageFit.Contain) // 设置视频填充模式
|
||||
.onPrepared((event) => {
|
||||
if (event) {
|
||||
this.durationTime = event.duration
|
||||
}
|
||||
})
|
||||
.onUpdate((event) => {
|
||||
if (event) {
|
||||
this.currentTime = event.time
|
||||
}
|
||||
})
|
||||
.onStart(() => {
|
||||
this.isPlaying = true
|
||||
})
|
||||
.onPause(() => {
|
||||
this.isPlaying = false
|
||||
avSessionManager.deactivate()
|
||||
})
|
||||
.onStop(() => {
|
||||
this.isPlaying = false
|
||||
avSessionManager.deactivate()
|
||||
})
|
||||
.onFinish(() => {
|
||||
this.isPlaying = false
|
||||
avSessionManager.deactivate()
|
||||
})
|
||||
.onError(() => {
|
||||
this.isPlaying = false
|
||||
avSessionManager.deactivate()
|
||||
})
|
||||
.onDisAppear(() => {
|
||||
avSessionManager.deactivate()
|
||||
})
|
||||
|
||||
Image($r('app.media.ic_play_video'))
|
||||
.width(50)
|
||||
.height(50)
|
||||
.visibility(this.isPlaying ? Visibility.None : Visibility.Visible)
|
||||
.onClick(async () => {
|
||||
await avSessionManager.activate()
|
||||
this.controller.start()
|
||||
})
|
||||
.alignRules({
|
||||
left: { anchor: '__container__', align: HorizontalAlign.Start },
|
||||
top: { anchor: '__container__', align: VerticalAlign.Top },
|
||||
right: { anchor: '__container__', align: HorizontalAlign.End },
|
||||
bottom: { anchor: '__container__', align: VerticalAlign.Bottom },
|
||||
})
|
||||
|
||||
Row() {
|
||||
Image(this.isPlaying ? $r('app.media.ic_player_controls_pause') : $r('app.media.ic_player_controls_play'))
|
||||
.width(20)
|
||||
.height(20)
|
||||
.margin({ right: 20 })
|
||||
.onClick(async () => {
|
||||
if (this.isPlaying) {
|
||||
this.controller.pause()
|
||||
} else {
|
||||
await avSessionManager.activate()
|
||||
this.controller.start()
|
||||
}
|
||||
})
|
||||
Text(this.formatTime(this.currentTime)).width(35).fontColor(Color.White).fontSize(12)
|
||||
Slider({
|
||||
value: this.currentTime,
|
||||
min: 0,
|
||||
max: this.durationTime
|
||||
})
|
||||
.blockColor(Color.White)
|
||||
.trackColor($r('app.color.color_60ffffff'))
|
||||
.onChange((value: number, mode: SliderChangeMode) => {
|
||||
this.controller.setCurrentTime(value); // 设置视频播放的进度跳转到value处
|
||||
})
|
||||
.layoutWeight(1)
|
||||
Text(this.formatTime(this.durationTime)).width(35).fontColor(Color.White).fontSize(12)
|
||||
}
|
||||
.opacity(0.8)
|
||||
.width("100%")
|
||||
.borderRadius({bottomLeft: 20, bottomRight: 20})
|
||||
.backgroundColor('#1A000000')
|
||||
.padding({ left: 30, right: 30 })
|
||||
.alignRules({
|
||||
bottom: { anchor: '__container__', align: VerticalAlign.Bottom }
|
||||
})
|
||||
}
|
||||
.width('100%')
|
||||
.height('100%')
|
||||
.visibility(this.videoUri ? Visibility.Visible : Visibility.None)
|
||||
}
|
||||
.width('100%')
|
||||
.aspectRatio(1)
|
||||
.borderRadius(20)
|
||||
.backgroundColor(Color.White)
|
||||
.shadow({radius: 10, color: '#1a9399a1'})
|
||||
}
|
||||
.width('100%')
|
||||
.height('auto')
|
||||
.padding({left: 32, right: 32})
|
||||
.margin({top: 40})
|
||||
|
||||
Blank().layoutWeight(1)
|
||||
|
||||
Stack() {
|
||||
Button('确认处理', { type: ButtonType.Capsule, stateEffect: true })
|
||||
.width('100%')
|
||||
.height(46)
|
||||
.fontColor(Color.White)
|
||||
.fontSize(15)
|
||||
.fontWeight(FontWeight.Medium)
|
||||
.backgroundColor($r('app.color.color_466afd'))
|
||||
.onClick(() => {
|
||||
if (this.videoUri) {
|
||||
this.videoToAudio()
|
||||
} else {
|
||||
ToastUtils.show('请上传视频')
|
||||
}
|
||||
})
|
||||
.visibility(!this.isSuccess ? Visibility.Visible : Visibility.None)
|
||||
|
||||
Row() {
|
||||
Button({ type: ButtonType.Capsule, stateEffect: true }) {
|
||||
Row() {
|
||||
Image($r('app.media.ic_reupload')).width(20).height(20)
|
||||
Text('重新上传').fontColor($r('app.color.color_466afd')).fontSize(15).fontWeight(FontWeight.Medium)
|
||||
}
|
||||
}
|
||||
.height(46)
|
||||
.layoutWeight(1)
|
||||
.borderWidth(1)
|
||||
.borderColor($r('app.color.color_466afd'))
|
||||
.backgroundColor(Color.Transparent)
|
||||
.onClick(() => {
|
||||
this.controller.stop()
|
||||
this.selectVideo()
|
||||
})
|
||||
|
||||
Blank().width(9)
|
||||
|
||||
Button({ type: ButtonType.Capsule, stateEffect: true }) {
|
||||
Row() {
|
||||
Image($r('app.media.ic_download3')).width(20).height(20)
|
||||
Text('保存').fontColor(Color.White).fontSize(15).fontWeight(FontWeight.Medium)
|
||||
}
|
||||
}
|
||||
.height(46)
|
||||
.layoutWeight(1)
|
||||
.backgroundColor($r('app.color.color_466afd'))
|
||||
.onClick(() => {
|
||||
this.controller.stop()
|
||||
SaveUtils.saveAudioToMusic([this.audioUri!!])
|
||||
.then((saved) => {
|
||||
if (saved) {
|
||||
this.videoUri = undefined
|
||||
this.showDownloadDialog()
|
||||
} else {
|
||||
ToastUtils.show('保存失败')
|
||||
}
|
||||
})
|
||||
.catch((e: BusinessError) => {
|
||||
ToastUtils.show('保存失败:' + e.message)
|
||||
})
|
||||
})
|
||||
}
|
||||
.visibility(this.isSuccess ? Visibility.Visible : Visibility.None)
|
||||
}
|
||||
.padding({left: 16, top: 9, right: 16, bottom: 30 })
|
||||
.backgroundColor(Color.White)
|
||||
}
|
||||
.width('100%')
|
||||
.height('100%')
|
||||
.backgroundColor($r('app.color.window_background'))
|
||||
}
|
||||
}
|
||||
|
|
@ -9,6 +9,7 @@ import { TipDialog } from '../../../../dialog/TipDialog';
|
|||
import { photoAccessHelper } from '@kit.MediaLibraryKit';
|
||||
import { LocalMediaManager } from '../../../../manager/LocalMediaManager';
|
||||
import { fileIo } from '@kit.CoreFileKit';
|
||||
import { ShareManager } from '../../../../manager/ShareManager';
|
||||
|
||||
@ComponentV2
|
||||
export struct AudioRecordPage {
|
||||
|
|
@ -68,6 +69,11 @@ export struct AudioRecordPage {
|
|||
ListItem() {
|
||||
AudioRecordItemView({ media: item })
|
||||
}
|
||||
.swipeAction({
|
||||
end: this.itemEnd(item)
|
||||
})
|
||||
.borderRadius(8)
|
||||
.backgroundColor(Color.White)
|
||||
})
|
||||
}
|
||||
.width('auto')
|
||||
|
|
@ -83,4 +89,51 @@ export struct AudioRecordPage {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
@Builder
|
||||
itemEnd(media: MediaRecordEntity) {
|
||||
Row() {
|
||||
Button({ type: ButtonType.Normal, stateEffect: true }) {
|
||||
Column() {
|
||||
Image($r('app.media.ic_share_material')).width(18).height(18)
|
||||
Text('分享').fontColor(Color.White).fontSize(10).margin({top: 4})
|
||||
}
|
||||
}
|
||||
.width(56)
|
||||
.height('100%')
|
||||
.backgroundColor('#FF9E43')
|
||||
.onClick(() => {
|
||||
ShareManager.shareFile(media.uri!!)
|
||||
})
|
||||
|
||||
Button({ type: ButtonType.Normal, stateEffect: true }) {
|
||||
Column() {
|
||||
Image($r('app.media.ic_delete_material')).width(18).height(18)
|
||||
Text('删除').fontColor(Color.White).fontSize(10).margin({top: 4})
|
||||
}
|
||||
}
|
||||
.width(56)
|
||||
.height('100%')
|
||||
.backgroundColor('#FF3E3E')
|
||||
.borderRadius({topRight: 8, bottomRight: 8})
|
||||
.onClick(() => {
|
||||
TipDialog.show(this.getUIContext(), {
|
||||
title: '提示', content: '确定删除该音频?', callback: {
|
||||
confirm: () => {
|
||||
fileIo.unlink(media.uri!!)
|
||||
.then(() => {
|
||||
ToastUtils.show('删除成功')
|
||||
LocalMediaManager.delete(media.name!!)
|
||||
AppUtil.getContext().eventHub.emit(EventConstants.MediaActionEvent, MediaType.AUDIO, MediaAction.DELETE)
|
||||
})
|
||||
.catch(() => {
|
||||
ToastUtils.show('删除失败, 请到文件管理中手动删除')
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
.height(74)
|
||||
}
|
||||
}
|
||||
|
|
@ -29,6 +29,12 @@ struct SettingsPage {
|
|||
ToastUtils.show('账户已注销');
|
||||
}
|
||||
|
||||
@Monitor('viewModel.logout')
|
||||
onLogout(monitor: IMonitor) {
|
||||
EventReportGlobalManager.eventReport(EventConstants.EXIT_LOGIN)
|
||||
this.logout();
|
||||
}
|
||||
|
||||
aboutToAppear(): void {
|
||||
this.getCache()
|
||||
}
|
||||
|
|
@ -141,8 +147,7 @@ struct SettingsPage {
|
|||
.onClick(() => {
|
||||
TipDialog.show(this.getUIContext(), {title: '温馨提示', content: '确定退出登录?', callback: {
|
||||
confirm: () => {
|
||||
EventReportGlobalManager.eventReport(EventConstants.EXIT_LOGIN)
|
||||
this.logout();
|
||||
this.viewModel.userLogout()
|
||||
}
|
||||
}})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -0,0 +1,67 @@
|
|||
import { RouterUrls } from '../../../../common/RouterUrls'
|
||||
import { ToolMenuEntity, toolsList } from '../../../../entity/ToolMenuEntity'
|
||||
import { ToolItemView } from '../../../../view/ToolItemView'
|
||||
|
||||
@ComponentV2
|
||||
export struct ToolsPage {
|
||||
build() {
|
||||
Scroll() {
|
||||
Column() {
|
||||
Image($r('app.media.ic_tools_top_bg')).width('100%').aspectRatio(2.925)
|
||||
|
||||
Grid() {
|
||||
ForEach(toolsList().convertToArray(), (item: ToolMenuEntity) => {
|
||||
GridItem() {
|
||||
ToolItemView({ menu: item })
|
||||
}
|
||||
.onClick(() => {
|
||||
switch (item.alias) {
|
||||
case 'resetMD5': {
|
||||
this.getUIContext().getRouter().pushUrl({url: RouterUrls.MD5_RESET_PAGE})
|
||||
break
|
||||
}
|
||||
case 'videoToText': {
|
||||
break
|
||||
}
|
||||
case 'videoToAudio': {
|
||||
this.getUIContext().getRouter().pushUrl({url: RouterUrls.VIDEO_TO_AUDIO_PAGE})
|
||||
break
|
||||
}
|
||||
case 'audioToText': {
|
||||
break
|
||||
}
|
||||
case 'addWatermark': {
|
||||
this.getUIContext().getRouter().pushUrl({url: RouterUrls.ADD_WATERMARK_PAGE})
|
||||
break
|
||||
}
|
||||
case 'longImageMerge': {
|
||||
this.getUIContext().getRouter().pushUrl({url: RouterUrls.IMAGE_MERGE_PAGE})
|
||||
break
|
||||
}
|
||||
case 'removeWatermark': {
|
||||
this.getUIContext().getRouter().pushUrl({url: RouterUrls.REMOVE_WATERMARK_PAGE})
|
||||
break
|
||||
}
|
||||
case 'removeAudio': {
|
||||
this.getUIContext().getRouter().pushUrl({url: RouterUrls.REMOVE_AUDIO_PAGE})
|
||||
break
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
.scrollBar(BarState.Off)
|
||||
.columnsTemplate('1fr 1fr')
|
||||
.rowsGap(9)
|
||||
.columnsGap(9)
|
||||
.margin({top: 20})
|
||||
}
|
||||
.width('100%')
|
||||
.height('auto')
|
||||
.padding({ left: 12, top: 70, right: 12, bottom: 10 })
|
||||
}
|
||||
.height('100%')
|
||||
.scrollBar(BarState.Off)
|
||||
.backgroundColor($r('app.color.window_background'))
|
||||
}
|
||||
}
|
||||
|
|
@ -78,7 +78,7 @@ export class SaveUtils {
|
|||
*/
|
||||
static async saveVideoToAlbum(path: string, name: string): Promise<boolean> {
|
||||
try {
|
||||
let name = `kcsp_${systemDateTime.getTime() + RandomUtil.getRandomInt(1000, 2000)}.mp4`
|
||||
let name = `scmf_${systemDateTime.getTime() + RandomUtil.getRandomInt(1000, 2000)}.mp4`
|
||||
const uri = await PhotoHelper.save(photoAccessHelper.PhotoType.VIDEO, 'mp4', { title: name.replace('.mp4', '') });
|
||||
let file = FileUtil.openSync(uri, fileIo.OpenMode.READ_WRITE | fileIo.OpenMode.CREATE);
|
||||
await FileUtil.copyFile(path, file.fd)
|
||||
|
|
@ -101,7 +101,7 @@ export class SaveUtils {
|
|||
*/
|
||||
static async saveImageToAlbum(path: string, name: string): Promise<boolean> {
|
||||
try {
|
||||
if (FileUtil.accessSync(path)) name = `kcsp_${systemDateTime.getTime() + RandomUtil.getRandomInt(1000, 2000)}.jpeg`
|
||||
if (FileUtil.accessSync(path)) name = `scmf_${systemDateTime.getTime() + RandomUtil.getRandomInt(1000, 2000)}.jpeg`
|
||||
const uri = await PhotoHelper.save(photoAccessHelper.PhotoType.IMAGE, 'jpeg', { title: name.replace('.jpeg', '') });
|
||||
let file = FileUtil.openSync(uri, fileIo.OpenMode.READ_WRITE | fileIo.OpenMode.CREATE);
|
||||
await FileUtil.copyFile(path, file.fd)
|
||||
|
|
|
|||
|
|
@ -138,61 +138,6 @@ export struct ImageRecordItemView {
|
|||
export struct AudioRecordItemView {
|
||||
@Param media?: MediaRecordEntity = undefined;
|
||||
|
||||
build() {
|
||||
RelativeContainer() {
|
||||
Text(this.media?.name)
|
||||
.layoutWeight(1)
|
||||
.fontColor($r('app.color.color_90ffffff'))
|
||||
.fontSize(15)
|
||||
.maxLines(1)
|
||||
.textOverflow({ overflow: TextOverflow.Ellipsis })
|
||||
.alignRules({
|
||||
bottom: { anchor: '__container__', align: VerticalAlign.Center }
|
||||
})
|
||||
.margin({ bottom: 2 })
|
||||
|
||||
Text(this.formatTime(Math.trunc(this.media!!.duration / 1000)))
|
||||
.fontColor($r('app.color.color_60ffffff'))
|
||||
.fontSize(14)
|
||||
.alignRules({
|
||||
top: { anchor: '__container__', align: VerticalAlign.Center }
|
||||
})
|
||||
.margin({ top: 2 })
|
||||
.id('tv_duration')
|
||||
|
||||
Text(DateUtil.getFormatDateStr(this.media!!.createTime, 'yyyy年MM月dd日 HH:mm:ss'))
|
||||
.fontColor($r('app.color.color_30ffffff'))
|
||||
.fontSize(12)
|
||||
.alignRules({
|
||||
left: { anchor: 'tv_duration', align: HorizontalAlign.End },
|
||||
top: { anchor: 'tv_duration', align: VerticalAlign.Top },
|
||||
bottom: { anchor: 'tv_duration', align: VerticalAlign.Bottom }
|
||||
})
|
||||
.margin({ left: 12 })
|
||||
|
||||
Image($r('app.media.ic_arrow_dp22')).width(24).height(24)
|
||||
.alignRules({
|
||||
top: { anchor: '__container__', align: VerticalAlign.Top },
|
||||
bottom: { anchor: '__container__', align: VerticalAlign.Bottom },
|
||||
right: { anchor: '__container__', align: HorizontalAlign.End }
|
||||
})
|
||||
|
||||
Divider().color($r('app.color.color_10ffffff')).width('100%').strokeWidth(1)
|
||||
.alignRules({
|
||||
bottom: { anchor: '__container__', align: VerticalAlign.Bottom }
|
||||
})
|
||||
}
|
||||
.height(74)
|
||||
.onClick(() => {
|
||||
this.getUIContext()
|
||||
.getRouter()
|
||||
.pushUrl({
|
||||
url: RouterUrls.AUDIO_PLAYER_PAGE,
|
||||
params: { title: this.media?.name, uri: this.media?.uri, showActions: true }
|
||||
}, router.RouterMode.Single)
|
||||
})
|
||||
}
|
||||
|
||||
formatTime(time: number): string {
|
||||
let minute: number = 0
|
||||
let second: number = 0
|
||||
|
|
@ -221,4 +166,60 @@ export struct AudioRecordItemView {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
build() {
|
||||
RelativeContainer() {
|
||||
Text(this.media?.name)
|
||||
.layoutWeight(1)
|
||||
.fontColor($r('app.color.color_212226'))
|
||||
.fontSize(15)
|
||||
.maxLines(1)
|
||||
.textOverflow({ overflow: TextOverflow.Ellipsis })
|
||||
.alignRules({
|
||||
bottom: { anchor: '__container__', align: VerticalAlign.Center }
|
||||
})
|
||||
.margin({ bottom: 2 })
|
||||
|
||||
Text(this.formatTime(Math.trunc(this.media!!.duration / 1000)))
|
||||
.fontColor($r('app.color.color_666666'))
|
||||
.fontSize(12)
|
||||
.alignRules({
|
||||
top: { anchor: '__container__', align: VerticalAlign.Center }
|
||||
})
|
||||
.margin({ top: 2 })
|
||||
.id('tv_duration')
|
||||
|
||||
Text(DateUtil.getFormatDateStr(this.media!!.createTime, 'yyyy年MM月dd日 HH:mm:ss'))
|
||||
.fontColor($r('app.color.color_30ffffff'))
|
||||
.fontSize(12)
|
||||
.alignRules({
|
||||
left: { anchor: 'tv_duration', align: HorizontalAlign.End },
|
||||
top: { anchor: 'tv_duration', align: VerticalAlign.Top },
|
||||
bottom: { anchor: 'tv_duration', align: VerticalAlign.Bottom }
|
||||
})
|
||||
.margin({ left: 12 })
|
||||
|
||||
Image($r('app.media.ic_arrow_dp16')).width(16).height(16)
|
||||
.alignRules({
|
||||
top: { anchor: '__container__', align: VerticalAlign.Top },
|
||||
bottom: { anchor: '__container__', align: VerticalAlign.Bottom },
|
||||
right: { anchor: '__container__', align: HorizontalAlign.End }
|
||||
})
|
||||
|
||||
Divider().color($r('app.color.color_10ffffff')).width('100%').strokeWidth(1)
|
||||
.alignRules({
|
||||
bottom: { anchor: '__container__', align: VerticalAlign.Bottom }
|
||||
})
|
||||
}
|
||||
.height(74)
|
||||
.padding({left: 14, right: 14})
|
||||
.onClick(() => {
|
||||
this.getUIContext()
|
||||
.getRouter()
|
||||
.pushUrl({
|
||||
url: RouterUrls.AUDIO_PLAYER_PAGE,
|
||||
params: { title: this.media?.name, uri: this.media?.uri, showActions: true }
|
||||
}, router.RouterMode.Single)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,201 @@
|
|||
import { ActionType, Position, RectPosition } from './RectCropView';
|
||||
|
||||
@ComponentV2
|
||||
export struct SelectBoundsView {
|
||||
private settings: RenderingContextSettings = new RenderingContextSettings(true);
|
||||
private canvasContext: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings);
|
||||
private actionType: ActionType = ActionType.move;
|
||||
private touchPosition: Position = { x: 0, y: 0 };
|
||||
private sw: number = 0; //图片展示框固定宽度
|
||||
private sh: number = 0; //图片展示框固定高度
|
||||
|
||||
@Param onRectChange?: (rect: RectPosition) => void = undefined
|
||||
@Param onClose?: () => void = undefined
|
||||
|
||||
@Local clipRect: RectPosition = {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 80,
|
||||
height: 40
|
||||
};
|
||||
@Local initPosition: Position = {
|
||||
x: 0,
|
||||
y: 0
|
||||
}
|
||||
@Local fontSize: number = 15
|
||||
|
||||
build() {
|
||||
Stack() {
|
||||
Stack()
|
||||
.position({
|
||||
x: this.clipRect.x,
|
||||
y: this.clipRect.y
|
||||
})
|
||||
.width(this.clipRect.width)
|
||||
.height(this.clipRect.height)
|
||||
.blur(20)
|
||||
.id('mosaic')
|
||||
|
||||
Image($r('app.media.ic_right_bottom_rect'))
|
||||
.position({
|
||||
x: this.clipRect.x + this.clipRect.width - 9,
|
||||
y: this.clipRect.y + this.clipRect.height - 9
|
||||
})
|
||||
.width(15)
|
||||
.height(15)
|
||||
|
||||
// 裁剪框
|
||||
Canvas(this.canvasContext)
|
||||
.position({
|
||||
x: this.clipRect.x,
|
||||
y: this.clipRect.y
|
||||
})
|
||||
.width(this.clipRect.width)
|
||||
.height(this.clipRect.height)
|
||||
.onReady(() => {
|
||||
this.drawClipImage()
|
||||
})
|
||||
.onTouch(event => {
|
||||
if (event.type === TouchType.Down) {
|
||||
this.isMove(event.target.area, event.touches[0]);
|
||||
this.touchPosition = {
|
||||
x: event.touches[0].screenX,
|
||||
y: event.touches[0].screenY
|
||||
}
|
||||
} else if (event.type === TouchType.Move) {
|
||||
let moveX = event.changedTouches[0].screenX - this.touchPosition.x;
|
||||
let moveY = event.changedTouches[0].screenY - this.touchPosition.y;
|
||||
this.touchPosition = {
|
||||
x: event.changedTouches[0].screenX,
|
||||
y: event.changedTouches[0].screenY
|
||||
}
|
||||
this.moveClipCanvas(moveX, moveY);
|
||||
}
|
||||
})
|
||||
|
||||
Image($r('app.media.ic_left_top_rect'))
|
||||
.position({
|
||||
x: this.clipRect.x - 7,
|
||||
y: this.clipRect.y - 7
|
||||
})
|
||||
.width(16)
|
||||
.height(16)
|
||||
.onClick(() => {
|
||||
if (this.onClose) {
|
||||
this.onClose()
|
||||
}
|
||||
})
|
||||
}
|
||||
.width('100%')
|
||||
.height('100%')
|
||||
.onAreaChange((_oldArea, newArea) => {
|
||||
this.sw = newArea.width as number
|
||||
this.sh = newArea.height as number
|
||||
if (this.onRectChange) {
|
||||
this.onRectChange(this.clipRect)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 绘制裁剪框
|
||||
drawClipImage() {
|
||||
this.canvasContext.clearRect(0, 0, this.clipRect.width, this.clipRect.height);
|
||||
this.canvasContext.lineWidth = 2
|
||||
this.canvasContext.strokeStyle = Color.White
|
||||
this.canvasContext.beginPath()
|
||||
this.canvasContext.rect(0, 0, this.clipRect.width, this.clipRect.height)
|
||||
this.canvasContext.stroke()
|
||||
}
|
||||
|
||||
// 裁剪框位置和大小变化 初始位置为图片的初始坐标 移动的坐标
|
||||
moveClipCanvas(moveX: number, moveY: number) {
|
||||
let clipRect: RectPosition = {
|
||||
x: this.clipRect.x,
|
||||
y: this.clipRect.y,
|
||||
width: this.clipRect.width,
|
||||
height: this.clipRect.height
|
||||
}
|
||||
switch (this.actionType) {
|
||||
case ActionType.move:
|
||||
clipRect.x += moveX;
|
||||
clipRect.y += moveY;
|
||||
break;
|
||||
case ActionType.topLeft:
|
||||
clipRect.x += moveX;
|
||||
clipRect.y += moveY;
|
||||
clipRect.width += -moveX;
|
||||
clipRect.height += -moveY;
|
||||
break;
|
||||
case ActionType.topRight:
|
||||
clipRect.y += moveY;
|
||||
clipRect.width += moveX;
|
||||
clipRect.height += -moveY;
|
||||
break;
|
||||
case ActionType.bottomLeft:
|
||||
clipRect.x += moveX;
|
||||
clipRect.width += -moveX;
|
||||
clipRect.height += moveY;
|
||||
break;
|
||||
case ActionType.bottomRight:
|
||||
clipRect.width += moveX;
|
||||
clipRect.height += moveY;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// 偏移坐标小于初始位置
|
||||
if (clipRect.x < this.initPosition.x) {
|
||||
clipRect.x = this.initPosition.x;
|
||||
}
|
||||
|
||||
if (clipRect.y < this.initPosition.y) {
|
||||
clipRect.y = this.initPosition.y;
|
||||
}
|
||||
|
||||
// 横坐标限制位置
|
||||
if (clipRect.width + clipRect.x > this.sw + this.initPosition.x) {
|
||||
if (this.actionType === ActionType.move) {
|
||||
clipRect.x = this.sw + this.initPosition.x - clipRect.width;
|
||||
} else {
|
||||
clipRect.width = this.sw + this.initPosition.x - clipRect.x;
|
||||
}
|
||||
}
|
||||
|
||||
// 纵坐标限制
|
||||
if (clipRect.height + clipRect.y > this.sh + this.initPosition.y) {
|
||||
if (this.actionType === ActionType.move) {
|
||||
clipRect.y = this.sh + this.initPosition.y - clipRect.height;
|
||||
} else {
|
||||
clipRect.height = this.sh + this.initPosition.y - clipRect.y;
|
||||
}
|
||||
}
|
||||
|
||||
//裁剪框位置大小
|
||||
this.clipRect = {
|
||||
x: Math.round(clipRect.x),
|
||||
y: Math.round(clipRect.y),
|
||||
width: Math.max(Math.round(clipRect.width), 80),
|
||||
height: Math.max(Math.round(clipRect.height), 40)
|
||||
};
|
||||
|
||||
if (this.onRectChange) {
|
||||
this.onRectChange(this.clipRect)
|
||||
}
|
||||
}
|
||||
|
||||
// 判断操作类型
|
||||
isMove(area: Area, touch: TouchObject) {
|
||||
if (touch.x < 30 && touch.y < 30) { // 左上角
|
||||
this.actionType = ActionType.topLeft
|
||||
} else if (touch.x < 30 && touch.y > (Number(area.height) - 30)) { // 左下
|
||||
this.actionType = ActionType.bottomLeft
|
||||
} else if (touch.x > Number(area.width) - 30 && touch.y < 30) { // 右上
|
||||
this.actionType = ActionType.topRight
|
||||
} else if (touch.x > Number(area.width) - 30 && touch.y > (Number(area.height) - 30)) { // 右下
|
||||
this.actionType = ActionType.bottomRight
|
||||
} else {
|
||||
this.actionType = ActionType.move
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
import { ToolMenuEntity } from '../entity/ToolMenuEntity'
|
||||
|
||||
@ComponentV2
|
||||
export struct ToolItemView {
|
||||
@Param menu?: ToolMenuEntity = undefined
|
||||
|
||||
build() {
|
||||
Column() {
|
||||
Row() {
|
||||
Image(this.menu?.icon).width(44).height(44).margin({left: 12, top: 16, bottom: 16})
|
||||
Column() {
|
||||
Text(this.menu?.title).fontColor($r('app.color.color_212226')).fontSize(16).fontWeight(FontWeight.Medium)
|
||||
Text(this.menu?.desc).fontColor($r('app.color.color_666666')).fontSize(12).margin({top: 4})
|
||||
}
|
||||
.margin({left: 12})
|
||||
.alignItems(HorizontalAlign.Start)
|
||||
}
|
||||
.width('100%')
|
||||
.borderRadius({topLeft: 8, topRight: 8})
|
||||
.linearGradient({
|
||||
direction: GradientDirection.Bottom,
|
||||
colors: [[this.menu?.colors[0], 0.0], [this.menu?.colors[1], 1.0]]
|
||||
})
|
||||
|
||||
Row() {
|
||||
Text(this.menu?.count + 'w人使用').fontColor($r('app.color.color_999999')).fontSize(12).layoutWeight(1)
|
||||
Image($r('app.media.ic_tool_arrow')).width(20).height(20)
|
||||
}
|
||||
.padding({left:12, top: 8, right: 12, bottom: 8 })
|
||||
}
|
||||
.width('100%')
|
||||
.borderRadius(8)
|
||||
.backgroundColor(Color.White)
|
||||
.padding(1)
|
||||
.alignItems(HorizontalAlign.Start)
|
||||
}
|
||||
}
|
||||
|
|
@ -5,6 +5,7 @@ import { BaseViewModel } from './BaseViewModel';
|
|||
@ObservedV2
|
||||
export class SettingsViewModel extends BaseViewModel {
|
||||
@Trace destroy?: object;
|
||||
@Trace logout?: object;
|
||||
|
||||
async userDestroy() {
|
||||
this.showLoading();
|
||||
|
|
@ -22,4 +23,21 @@ export class SettingsViewModel extends BaseViewModel {
|
|||
this.dismissLoading();
|
||||
}
|
||||
}
|
||||
|
||||
async userLogout() {
|
||||
this.showLoading();
|
||||
try {
|
||||
const result = await apiService.logout();
|
||||
if (result.isSuccess()) {
|
||||
this.logout = new Object();
|
||||
} else {
|
||||
ToastUtils.show(result.message, true);
|
||||
}
|
||||
this.dismissLoading();
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
ToastUtils.show(e);
|
||||
this.dismissLoading();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -52,6 +52,10 @@
|
|||
"name": "color_cccccc",
|
||||
"value": "#CCCCCC"
|
||||
},
|
||||
{
|
||||
"name": "color_eeeeee",
|
||||
"value": "#EEEEEE"
|
||||
},
|
||||
|
||||
|
||||
{
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 264 B After Width: | Height: | Size: 3.2 KiB |
|
Before Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 794 B |
|
After Width: | Height: | Size: 524 B |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 2.8 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 5.9 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 674 B After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 418 B |
|
After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 338 B |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 770 B |
|
After Width: | Height: | Size: 544 B |
|
After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 127 KiB |
|
Before Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 7.1 KiB |
|
Before Width: | Height: | Size: 1.4 KiB |
|
|
@ -9,14 +9,16 @@
|
|||
"pages/main/home/link/TakeMaterialPage",
|
||||
"pages/main/home/course/CoursePage",
|
||||
"pages/main/home/wx/WxVideoPage",
|
||||
"pages/main/home/tools/AddWaterMarkerPage",
|
||||
"pages/main/home/tools/AddWatermarkPage",
|
||||
"pages/main/home/tools/RemoveWatermarkPage",
|
||||
"pages/main/home/tools/MD5ResetPage",
|
||||
"pages/main/home/tools/VideoReversePage",
|
||||
"pages/main/home/tools/VideoMirrorPage",
|
||||
"pages/main/home/tools/ClipVideoPage",
|
||||
"pages/main/home/tools/RemoveAudioPage",
|
||||
"pages/main/home/tools/AddAudioPage",
|
||||
"pages/main/home/tools/TakeAudioPage",
|
||||
"pages/main/home/tools/VideoToAudioPage",
|
||||
"pages/main/home/tools/ImageMergePage",
|
||||
"pages/main/home/material/MaterialDetailPage",
|
||||
"pages/main/mine/user/UserSettingsPage",
|
||||
"pages/main/mine/vip/VipPage",
|
||||
|
|
|
|||