添加视频转音频,md5修改, 视频加水印,视频打码,视频去原声,长图拼接(待完善)
|
|
@ -7,6 +7,7 @@ export class EventConstants {
|
||||||
static readonly MineRefreshEvent = "MineRefreshEvent"
|
static readonly MineRefreshEvent = "MineRefreshEvent"
|
||||||
static readonly MediaActionEvent = "MediaActionEvent"
|
static readonly MediaActionEvent = "MediaActionEvent"
|
||||||
static readonly JumpToRecordEvent = "JumpToRecordEvent"
|
static readonly JumpToRecordEvent = "JumpToRecordEvent"
|
||||||
|
static readonly JumpToToolsEvent = "JumpToToolsEvent"
|
||||||
static readonly DownloadHistoryRefreshEvent = "DownloadHistoryRefreshEvent"
|
static readonly DownloadHistoryRefreshEvent = "DownloadHistoryRefreshEvent"
|
||||||
static readonly MaterialListRefreshEvent = "MaterialListRefreshEvent"
|
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去重页
|
* 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 { 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';
|
import { DialogCallback } from '../callback/DialogCallback';
|
||||||
|
|
||||||
export enum DownloadStatus {
|
export enum DownloadStatus {
|
||||||
|
|
@ -29,7 +29,7 @@ function defaultBuilder(option: DownloadDialogOption) {
|
||||||
option.status === DownloadStatus.VIDEO_DOWNLOADING ? '视频下载中' :
|
option.status === DownloadStatus.VIDEO_DOWNLOADING ? '视频下载中' :
|
||||||
option.status === DownloadStatus.AUDIO_DOWNLOADING ? '音频下载中' : '处理中') +
|
option.status === DownloadStatus.AUDIO_DOWNLOADING ? '音频下载中' : '处理中') +
|
||||||
(option.totalCount > 1 ? ` ${option.index + 1}/${option.totalCount}` : ''))
|
(option.totalCount > 1 ? ` ${option.index + 1}/${option.totalCount}` : ''))
|
||||||
.fontColor($r('app.color.color_90ffffff'))
|
.fontColor($r('app.color.color_212226'))
|
||||||
.fontSize(16)
|
.fontSize(16)
|
||||||
.visibility(option.status === DownloadStatus.COMPLETED ? Visibility.None : Visibility.Visible)
|
.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 })
|
Progress({ value: option.progress, total: option.totalSize, type: ProgressType.Linear })
|
||||||
.width('100%')
|
.width('100%')
|
||||||
.style({ strokeWidth: 12, strokeRadius: 6 })
|
.style({ strokeWidth: 12, strokeRadius: 6 })
|
||||||
.color('#FC4F54')
|
.color($r('app.color.color_466afd'))
|
||||||
.colorBlend($r('app.color.color_10ffffff'))
|
// .colorBlend('#F1F2F6')
|
||||||
.borderRadius(6)
|
.borderRadius(6)
|
||||||
|
|
||||||
Text(FormatUtil.getFormatPercentage(option.progress / option.totalSize, 1))
|
Text(FormatUtil.getFormatPercentage(option.progress / option.totalSize, 1))
|
||||||
|
|
@ -56,14 +56,14 @@ function defaultBuilder(option: DownloadDialogOption) {
|
||||||
.fontSize(10)
|
.fontSize(10)
|
||||||
.borderRadius(10)
|
.borderRadius(10)
|
||||||
.borderWidth(1)
|
.borderWidth(1)
|
||||||
.borderColor($r('app.color.color_80ffffff'))
|
.borderColor(Color.White)
|
||||||
.backgroundColor($r("app.color.color_466afd"))
|
.backgroundColor($r("app.color.color_466afd"))
|
||||||
.translate({ x: (AppUtil.getUIContext().px2vp(DisplayUtil.getWidth()) * 0.8 - 80) * option.progress / option.totalSize })
|
.translate({ x: (AppUtil.getUIContext().px2vp(DisplayUtil.getWidth()) * 0.8 - 80) * option.progress / option.totalSize })
|
||||||
}
|
}
|
||||||
|
|
||||||
Text(`${FileUtil.getFormatFileSize(option.progress)}/${option.totalSize !== 0 ?
|
Text(`${FileUtil.getFormatFileSize(option.progress)}/${option.totalSize !== 0 ?
|
||||||
FileUtil.getFormatFileSize(option.totalSize) : '获取中'}`)
|
FileUtil.getFormatFileSize(option.totalSize) : '获取中'}`)
|
||||||
.fontColor($r('app.color.color_999999'))
|
.fontColor($r('app.color.color_727686'))
|
||||||
.fontSize(12)
|
.fontSize(12)
|
||||||
.margin({ top: 16 })
|
.margin({ top: 16 })
|
||||||
.visibility(option.status === DownloadStatus.PROCESSING ? Visibility.Hidden : Visibility.Visible)
|
.visibility(option.status === DownloadStatus.PROCESSING ? Visibility.Hidden : Visibility.Visible)
|
||||||
|
|
@ -72,8 +72,8 @@ function defaultBuilder(option: DownloadDialogOption) {
|
||||||
Button('取消下载', { type: ButtonType.Capsule, stateEffect: true })
|
Button('取消下载', { type: ButtonType.Capsule, stateEffect: true })
|
||||||
.width(110)
|
.width(110)
|
||||||
.height(36)
|
.height(36)
|
||||||
.backgroundColor($r('app.color.color_333333'))
|
.backgroundColor('#F1F2F6')
|
||||||
.fontColor($r('app.color.color_50ffffff'))
|
.fontColor('#80859B')
|
||||||
.fontSize(15)
|
.fontSize(15)
|
||||||
.onClick(() => {
|
.onClick(() => {
|
||||||
if (option.callback?.cancel) {
|
if (option.callback?.cancel) {
|
||||||
|
|
@ -85,11 +85,8 @@ function defaultBuilder(option: DownloadDialogOption) {
|
||||||
Button('后台下载', { type: ButtonType.Capsule, stateEffect: true })
|
Button('后台下载', { type: ButtonType.Capsule, stateEffect: true })
|
||||||
.width(110)
|
.width(110)
|
||||||
.height(36)
|
.height(36)
|
||||||
.linearGradient({
|
.backgroundColor($r('app.color.color_466afd'))
|
||||||
colors: [['#F62C6C', 0.0], ['#FC4F54', 1.0]],
|
.fontColor(Color.White)
|
||||||
direction: GradientDirection.Right
|
|
||||||
})
|
|
||||||
.fontColor($r('app.color.color_90ffffff'))
|
|
||||||
.fontSize(15)
|
.fontSize(15)
|
||||||
.margin({ left: 10 })
|
.margin({ left: 10 })
|
||||||
.onClick(() => {
|
.onClick(() => {
|
||||||
|
|
@ -106,10 +103,10 @@ function defaultBuilder(option: DownloadDialogOption) {
|
||||||
.visibility(option.status === DownloadStatus.COMPLETED ? Visibility.None : Visibility.Visible)
|
.visibility(option.status === DownloadStatus.COMPLETED ? Visibility.None : Visibility.Visible)
|
||||||
|
|
||||||
Column() {
|
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/图库')
|
Text(option.isAudio ? '文件管理/我的手机/Download/素材魔方' : '文件管理/我的手机/Download/图库')
|
||||||
.fontColor($r('app.color.color_999999'))
|
.fontColor($r('app.color.color_727686'))
|
||||||
.fontSize(12)
|
.fontSize(12)
|
||||||
.margin({ top: 10 })
|
.margin({ top: 10 })
|
||||||
|
|
||||||
|
|
@ -117,8 +114,8 @@ function defaultBuilder(option: DownloadDialogOption) {
|
||||||
Button('取消', { type: ButtonType.Capsule, stateEffect: true })
|
Button('取消', { type: ButtonType.Capsule, stateEffect: true })
|
||||||
.width(110)
|
.width(110)
|
||||||
.height(36)
|
.height(36)
|
||||||
.backgroundColor($r('app.color.color_333333'))
|
.backgroundColor('#F1F2F6')
|
||||||
.fontColor($r('app.color.color_50ffffff'))
|
.fontColor('#80859B')
|
||||||
.fontSize(15)
|
.fontSize(15)
|
||||||
.onClick(() => {
|
.onClick(() => {
|
||||||
if (option.callback?.cancel) {
|
if (option.callback?.cancel) {
|
||||||
|
|
@ -132,11 +129,8 @@ function defaultBuilder(option: DownloadDialogOption) {
|
||||||
Button('前往查看', { type: ButtonType.Capsule, stateEffect: true })
|
Button('前往查看', { type: ButtonType.Capsule, stateEffect: true })
|
||||||
.width(110)
|
.width(110)
|
||||||
.height(36)
|
.height(36)
|
||||||
.linearGradient({
|
.backgroundColor($r('app.color.color_466afd'))
|
||||||
colors: [['#F62C6C', 0.0], ['#FC4F54', 1.0]],
|
.fontColor(Color.White)
|
||||||
direction: GradientDirection.Right
|
|
||||||
})
|
|
||||||
.fontColor($r('app.color.color_90ffffff'))
|
|
||||||
.fontSize(15)
|
.fontSize(15)
|
||||||
.onClick(() => {
|
.onClick(() => {
|
||||||
if (option.callback?.confirm) {
|
if (option.callback?.confirm) {
|
||||||
|
|
@ -153,7 +147,7 @@ function defaultBuilder(option: DownloadDialogOption) {
|
||||||
}
|
}
|
||||||
.width('80%')
|
.width('80%')
|
||||||
.borderRadius(10)
|
.borderRadius(10)
|
||||||
.backgroundColor($r('app.color.color_222222'))
|
.backgroundColor(Color.White)
|
||||||
.padding(20)
|
.padding(20)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import { SaveUtils } from '../utils/SaveUtils';
|
||||||
import { LoginManager } from '../manager/LoginGlobalManager';
|
import { LoginManager } from '../manager/LoginGlobalManager';
|
||||||
import { Want } from '@kit.AbilityKit';
|
import { Want } from '@kit.AbilityKit';
|
||||||
import { WXApi } from '../utils/wechat/WXApiEventHandlerImpl';
|
import { WXApi } from '../utils/wechat/WXApiEventHandlerImpl';
|
||||||
|
import { Constants } from '../common/Constants';
|
||||||
|
|
||||||
@CustomDialog
|
@CustomDialog
|
||||||
export struct JoinWxGroupCourseDialog {
|
export struct JoinWxGroupCourseDialog {
|
||||||
|
|
@ -15,22 +16,22 @@ export struct JoinWxGroupCourseDialog {
|
||||||
isPlayback: boolean = true
|
isPlayback: boolean = true
|
||||||
|
|
||||||
images: Array<Resource> = [
|
images: Array<Resource> = [
|
||||||
$r('app.media.ic_wx_group_tip1'),
|
$r('app.media.ic_join_wx_group_tip1'),
|
||||||
$r("app.media.ic_wx_group_tip2"),
|
$r('app.media.ic_join_wx_group_tip2'),
|
||||||
$r("app.media.ic_wx_group_tip3"),
|
$r("app.media.ic_join_wx_group_tip3"),
|
||||||
$r("app.media.ic_wx_group_tip4"),
|
$r("app.media.ic_join_wx_group_tip4"),
|
||||||
$r('app.media.ic_wx_group_tip5')
|
$r("app.media.ic_join_wx_group_tip5"),
|
||||||
];
|
];
|
||||||
|
|
||||||
steps: Array<string> = ['第一步', '第二步', '第三步', '第四步', '第五步']
|
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
|
@State currentIndex: number = 0
|
||||||
|
|
||||||
downloadImage() {
|
downloadImage() {
|
||||||
try {
|
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)) {
|
if (FileUtil.accessSync(cachePath)) {
|
||||||
FileUtil.unlink(cachePath)
|
FileUtil.unlink(cachePath)
|
||||||
}
|
}
|
||||||
|
|
@ -43,7 +44,7 @@ export struct JoinWxGroupCourseDialog {
|
||||||
SaveUtils.saveImageVideoToAlbumDialog([cachePath], false)
|
SaveUtils.saveImageVideoToAlbumDialog([cachePath], false)
|
||||||
.then((saved) => {
|
.then((saved) => {
|
||||||
if (saved) {
|
if (saved) {
|
||||||
PasteboardUtil.setDataTextSync(LoginManager.getUserInfo()!!.user_id)
|
PasteboardUtil.setDataTextSync(`${LoginManager.getUserInfo()!!.user_id}|${Constants.APP_ID}`)
|
||||||
ToastUtils.show('ID复制成功')
|
ToastUtils.show('ID复制成功')
|
||||||
this.jumpToWxScan()
|
this.jumpToWxScan()
|
||||||
this.controller.close()
|
this.controller.close()
|
||||||
|
|
@ -78,11 +79,11 @@ export struct JoinWxGroupCourseDialog {
|
||||||
|
|
||||||
build() {
|
build() {
|
||||||
RelativeContainer() {
|
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 ? '添加直播回放助手流程' : '添加视频助手流程')
|
Text(this.isPlayback ? '添加直播回放助手流程' : '添加视频助手流程')
|
||||||
.width('auto')
|
.width('auto')
|
||||||
.fontColor(Color.White)
|
.fontColor($r('app.color.color_1a1a1a'))
|
||||||
.fontSize(16)
|
.fontSize(16)
|
||||||
.fontWeight(FontWeight.Medium)
|
.fontWeight(FontWeight.Medium)
|
||||||
.margin({ top: 16 })
|
.margin({ top: 16 })
|
||||||
|
|
@ -95,10 +96,17 @@ export struct JoinWxGroupCourseDialog {
|
||||||
List({space: 16}) {
|
List({space: 16}) {
|
||||||
ForEach(this.steps, (item: string, index) => {
|
ForEach(this.steps, (item: string, index) => {
|
||||||
ListItem() {
|
ListItem() {
|
||||||
Text(item)
|
Stack() {
|
||||||
.fontColor(index == this.currentIndex ? Color.White : $r('app.color.color_bebebe'))
|
if (index === this.currentIndex) {
|
||||||
.fontSize(index == this.currentIndex ? 16 : 14)
|
Image($r('app.media.ic_join_wx_group_tip_indicator')).width(44).height(10)
|
||||||
.fontWeight(index == this.currentIndex ? FontWeight.Medium : FontWeight.Normal)
|
.margin({top: 10, left: 5})
|
||||||
|
}
|
||||||
|
Text(item)
|
||||||
|
.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(() => {
|
.onClick(() => {
|
||||||
this.swiperController.changeIndex(index, true)
|
this.swiperController.changeIndex(index, true)
|
||||||
|
|
@ -137,9 +145,9 @@ export struct JoinWxGroupCourseDialog {
|
||||||
|
|
||||||
Row() {
|
Row() {
|
||||||
Button('取消', { type: ButtonType.Capsule, stateEffect: false })
|
Button('取消', { type: ButtonType.Capsule, stateEffect: false })
|
||||||
.fontColor($r('app.color.color_50ffffff'))
|
.fontColor($r('app.color.color_1a1a1a'))
|
||||||
.fontSize(15)
|
.fontSize(15)
|
||||||
.backgroundColor($r('app.color.color_333333'))
|
.backgroundColor($r('app.color.color_eeeeee'))
|
||||||
.width(126)
|
.width(126)
|
||||||
.height(46)
|
.height(46)
|
||||||
.onClick(() => {
|
.onClick(() => {
|
||||||
|
|
@ -149,11 +157,7 @@ export struct JoinWxGroupCourseDialog {
|
||||||
Button('前往微信扫码加群', { type: ButtonType.Capsule, stateEffect: false })
|
Button('前往微信扫码加群', { type: ButtonType.Capsule, stateEffect: false })
|
||||||
.fontColor(Color.White)
|
.fontColor(Color.White)
|
||||||
.fontSize(15)
|
.fontSize(15)
|
||||||
.backgroundColor(Color.Transparent)
|
.backgroundColor($r('app.color.color_466afd'))
|
||||||
.linearGradient({
|
|
||||||
colors: [['#F62C6C', 0.0], ['#FC4F54', 1.0]],
|
|
||||||
direction: GradientDirection.Right
|
|
||||||
})
|
|
||||||
.layoutWeight(1)
|
.layoutWeight(1)
|
||||||
.height(46)
|
.height(46)
|
||||||
.onClick(() => {
|
.onClick(() => {
|
||||||
|
|
@ -164,7 +168,7 @@ export struct JoinWxGroupCourseDialog {
|
||||||
this.downloadImage()
|
this.downloadImage()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
.backgroundColor($r('app.color.color_222222'))
|
.backgroundColor(Color.White)
|
||||||
.alignRules({
|
.alignRules({
|
||||||
top: {anchor: 'swiper', align: VerticalAlign.Bottom}
|
top: {anchor: 'swiper', align: VerticalAlign.Bottom}
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -4,12 +4,12 @@ import { ComponentContent } from '@kit.ArkUI';
|
||||||
function defaultBuilder(text: string) {
|
function defaultBuilder(text: string) {
|
||||||
Column() {
|
Column() {
|
||||||
LoadingProgress()
|
LoadingProgress()
|
||||||
.color(Color.White)
|
.color($r('app.color.color_466afd'))
|
||||||
.width(50)
|
.width(50)
|
||||||
.height(50)
|
.height(50)
|
||||||
|
|
||||||
Text(text)
|
Text(text)
|
||||||
.fontColor(Color.White)
|
.fontColor($r('app.color.color_466afd'))
|
||||||
.fontSize(12)
|
.fontSize(12)
|
||||||
.maxLines(1)
|
.maxLines(1)
|
||||||
.textOverflow({ overflow: TextOverflow.Ellipsis })
|
.textOverflow({ overflow: TextOverflow.Ellipsis })
|
||||||
|
|
@ -22,7 +22,7 @@ function defaultBuilder(text: string) {
|
||||||
.height(124)
|
.height(124)
|
||||||
.justifyContent(FlexAlign.Center)
|
.justifyContent(FlexAlign.Center)
|
||||||
.borderRadius(6)
|
.borderRadius(6)
|
||||||
.backgroundColor($r('app.color.color_222222'))
|
.backgroundColor(Color.White)
|
||||||
.padding({left: 10, right: 10})
|
.padding({left: 10, right: 10})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -52,11 +52,11 @@ export class MediaEntity {
|
||||||
initFileName(): string {
|
initFileName(): string {
|
||||||
if (!this.name) {
|
if (!this.name) {
|
||||||
if (this instanceof VideoMaterial) {
|
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) {
|
} 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) {
|
} 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
|
return this.name
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { ArrayList } from "@kit.ArkTS";
|
import { ArrayList } from '@kit.ArkTS';
|
||||||
import { LoginManager } from "../manager/LoginGlobalManager";
|
import { LoginManager } from '../manager/LoginGlobalManager';
|
||||||
|
|
||||||
export class MenuEntity {
|
export class MenuEntity {
|
||||||
icon: Resource | null = null;
|
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_DESTROY = '/api/user/destroy';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 退出登陆
|
||||||
|
*/
|
||||||
|
static readonly USER_LOGOUT = '/api/user/logout';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 用户账号列表
|
* 用户账号列表
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -147,6 +147,14 @@ class ApiService {
|
||||||
return AxiosRequest.post<HttpResult>(Api.USER_DESTROY)
|
return AxiosRequest.post<HttpResult>(Api.USER_DESTROY)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 退出登陆
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
logout(): Promise<HttpResult> {
|
||||||
|
return AxiosRequest.post<HttpResult>(Api.USER_LOGOUT)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 解绑账号
|
* 解绑账号
|
||||||
* @returns
|
* @returns
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ import { ConfigManager } from '../../manager/UserConfigManager';
|
||||||
import { EventReportGlobalManager } from '../../manager/EventReportGlobalManager';
|
import { EventReportGlobalManager } from '../../manager/EventReportGlobalManager';
|
||||||
import { PasteboardUtils } from '../../utils/PasteboardUtils';
|
import { PasteboardUtils } from '../../utils/PasteboardUtils';
|
||||||
import { MaterialPage } from './material/MaterialPage';
|
import { MaterialPage } from './material/MaterialPage';
|
||||||
|
import { ToolsPage } from './mine/tool/ToolsPage';
|
||||||
|
|
||||||
@Entry
|
@Entry
|
||||||
@ComponentV2
|
@ComponentV2
|
||||||
|
|
@ -51,6 +52,7 @@ struct MainPage {
|
||||||
aboutToDisappear(): void {
|
aboutToDisappear(): void {
|
||||||
AppUtil.getContext().eventHub.off(EventConstants.LoginSuccessEvent);
|
AppUtil.getContext().eventHub.off(EventConstants.LoginSuccessEvent);
|
||||||
AppUtil.getContext().eventHub.off(EventConstants.JumpToRecordEvent);
|
AppUtil.getContext().eventHub.off(EventConstants.JumpToRecordEvent);
|
||||||
|
AppUtil.getContext().eventHub.off(EventConstants.JumpToToolsEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
onPageShow(): void {
|
onPageShow(): void {
|
||||||
|
|
@ -71,6 +73,9 @@ struct MainPage {
|
||||||
this.tabController.changeIndex(3)
|
this.tabController.changeIndex(3)
|
||||||
this.currentIndex = 1
|
this.currentIndex = 1
|
||||||
})
|
})
|
||||||
|
AppUtil.getContext().eventHub.on(EventConstants.JumpToToolsEvent, () => {
|
||||||
|
this.tabController.changeIndex(2)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
checkPasteboard() {
|
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')))
|
.tabBar(this.tabBuilder(this.titles[1], 1, $r('app.media.ic_material_select'), $r('app.media.ic_material_default')))
|
||||||
|
|
||||||
TabContent() {
|
TabContent() {
|
||||||
|
ToolsPage()
|
||||||
}
|
}
|
||||||
.tabBar(this.tabBuilder(this.titles[2], 2, $r('app.media.ic_tool_select'), $r('app.media.ic_tool_default')))
|
.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(() => {
|
.onClick(() => {
|
||||||
switch (item.alias) {
|
switch (item.alias) {
|
||||||
case 'videoToAudio': {
|
case 'videoToAudio': {
|
||||||
this.getUIContext().getRouter().pushUrl({url: RouterUrls.TAKE_AUDIO_PAGE})
|
this.getUIContext().getRouter().pushUrl({url: RouterUrls.VIDEO_TO_AUDIO_PAGE})
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
case 'addWatermark': {
|
case 'addWatermark': {
|
||||||
this.getUIContext().getRouter().pushUrl({url: RouterUrls.ADD_WATER_MARKER_PAGE})
|
this.getUIContext().getRouter().pushUrl({url: RouterUrls.ADD_WATERMARK_PAGE})
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
case 'videoToText': {
|
case 'videoToText': {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
case 'longImageMerge': {
|
case 'longImageMerge': {
|
||||||
|
this.getUIContext().getRouter().pushUrl({url: RouterUrls.IMAGE_MERGE_PAGE})
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
case 'moreTools': {
|
case 'moreTools': {
|
||||||
|
AppUtil.getContext().eventHub.emit(EventConstants.JumpToToolsEvent);
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -380,6 +380,7 @@ struct TakeMaterialPage {
|
||||||
parseUrl(url: string) {
|
parseUrl(url: string) {
|
||||||
if (StrUtil.isNotEmpty(this.inputText)) {
|
if (StrUtil.isNotEmpty(this.inputText)) {
|
||||||
this.viewModel.getMaterialInfo(url);
|
this.viewModel.getMaterialInfo(url);
|
||||||
|
KeyboardUtil.hide()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -499,7 +500,6 @@ struct TakeMaterialPage {
|
||||||
.backgroundColor($r('app.color.color_466afd'))
|
.backgroundColor($r('app.color.color_466afd'))
|
||||||
.onClick(() => {
|
.onClick(() => {
|
||||||
if (StrUtil.isNotEmpty(this.inputText)) {
|
if (StrUtil.isNotEmpty(this.inputText)) {
|
||||||
KeyboardUtil.hide()
|
|
||||||
this.parseUrl(this.inputText)
|
this.parseUrl(this.inputText)
|
||||||
EventReportGlobalManager.eventReport(EventConstants.GET_MATERIAL, "material-button", this.inputText)
|
EventReportGlobalManager.eventReport(EventConstants.GET_MATERIAL, "material-button", this.inputText)
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -87,7 +87,7 @@ struct MaterialDetailPage {
|
||||||
|
|
||||||
download() {
|
download() {
|
||||||
LoadingDialog.show(this.getUIContext())
|
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 = {
|
let config: request.agent.Config = {
|
||||||
action: request.agent.Action.DOWNLOAD,
|
action: request.agent.Action.DOWNLOAD,
|
||||||
url: this.material!!.pic!!.url,
|
url: this.material!!.pic!!.url,
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,7 @@ struct AddAudioPage {
|
||||||
// 复制音频文件到缓存目录下
|
// 复制音频文件到缓存目录下
|
||||||
FileUtil.copyFileSync(audioFile.fd, cacheAudioPath)
|
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}`
|
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, {
|
MP4Parser.ffmpegCmd(cmd, {
|
||||||
callBackResult: (code: number) => {
|
callBackResult: (code: number) => {
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ import { avSessionManager } from '../../../../manager/AVSessionManager'
|
||||||
|
|
||||||
@Entry
|
@Entry
|
||||||
@ComponentV2
|
@ComponentV2
|
||||||
struct AddWaterMarkerPage {
|
struct AddWatermarkPage {
|
||||||
@Local uri?: string
|
@Local uri?: string
|
||||||
@Local currentTime: number = 0
|
@Local currentTime: number = 0
|
||||||
@Local durationTime: number = 0
|
@Local durationTime: number = 0
|
||||||
|
|
@ -29,7 +29,7 @@ struct AddWaterMarkerPage {
|
||||||
@Local isSuccess: boolean = false
|
@Local isSuccess: boolean = false
|
||||||
@Local playerSize: media.PixelMapParams = { width: 0, height: 0 }
|
@Local playerSize: media.PixelMapParams = { width: 0, height: 0 }
|
||||||
|
|
||||||
@Local showWaterMaker: boolean = false
|
@Local showWatermark: boolean = false
|
||||||
@Local textContent: string = ''
|
@Local textContent: string = ''
|
||||||
@Local imagePath: string = ''
|
@Local imagePath: string = ''
|
||||||
|
|
||||||
|
|
@ -37,10 +37,10 @@ struct AddWaterMarkerPage {
|
||||||
private videoSize: media.PixelMapParams = { width: 0, height: 0 }
|
private videoSize: media.PixelMapParams = { width: 0, height: 0 }
|
||||||
private rect: RectPosition = { x: 0, y: 0, width: 0, height: 0 }
|
private rect: RectPosition = { x: 0, y: 0, width: 0, height: 0 }
|
||||||
|
|
||||||
addWaterMarker() {
|
addWatermark() {
|
||||||
LoadingDialog.show(this.getUIContext())
|
LoadingDialog.show(this.getUIContext())
|
||||||
this.isSuccess = false
|
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)) {
|
if (FileUtil.accessSync(cacheVideoPath)) {
|
||||||
FileUtil.unlinkSync(cacheVideoPath)
|
FileUtil.unlinkSync(cacheVideoPath)
|
||||||
}
|
}
|
||||||
|
|
@ -58,7 +58,7 @@ struct AddWaterMarkerPage {
|
||||||
this.getUIContext().getComponentSnapshot().get(StrUtil.isNotEmpty(this.textContent) ? 'textWaterMarker' : 'imageWaterMarker')
|
this.getUIContext().getComponentSnapshot().get(StrUtil.isNotEmpty(this.textContent) ? 'textWaterMarker' : 'imageWaterMarker')
|
||||||
.then(async (image: image.PixelMap) => {
|
.then(async (image: image.PixelMap) => {
|
||||||
let imagePath = await ImageUtil.savePixelMap(image, FileUtil.getCacheDirPath(), `cache_${systemDateTime.getTime()}.png`)
|
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}`
|
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, {
|
MP4Parser.ffmpegCmd(cmd, {
|
||||||
callBackResult: (code: number) => {
|
callBackResult: (code: number) => {
|
||||||
|
|
@ -93,7 +93,7 @@ struct AddWaterMarkerPage {
|
||||||
this.isSuccess = false
|
this.isSuccess = false
|
||||||
this.uri = uris[0]
|
this.uri = uris[0]
|
||||||
|
|
||||||
this.showWaterMaker = false
|
this.showWatermark = false
|
||||||
this.textContent = ''
|
this.textContent = ''
|
||||||
this.imagePath = ''
|
this.imagePath = ''
|
||||||
|
|
||||||
|
|
@ -101,7 +101,7 @@ struct AddWaterMarkerPage {
|
||||||
.then((size) => {
|
.then((size) => {
|
||||||
this.videoSize = size
|
this.videoSize = size
|
||||||
if (size.width && size.height) {
|
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)}
|
this.playerSize = {width: Math.ceil(size.width * ratio), height: Math.ceil(size.height * ratio)}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
@ -168,37 +168,28 @@ struct AddWaterMarkerPage {
|
||||||
|
|
||||||
build() {
|
build() {
|
||||||
Column() {
|
Column() {
|
||||||
TitleBar({ title: '加水印' })
|
TitleBar({ title: '视频加水印' })
|
||||||
|
|
||||||
Column() {
|
Stack() {
|
||||||
Row() {
|
Stack() {
|
||||||
Text('上传视频').fontColor($r('app.color.color_90ffffff')).fontSize(16).fontWeight(FontWeight.Medium)
|
Column() {
|
||||||
Text('(仅支持mp4格式)').fontColor($r('app.color.color_50ffffff')).fontSize(12)
|
Image($r('app.media.ic_add_video')).width(40).height(40)
|
||||||
}.alignSelf(ItemAlign.Start)
|
Text('请上传视频').fontColor($r('app.color.color_466afd')).fontSize(15).fontWeight(FontWeight.Medium).margin({ top: 8})
|
||||||
|
|
||||||
RelativeContainer() {
|
|
||||||
Stack() {
|
|
||||||
Image($r('app.media.ic_add_video')).width(44).height(44)
|
|
||||||
}
|
}
|
||||||
.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 }
|
|
||||||
})
|
|
||||||
.onClick(() => {
|
|
||||||
this.selectVideo()
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
.height(220)
|
.width('100%')
|
||||||
.margin({ top: 12 })
|
.aspectRatio(1)
|
||||||
.borderRadius(8)
|
.borderRadius(20)
|
||||||
.backgroundColor($r('app.color.color_222222'))
|
.backgroundColor(Color.White)
|
||||||
}.margin({ left: 16, top: 16, right: 16 })
|
.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)
|
.visibility(this.uri ? Visibility.None : Visibility.Visible)
|
||||||
|
|
||||||
Column() {
|
Column() {
|
||||||
|
|
@ -305,7 +296,7 @@ struct AddWaterMarkerPage {
|
||||||
bottom: { anchor: 'video', align: VerticalAlign.Bottom }
|
bottom: { anchor: 'video', align: VerticalAlign.Bottom }
|
||||||
})
|
})
|
||||||
|
|
||||||
if (this.showWaterMaker && this.uri && !this.isSuccess) {
|
if (this.showWatermark && this.uri && !this.isSuccess) {
|
||||||
WaterMarkerView({
|
WaterMarkerView({
|
||||||
content: this.textContent,
|
content: this.textContent,
|
||||||
imagePath: this.imagePath,
|
imagePath: this.imagePath,
|
||||||
|
|
@ -313,7 +304,7 @@ struct AddWaterMarkerPage {
|
||||||
this.rect = rect
|
this.rect = rect
|
||||||
},
|
},
|
||||||
onClose: () => {
|
onClose: () => {
|
||||||
this.showWaterMaker = false
|
this.showWatermark = false
|
||||||
this.textContent = ''
|
this.textContent = ''
|
||||||
this.imagePath = ''
|
this.imagePath = ''
|
||||||
}
|
}
|
||||||
|
|
@ -332,25 +323,36 @@ struct AddWaterMarkerPage {
|
||||||
|
|
||||||
Row() {
|
Row() {
|
||||||
Column(){
|
Column(){
|
||||||
Image($r('app.media.ic_text_water_marker')).width(50).height(50)
|
Image($r('app.media.ic_watermark_icon1')).width(26).height(26)
|
||||||
Text('文字').fontColor($r('app.color.color_90ffffff')).fontSize(14).margin({ top: 8 })
|
Text('水印').fontColor($r('app.color.color_212226')).fontSize(12).margin({ top: 8 })
|
||||||
}
|
}
|
||||||
|
.layoutWeight(1)
|
||||||
.onClick(() => {
|
.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()
|
this.controller.stop()
|
||||||
EditTextDialog.show(this.getUIContext(), {title: '添加水印', hintText: '请输入文字', confirm: (text) => {
|
EditTextDialog.show(this.getUIContext(), {title: '添加水印', hintText: '请输入文字', confirm: (text) => {
|
||||||
this.textContent = text
|
this.textContent = text
|
||||||
this.showWaterMaker = true
|
this.showWatermark = true
|
||||||
}})
|
}})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
Column(){
|
Column(){
|
||||||
Image($r('app.media.ic_image_water_marker')).width(50).height(50)
|
Image($r('app.media.ic_watermark_icon3')).width(26).height(26)
|
||||||
Text('图片').fontColor($r('app.color.color_90ffffff')).fontSize(14).margin({ top: 8 })
|
Text('图片').fontColor($r('app.color.color_212226')).fontSize(12).margin({ top: 8 })
|
||||||
}
|
}
|
||||||
.margin({ left: 50 })
|
.layoutWeight(1)
|
||||||
.onClick(() => {
|
.onClick(() => {
|
||||||
if (!this.showWaterMaker) {
|
if (!this.showWatermark) {
|
||||||
this.controller.stop()
|
this.controller.stop()
|
||||||
PhotoHelper.selectEasy({
|
PhotoHelper.selectEasy({
|
||||||
MIMEType: photoAccessHelper.PhotoViewMIMETypes.IMAGE_TYPE,
|
MIMEType: photoAccessHelper.PhotoViewMIMETypes.IMAGE_TYPE,
|
||||||
|
|
@ -363,60 +365,88 @@ struct AddWaterMarkerPage {
|
||||||
if (uris.length != 0) {
|
if (uris.length != 0) {
|
||||||
this.isSuccess = false
|
this.isSuccess = false
|
||||||
this.imagePath = uris[0]
|
this.imagePath = uris[0]
|
||||||
this.showWaterMaker = true
|
this.showWatermark = true
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
.margin({ top: 20 })
|
.width('90%')
|
||||||
|
.height(82)
|
||||||
Row() {
|
.margin({ top: 20, bottom: 20 })
|
||||||
Text(this.isSuccess ? '重新上传' : '取消').fontColor($r('app.color.color_90ffffff'))
|
.borderRadius(10)
|
||||||
.fontSize(17)
|
.backgroundColor(Color.White)
|
||||||
.margin({ left: 16 })
|
|
||||||
.onClick(() => {
|
|
||||||
this.controller.stop()
|
|
||||||
if (this.isSuccess) {
|
|
||||||
this.selectVideo()
|
|
||||||
} else {
|
|
||||||
this.getUIContext().getRouter().back()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
Blank().layoutWeight(1)
|
|
||||||
Text(this.isSuccess ? '保存' : '确定')
|
|
||||||
.fontColor($r("app.color.color_466afd"))
|
|
||||||
.fontSize(17)
|
|
||||||
.margin({ right: 16 })
|
|
||||||
.onClick(() => {
|
|
||||||
this.controller.stop()
|
|
||||||
if (this.isSuccess) {
|
|
||||||
SaveUtils.saveImageVideoToAlbumDialog([this.uri!!])
|
|
||||||
.then((saved) => {
|
|
||||||
if (saved) {
|
|
||||||
this.uri = undefined
|
|
||||||
this.showDownloadDialog()
|
|
||||||
} else {
|
|
||||||
ToastUtils.show('保存失败')
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch((e: BusinessError) => {
|
|
||||||
ToastUtils.show('保存失败:' + e.message)
|
|
||||||
})
|
|
||||||
|
|
||||||
} else {
|
|
||||||
if (this.showWaterMaker) {
|
|
||||||
this.addWaterMarker()
|
|
||||||
} else {
|
|
||||||
ToastUtils.show('请添加水印')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
.margin({ top: 20, bottom: 30 })
|
|
||||||
}
|
}
|
||||||
.layoutWeight(1)
|
.layoutWeight(1)
|
||||||
.visibility(this.uri ? Visibility.Visible : Visibility.None)
|
.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%')
|
.width('100%')
|
||||||
.height('100%')
|
.height('100%')
|
||||||
|
|
@ -35,7 +35,7 @@ struct ClipVideoPage {
|
||||||
clipVideo() {
|
clipVideo() {
|
||||||
LoadingDialog.show(this.getUIContext())
|
LoadingDialog.show(this.getUIContext())
|
||||||
this.isSuccess = false
|
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)) {
|
if (FileUtil.accessSync(cacheVideoPath)) {
|
||||||
FileUtil.unlinkSync(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!!
|
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}`
|
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, {
|
MP4Parser.ffmpegCmd(cmd, {
|
||||||
callBackResult: (code: number) => {
|
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() {
|
modifyMD5() {
|
||||||
LoadingDialog.show(this.getUIContext())
|
LoadingDialog.show(this.getUIContext())
|
||||||
this.isSuccess = false
|
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)) {
|
if (FileUtil.accessSync(outputPath)) {
|
||||||
FileUtil.unlinkSync(outputPath)
|
FileUtil.unlinkSync(outputPath)
|
||||||
}
|
}
|
||||||
|
|
@ -115,172 +115,201 @@ struct MD5ResetPage {
|
||||||
Column() {
|
Column() {
|
||||||
TitleBar({ title: 'MD5去重' })
|
TitleBar({ title: 'MD5去重' })
|
||||||
|
|
||||||
Column() {
|
Stack() {
|
||||||
Row() {
|
Stack() {
|
||||||
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)
|
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)
|
.width('100%')
|
||||||
.height(140)
|
.height('100%')
|
||||||
.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 }
|
|
||||||
})
|
|
||||||
.onClick(() => {
|
.onClick(() => {
|
||||||
this.selectVideo()
|
this.selectVideo()
|
||||||
})
|
})
|
||||||
}
|
.visibility(this.uri ? Visibility.None : Visibility.Visible)
|
||||||
.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() {
|
||||||
RelativeContainer() {
|
Video({
|
||||||
Video({
|
src: this.uri, // 设置视频源
|
||||||
src: this.uri, // 设置视频源
|
controller: this.controller, //设置视频控制器,可以控制视频的播放状态
|
||||||
controller: this.controller, //设置视频控制器,可以控制视频的播放状态
|
posterOptions: { showFirstFrame: true }
|
||||||
posterOptions: { showFirstFrame: true }
|
|
||||||
})
|
|
||||||
.width('100%')
|
|
||||||
.height('100%')
|
|
||||||
.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) => {
|
.width('100%')
|
||||||
if (event) {
|
.height('100%')
|
||||||
this.currentTime = event.time
|
.borderRadius(20)
|
||||||
}
|
.backgroundColor(Color.White)
|
||||||
})
|
.controls(false) // 设置是否显示默认控制条
|
||||||
.onStart(() => {
|
.autoPlay(false) // 设置是否自动播放
|
||||||
this.isPlaying = true
|
.loop(false) // 设置是否循环播放
|
||||||
})
|
.objectFit(ImageFit.Contain) // 设置视频填充模式
|
||||||
.onPause(() => {
|
.onPrepared((event) => {
|
||||||
this.isPlaying = false
|
if (event) {
|
||||||
avSessionManager.deactivate()
|
this.durationTime = event.duration
|
||||||
})
|
|
||||||
.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)
|
.onUpdate((event) => {
|
||||||
Slider({
|
if (event) {
|
||||||
value: this.currentTime,
|
this.currentTime = event.time
|
||||||
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)
|
.onStart(() => {
|
||||||
Text(this.formatTime(this.durationTime)).width(35).fontColor(Color.White).fontSize(12)
|
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 }
|
||||||
|
})
|
||||||
}
|
}
|
||||||
.opacity(0.8)
|
.width('100%')
|
||||||
.width("100%")
|
.height('100%')
|
||||||
.padding({ left: 30, right: 30 })
|
.visibility(this.uri ? Visibility.Visible : Visibility.None)
|
||||||
.alignRules({
|
|
||||||
bottom: { anchor: '__container__', align: VerticalAlign.Bottom }
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
.layoutWeight(1)
|
.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.uri) {
|
||||||
|
this.modifyMD5()
|
||||||
|
} else {
|
||||||
|
ToastUtils.show('请上传视频')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.visibility(!this.isSuccess ? Visibility.Visible : Visibility.None)
|
||||||
|
|
||||||
Row() {
|
Row() {
|
||||||
Text(this.isSuccess ? '重新上传' : '取消').fontColor($r('app.color.color_90ffffff')).fontSize(17).margin({ left: 16 })
|
Button({ type: ButtonType.Capsule, stateEffect: true }) {
|
||||||
.onClick(() => {
|
Row() {
|
||||||
this.controller.stop()
|
Image($r('app.media.ic_reupload')).width(20).height(20)
|
||||||
if (this.isSuccess) {
|
Text('重新上传').fontColor($r('app.color.color_466afd')).fontSize(15).fontWeight(FontWeight.Medium)
|
||||||
this.selectVideo()
|
}
|
||||||
} else {
|
}
|
||||||
this.getUIContext().getRouter().back()
|
.height(46)
|
||||||
}
|
.layoutWeight(1)
|
||||||
})
|
.borderWidth(1)
|
||||||
Blank().layoutWeight(1)
|
.borderColor($r('app.color.color_466afd'))
|
||||||
Text(this.isSuccess ? '保存' : '确定').fontColor($r("app.color.color_466afd")).fontSize(17).margin({ right: 16 })
|
.backgroundColor(Color.Transparent)
|
||||||
.onClick(() => {
|
.onClick(() => {
|
||||||
this.controller.stop()
|
this.controller.stop()
|
||||||
if (this.isSuccess) {
|
this.selectVideo()
|
||||||
SaveUtils.saveImageVideoToAlbumDialog([this.uri!!])
|
})
|
||||||
.then((saved) => {
|
|
||||||
if (saved) {
|
|
||||||
this.uri = undefined
|
|
||||||
this.showDownloadDialog()
|
|
||||||
} else {
|
|
||||||
ToastUtils.show('保存失败')
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch((e: BusinessError) => {
|
|
||||||
ToastUtils.show('保存失败:' + e.message)
|
|
||||||
})
|
|
||||||
|
|
||||||
} else {
|
Blank().width(9)
|
||||||
this.modifyMD5()
|
|
||||||
}
|
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)
|
||||||
|
})
|
||||||
|
})
|
||||||
}
|
}
|
||||||
.margin({ top: 140, bottom: 30 })
|
.visibility(this.isSuccess ? Visibility.Visible : Visibility.None)
|
||||||
}
|
}
|
||||||
.layoutWeight(1)
|
.padding({left: 16, top: 9, right: 16, bottom: 30 })
|
||||||
.visibility(this.uri ? Visibility.Visible : Visibility.None)
|
.backgroundColor(Color.White)
|
||||||
}
|
}
|
||||||
.width('100%')
|
.width('100%')
|
||||||
.height('100%')
|
.height('100%')
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ struct RemoveAudioPage {
|
||||||
@Local isPlaying: boolean = false
|
@Local isPlaying: boolean = false
|
||||||
@Local isSuccess: boolean = false
|
@Local isSuccess: boolean = false
|
||||||
|
|
||||||
mirrorVideo() {
|
removeAudio() {
|
||||||
LoadingDialog.show(this.getUIContext())
|
LoadingDialog.show(this.getUIContext())
|
||||||
this.isSuccess = false
|
this.isSuccess = false
|
||||||
let cachePath = FileUtil.getCacheDirPath() + FileUtil.separator + `cache_${systemDateTime.getTime()}.mp4`
|
let cachePath = FileUtil.getCacheDirPath() + FileUtil.separator + `cache_${systemDateTime.getTime()}.mp4`
|
||||||
|
|
@ -34,7 +34,7 @@ struct RemoveAudioPage {
|
||||||
// 复制文件到缓存目录下
|
// 复制文件到缓存目录下
|
||||||
FileUtil.copyFileSync(file.fd, cachePath)
|
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}`
|
let cmd = `ffmpeg -i ${cachePath} -an -c:v copy ${outputPath}`
|
||||||
MP4Parser.ffmpegCmd(cmd, {
|
MP4Parser.ffmpegCmd(cmd, {
|
||||||
callBackResult: (code: number) => {
|
callBackResult: (code: number) => {
|
||||||
|
|
@ -119,174 +119,203 @@ struct RemoveAudioPage {
|
||||||
|
|
||||||
build() {
|
build() {
|
||||||
Column() {
|
Column() {
|
||||||
TitleBar({ title: '去音乐' })
|
TitleBar({ title: '视频去原声' })
|
||||||
|
|
||||||
Column() {
|
Stack() {
|
||||||
Row() {
|
Stack() {
|
||||||
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)
|
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)
|
.width('100%')
|
||||||
.height(140)
|
.height('100%')
|
||||||
.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 }
|
|
||||||
})
|
|
||||||
.onClick(() => {
|
.onClick(() => {
|
||||||
this.selectVideo()
|
this.selectVideo()
|
||||||
})
|
})
|
||||||
}
|
.visibility(this.uri ? Visibility.None : Visibility.Visible)
|
||||||
.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() {
|
||||||
RelativeContainer() {
|
Video({
|
||||||
Video({
|
src: this.uri, // 设置视频源
|
||||||
src: this.uri, // 设置视频源
|
controller: this.controller, //设置视频控制器,可以控制视频的播放状态
|
||||||
controller: this.controller, //设置视频控制器,可以控制视频的播放状态
|
posterOptions: { showFirstFrame: true }
|
||||||
posterOptions: { showFirstFrame: true }
|
|
||||||
})
|
|
||||||
.width('100%')
|
|
||||||
.height('100%')
|
|
||||||
.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) => {
|
.width('100%')
|
||||||
if (event) {
|
.height('100%')
|
||||||
this.currentTime = event.time
|
.borderRadius(20)
|
||||||
}
|
.backgroundColor(Color.White)
|
||||||
})
|
.controls(false) // 设置是否显示默认控制条
|
||||||
.onStart(() => {
|
.autoPlay(false) // 设置是否自动播放
|
||||||
this.isPlaying = true
|
.loop(false) // 设置是否循环播放
|
||||||
})
|
.objectFit(ImageFit.Contain) // 设置视频填充模式
|
||||||
.onPause(() => {
|
.onPrepared((event) => {
|
||||||
this.isPlaying = false
|
if (event) {
|
||||||
avSessionManager.deactivate()
|
this.durationTime = event.duration
|
||||||
})
|
|
||||||
.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)
|
.onUpdate((event) => {
|
||||||
Slider({
|
if (event) {
|
||||||
value: this.currentTime,
|
this.currentTime = event.time
|
||||||
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)
|
.onStart(() => {
|
||||||
Text(this.formatTime(this.durationTime)).width(35).fontColor(Color.White).fontSize(12)
|
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 }
|
||||||
|
})
|
||||||
}
|
}
|
||||||
.opacity(0.8)
|
.width('100%')
|
||||||
.width("100%")
|
.height('100%')
|
||||||
.padding({ left: 30, right: 30 })
|
.visibility(this.uri ? Visibility.Visible : Visibility.None)
|
||||||
.alignRules({
|
|
||||||
bottom: { anchor: '__container__', align: VerticalAlign.Bottom }
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
.layoutWeight(1)
|
.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.uri) {
|
||||||
|
this.removeAudio()
|
||||||
|
} else {
|
||||||
|
ToastUtils.show('请上传视频')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.visibility(!this.isSuccess ? Visibility.Visible : Visibility.None)
|
||||||
|
|
||||||
Row() {
|
Row() {
|
||||||
Text(this.isSuccess ? '重新上传' : '取消').fontColor($r('app.color.color_90ffffff')).fontSize(17).margin({ left: 16 })
|
Button({ type: ButtonType.Capsule, stateEffect: true }) {
|
||||||
.onClick(() => {
|
Row() {
|
||||||
this.controller.stop()
|
Image($r('app.media.ic_reupload')).width(20).height(20)
|
||||||
if (this.isSuccess) {
|
Text('重新上传').fontColor($r('app.color.color_466afd')).fontSize(15).fontWeight(FontWeight.Medium)
|
||||||
this.selectVideo()
|
}
|
||||||
} else {
|
}
|
||||||
this.getUIContext().getRouter().back()
|
.height(46)
|
||||||
}
|
.layoutWeight(1)
|
||||||
})
|
.borderWidth(1)
|
||||||
Blank().layoutWeight(1)
|
.borderColor($r('app.color.color_466afd'))
|
||||||
Text(this.isSuccess ? '保存' : '确定').fontColor($r("app.color.color_466afd")).fontSize(17).margin({ right: 16 })
|
.backgroundColor(Color.Transparent)
|
||||||
.onClick(() => {
|
.onClick(() => {
|
||||||
this.controller.stop()
|
this.controller.stop()
|
||||||
if (this.isSuccess) {
|
this.selectVideo()
|
||||||
SaveUtils.saveImageVideoToAlbumDialog([this.uri!!])
|
})
|
||||||
.then((saved) => {
|
|
||||||
if (saved) {
|
|
||||||
this.uri = undefined
|
|
||||||
this.showDownloadDialog()
|
|
||||||
} else {
|
|
||||||
ToastUtils.show('保存失败')
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch((e: BusinessError) => {
|
|
||||||
ToastUtils.show('保存失败:' + e.message)
|
|
||||||
})
|
|
||||||
|
|
||||||
} else {
|
Blank().width(9)
|
||||||
this.mirrorVideo()
|
|
||||||
}
|
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)
|
||||||
|
})
|
||||||
|
})
|
||||||
}
|
}
|
||||||
.margin({ top: 140, bottom: 30 })
|
.visibility(this.isSuccess ? Visibility.Visible : Visibility.None)
|
||||||
}
|
}
|
||||||
.layoutWeight(1)
|
.padding({left: 16, top: 9, right: 16, bottom: 30 })
|
||||||
.visibility(this.uri ? Visibility.Visible : Visibility.None)
|
.backgroundColor(Color.White)
|
||||||
}
|
}
|
||||||
.width('100%')
|
.width('100%')
|
||||||
.height('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() {
|
mirrorVideo() {
|
||||||
LoadingDialog.show(this.getUIContext())
|
LoadingDialog.show(this.getUIContext())
|
||||||
this.isSuccess = false
|
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)) {
|
if (FileUtil.accessSync(cacheVideoPath)) {
|
||||||
FileUtil.unlinkSync(cacheVideoPath)
|
FileUtil.unlinkSync(cacheVideoPath)
|
||||||
}
|
}
|
||||||
|
|
@ -37,7 +37,7 @@ struct VideoMirrorPage {
|
||||||
// 复制文件到缓存目录下
|
// 复制文件到缓存目录下
|
||||||
FileUtil.copyFileSync(file.fd, cacheVideoPath)
|
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}`
|
let cmd = `ffmpeg -i ${cacheVideoPath} -vf ${this.orientation === 1 ? "hflip" : "vflip"} -c:v h264 -pix_fmt yuv420p -y ${outputPath}`
|
||||||
MP4Parser.ffmpegCmd(cmd, {
|
MP4Parser.ffmpegCmd(cmd, {
|
||||||
callBackResult: (code: number) => {
|
callBackResult: (code: number) => {
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ struct VideoReversePage {
|
||||||
videoReverse() {
|
videoReverse() {
|
||||||
LoadingDialog.show(this.getUIContext())
|
LoadingDialog.show(this.getUIContext())
|
||||||
this.isSuccess = false
|
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)) {
|
if (FileUtil.accessSync(cacheVideoPath)) {
|
||||||
FileUtil.unlinkSync(cacheVideoPath)
|
FileUtil.unlinkSync(cacheVideoPath)
|
||||||
}
|
}
|
||||||
|
|
@ -35,7 +35,7 @@ struct VideoReversePage {
|
||||||
// 复制文件到缓存目录下
|
// 复制文件到缓存目录下
|
||||||
FileUtil.copyFileSync(file.fd, cacheVideoPath)
|
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}`
|
let cmd = `ffmpeg -i ${cacheVideoPath} -vf reverse -af areverse -c:v h264 -pix_fmt yuv420p -y ${outputPath}`
|
||||||
MP4Parser.ffmpegCmd(cmd, {
|
MP4Parser.ffmpegCmd(cmd, {
|
||||||
callBackResult: (code: number) => {
|
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 { photoAccessHelper } from '@kit.MediaLibraryKit';
|
||||||
import { LocalMediaManager } from '../../../../manager/LocalMediaManager';
|
import { LocalMediaManager } from '../../../../manager/LocalMediaManager';
|
||||||
import { fileIo } from '@kit.CoreFileKit';
|
import { fileIo } from '@kit.CoreFileKit';
|
||||||
|
import { ShareManager } from '../../../../manager/ShareManager';
|
||||||
|
|
||||||
@ComponentV2
|
@ComponentV2
|
||||||
export struct AudioRecordPage {
|
export struct AudioRecordPage {
|
||||||
|
|
@ -68,6 +69,11 @@ export struct AudioRecordPage {
|
||||||
ListItem() {
|
ListItem() {
|
||||||
AudioRecordItemView({ media: item })
|
AudioRecordItemView({ media: item })
|
||||||
}
|
}
|
||||||
|
.swipeAction({
|
||||||
|
end: this.itemEnd(item)
|
||||||
|
})
|
||||||
|
.borderRadius(8)
|
||||||
|
.backgroundColor(Color.White)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
.width('auto')
|
.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('账户已注销');
|
ToastUtils.show('账户已注销');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Monitor('viewModel.logout')
|
||||||
|
onLogout(monitor: IMonitor) {
|
||||||
|
EventReportGlobalManager.eventReport(EventConstants.EXIT_LOGIN)
|
||||||
|
this.logout();
|
||||||
|
}
|
||||||
|
|
||||||
aboutToAppear(): void {
|
aboutToAppear(): void {
|
||||||
this.getCache()
|
this.getCache()
|
||||||
}
|
}
|
||||||
|
|
@ -141,8 +147,7 @@ struct SettingsPage {
|
||||||
.onClick(() => {
|
.onClick(() => {
|
||||||
TipDialog.show(this.getUIContext(), {title: '温馨提示', content: '确定退出登录?', callback: {
|
TipDialog.show(this.getUIContext(), {title: '温馨提示', content: '确定退出登录?', callback: {
|
||||||
confirm: () => {
|
confirm: () => {
|
||||||
EventReportGlobalManager.eventReport(EventConstants.EXIT_LOGIN)
|
this.viewModel.userLogout()
|
||||||
this.logout();
|
|
||||||
}
|
}
|
||||||
}})
|
}})
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -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> {
|
static async saveVideoToAlbum(path: string, name: string): Promise<boolean> {
|
||||||
try {
|
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', '') });
|
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);
|
let file = FileUtil.openSync(uri, fileIo.OpenMode.READ_WRITE | fileIo.OpenMode.CREATE);
|
||||||
await FileUtil.copyFile(path, file.fd)
|
await FileUtil.copyFile(path, file.fd)
|
||||||
|
|
@ -101,7 +101,7 @@ export class SaveUtils {
|
||||||
*/
|
*/
|
||||||
static async saveImageToAlbum(path: string, name: string): Promise<boolean> {
|
static async saveImageToAlbum(path: string, name: string): Promise<boolean> {
|
||||||
try {
|
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', '') });
|
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);
|
let file = FileUtil.openSync(uri, fileIo.OpenMode.READ_WRITE | fileIo.OpenMode.CREATE);
|
||||||
await FileUtil.copyFile(path, file.fd)
|
await FileUtil.copyFile(path, file.fd)
|
||||||
|
|
|
||||||
|
|
@ -138,61 +138,6 @@ export struct ImageRecordItemView {
|
||||||
export struct AudioRecordItemView {
|
export struct AudioRecordItemView {
|
||||||
@Param media?: MediaRecordEntity = undefined;
|
@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 {
|
formatTime(time: number): string {
|
||||||
let minute: number = 0
|
let minute: number = 0
|
||||||
let second: 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
|
@ObservedV2
|
||||||
export class SettingsViewModel extends BaseViewModel {
|
export class SettingsViewModel extends BaseViewModel {
|
||||||
@Trace destroy?: object;
|
@Trace destroy?: object;
|
||||||
|
@Trace logout?: object;
|
||||||
|
|
||||||
async userDestroy() {
|
async userDestroy() {
|
||||||
this.showLoading();
|
this.showLoading();
|
||||||
|
|
@ -22,4 +23,21 @@ export class SettingsViewModel extends BaseViewModel {
|
||||||
this.dismissLoading();
|
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",
|
"name": "color_cccccc",
|
||||||
"value": "#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/link/TakeMaterialPage",
|
||||||
"pages/main/home/course/CoursePage",
|
"pages/main/home/course/CoursePage",
|
||||||
"pages/main/home/wx/WxVideoPage",
|
"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/MD5ResetPage",
|
||||||
"pages/main/home/tools/VideoReversePage",
|
"pages/main/home/tools/VideoReversePage",
|
||||||
"pages/main/home/tools/VideoMirrorPage",
|
"pages/main/home/tools/VideoMirrorPage",
|
||||||
"pages/main/home/tools/ClipVideoPage",
|
"pages/main/home/tools/ClipVideoPage",
|
||||||
"pages/main/home/tools/RemoveAudioPage",
|
"pages/main/home/tools/RemoveAudioPage",
|
||||||
"pages/main/home/tools/AddAudioPage",
|
"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/home/material/MaterialDetailPage",
|
||||||
"pages/main/mine/user/UserSettingsPage",
|
"pages/main/mine/user/UserSettingsPage",
|
||||||
"pages/main/mine/vip/VipPage",
|
"pages/main/mine/vip/VipPage",
|
||||||
|
|
|
||||||