init
This commit is contained in:
commit
3936d39f7a
|
|
@ -0,0 +1,12 @@
|
|||
/node_modules
|
||||
/oh_modules
|
||||
/local.properties
|
||||
/.idea
|
||||
**/build
|
||||
/.hvigor
|
||||
.cxx
|
||||
/.clangd
|
||||
/.clang-format
|
||||
/.clang-tidy
|
||||
**/.test
|
||||
/.appanalyzer
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"app": {
|
||||
"bundleName": "com.ylqh.hm_cube",
|
||||
"vendor": "devcon",
|
||||
"versionCode": 210,
|
||||
"versionName": "2.1.0",
|
||||
"icon": "$media:layer_logo",
|
||||
"label": "$string:app_name"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
{
|
||||
"string": [
|
||||
{
|
||||
"name": "app_name",
|
||||
"value": "素材魔方"
|
||||
},
|
||||
{
|
||||
"name": "oaid_reason",
|
||||
"value": "为了更好的为您提供服务,请求授权广告跨应用关联访问权限"
|
||||
},
|
||||
{
|
||||
"name": "read_pasteboard_reason",
|
||||
"value": "为了方便识别您复制的链接并跳转相关页面,请求授权剪贴板读取权限"
|
||||
},
|
||||
{
|
||||
"name": "privacy_content",
|
||||
"value": "请你务必审慎阅读、充分理解服务协议和隐私政策各条款,包括但不限于:为了更好的向你提供服务,我们需要访问你的相册、位置信息等。你可阅读《隐私政策》了解详细信息。如果你同意,请点击下面同意按钮开始接受我们的服务。"
|
||||
},
|
||||
{
|
||||
"name": "wx_video_course",
|
||||
"value": "1、点击【添加助手】,自动跳转进入微信创建快存助手;\n2、进入微信视频号,选择视频分享至-客服消息-素材助手;\n3、返回【素材魔方APP】微信视频号页面,下拉刷新即可下载微信号视频;"
|
||||
},
|
||||
{
|
||||
"name": "wx_playback_course",
|
||||
"value": "1、点击【添加直播回放助手】;\n2、自动跳转进入微信小程序,扫二维码加入群聊;\n3、成功加入会自动绑定您的ID,若显示绑定失败可回到我们APP,点击复制我的ID后发送至群聊即可重新绑定;\n4、绑定成功就可以去微信直播回放页面,选择直播回放视频分享到群聊里,返回我们APP刷新即可;"
|
||||
}
|
||||
]
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 6.4 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 51 KiB |
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"layered-image": {
|
||||
"foreground": "$media:ic_launcher_foreground",
|
||||
"background": "$media:ic_launcher_background"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
{
|
||||
"app": {
|
||||
"signingConfigs": [
|
||||
{
|
||||
"name": "release",
|
||||
"type": "HarmonyOS",
|
||||
"material": {
|
||||
"storeFile": "D:/android/签名/hmos/hmos.p12",
|
||||
"storePassword": "000000188D653F4B8748579F0084CAC913B6D6AB6FF60084FB0F318CC52AC425A874B607DD8261F9",
|
||||
"keyAlias": "__uni__1be0b2f",
|
||||
"keyPassword": "00000018779445CEA4B7EA75CB8F722F9DA76CBDBC5CE7C083CE8B5E1973141BF17E654C7237F5EF",
|
||||
"signAlg": "SHA256withECDSA",
|
||||
"profile": "D:/android/签名/hmos/素材魔方/cube_releaseRelease.p7b",
|
||||
"certpath": "D:/android/签名/hmos/素材魔方/cube_release.cer"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "debug",
|
||||
"type": "HarmonyOS",
|
||||
"material": {
|
||||
"storeFile": "D:/android/签名/hmos/hmos.p12",
|
||||
"storePassword": "000000188D653F4B8748579F0084CAC913B6D6AB6FF60084FB0F318CC52AC425A874B607DD8261F9",
|
||||
"keyAlias": "__uni__1be0b2f",
|
||||
"keyPassword": "00000018779445CEA4B7EA75CB8F722F9DA76CBDBC5CE7C083CE8B5E1973141BF17E654C7237F5EF",
|
||||
"signAlg": "SHA256withECDSA",
|
||||
"profile": "D:/android/签名/hmos/素材魔方/cube_debugDebug.p7b",
|
||||
"certpath": "D:/android/签名/hmos/素材魔方/cube_debug.cer"
|
||||
}
|
||||
}
|
||||
],
|
||||
"products": [
|
||||
{
|
||||
"name": "default",
|
||||
"signingConfig": "release",
|
||||
"targetSdkVersion": "5.1.0(18)",
|
||||
"compatibleSdkVersion": "5.0.4(16)",
|
||||
"runtimeOS": "HarmonyOS",
|
||||
"buildOption": {
|
||||
"strictMode": {
|
||||
"caseSensitiveCheck": true,
|
||||
"useNormalizedOHMUrl": true
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "debug",
|
||||
"signingConfig": "debug",
|
||||
"targetSdkVersion": "5.1.0(18)",
|
||||
"compatibleSdkVersion": "5.0.4(16)",
|
||||
"runtimeOS": "HarmonyOS",
|
||||
"buildOption": {
|
||||
"strictMode": {
|
||||
"caseSensitiveCheck": true,
|
||||
"useNormalizedOHMUrl": true
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"buildModeSet": [
|
||||
{
|
||||
"name": "debug",
|
||||
},
|
||||
{
|
||||
"name": "release",
|
||||
"buildOption": {
|
||||
"nativeLib": {
|
||||
"filter": {
|
||||
//根据正则表达式排除匹配到的.so文件,匹配到的so文件将不会被打包
|
||||
"excludes": [
|
||||
"**/x86_64/*.so",
|
||||
"**/armeabi-v7a/*.so"
|
||||
//排除所有x86_64架构的so文件
|
||||
],
|
||||
//允许当.so重名冲突时,使用高优先级的.so文件覆盖低优先级的.so文件
|
||||
"enableOverride": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"modules": [
|
||||
{
|
||||
"name": "entry",
|
||||
"srcPath": "./entry",
|
||||
"targets": [
|
||||
{
|
||||
"name": "default",
|
||||
"applyToProducts": [
|
||||
"default",
|
||||
"debug"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
{
|
||||
"files": [
|
||||
"**/*.ets"
|
||||
],
|
||||
"ignore": [
|
||||
"**/src/ohosTest/**/*",
|
||||
"**/src/test/**/*",
|
||||
"**/src/mock/**/*",
|
||||
"**/node_modules/**/*",
|
||||
"**/oh_modules/**/*",
|
||||
"**/build/**/*",
|
||||
"**/.preview/**/*"
|
||||
],
|
||||
"ruleSet": [
|
||||
"plugin:@performance/recommended",
|
||||
"plugin:@typescript-eslint/recommended"
|
||||
],
|
||||
"rules": {
|
||||
"@security/no-unsafe-aes": "error",
|
||||
"@security/no-unsafe-hash": "error",
|
||||
"@security/no-unsafe-mac": "warn",
|
||||
"@security/no-unsafe-dh": "error",
|
||||
"@security/no-unsafe-dsa": "error",
|
||||
"@security/no-unsafe-ecdsa": "error",
|
||||
"@security/no-unsafe-rsa-encrypt": "error",
|
||||
"@security/no-unsafe-rsa-sign": "error",
|
||||
"@security/no-unsafe-rsa-key": "error",
|
||||
"@security/no-unsafe-dsa-key": "error",
|
||||
"@security/no-unsafe-dh-key": "error",
|
||||
"@security/no-unsafe-3des": "error"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
/node_modules
|
||||
/oh_modules
|
||||
/.preview
|
||||
/build
|
||||
/.cxx
|
||||
/.test
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
{
|
||||
"apiType": "stageMode",
|
||||
"buildOption": {
|
||||
},
|
||||
"buildOptionSet": [
|
||||
{
|
||||
"name": "release",
|
||||
"arkOptions": {
|
||||
"obfuscation": {
|
||||
"ruleOptions": {
|
||||
"enable": false,
|
||||
"files": [
|
||||
"./obfuscation-rules.txt"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
],
|
||||
"targets": [
|
||||
{
|
||||
"name": "default"
|
||||
},
|
||||
{
|
||||
"name": "ohosTest",
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
import { hapTasks } from '@ohos/hvigor-ohos-plugin';
|
||||
|
||||
export default {
|
||||
system: hapTasks, /* Built-in plugin of Hvigor. It cannot be modified. */
|
||||
plugins:[] /* Custom plugin to extend the functionality of Hvigor. */
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
# Define project specific obfuscation rules here.
|
||||
# You can include the obfuscation configuration files in the current module's build-profile.json5.
|
||||
#
|
||||
# For more details, see
|
||||
# https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/source-obfuscation-V5
|
||||
|
||||
# Obfuscation options:
|
||||
# -disable-obfuscation: disable all obfuscations
|
||||
# -enable-property-obfuscation: obfuscate the property names
|
||||
# -enable-toplevel-obfuscation: obfuscate the names in the global scope
|
||||
# -compact: remove unnecessary blank spaces and all line feeds
|
||||
# -remove-log: remove all console.* statements
|
||||
# -print-namecache: print the name cache that contains the mapping from the old names to new names
|
||||
# -apply-namecache: reuse the given cache file
|
||||
|
||||
# Keep options:
|
||||
# -keep-property-name: specifies property names that you want to keep
|
||||
# -keep-global-name: specifies names that you want to keep in the global scope
|
||||
|
||||
-enable-property-obfuscation
|
||||
-enable-toplevel-obfuscation
|
||||
-enable-filename-obfuscation
|
||||
-enable-export-obfuscation
|
||||
-keep-property-name
|
||||
quickLoginAnonymousPhone
|
||||
|
||||
-keep
|
||||
./oh_modules/@ohos/imageknifepro
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
{
|
||||
"meta": {
|
||||
"stableOrder": true,
|
||||
"enableUnifiedLockfile": false
|
||||
},
|
||||
"lockfileVersion": 3,
|
||||
"ATTENTION": "THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.",
|
||||
"specifiers": {
|
||||
"@getui/gtc@../oh_modules/.ohpm/@getui+gysdk@1.0.10/oh_modules/@getui/gysdk/libs/GTC-HM-1.0.5-20241203.har": "@getui/gtc@../oh_modules/.ohpm/@getui+gysdk@1.0.10/oh_modules/@getui/gysdk/libs/GTC-HM-1.0.5-20241203.har",
|
||||
"@getui/gysdk@1.0.10": "@getui/gysdk@1.0.10",
|
||||
"@ohos/axios@^2.2.6": "@ohos/axios@2.2.6",
|
||||
"cmccssosdk@../oh_modules/.ohpm/@getui+gysdk@1.0.10/oh_modules/@getui/gysdk/libs/quick_login_hm_1.0.2.har": "cmccssosdk@../oh_modules/.ohpm/@getui+gysdk@1.0.10/oh_modules/@getui/gysdk/libs/quick_login_hm_1.0.2.har",
|
||||
"ctaccount@../oh_modules/.ohpm/@getui+gysdk@1.0.10/oh_modules/@getui/gysdk/libs/ctaccount_v1.1.2.har": "ctaccount@../oh_modules/.ohpm/@getui+gysdk@1.0.10/oh_modules/@getui/gysdk/libs/ctaccount_v1.1.2.har",
|
||||
"dljson@../oh_modules/.ohpm/ctaccount@qccjk9bmoqtng+2vpbi+2wqjznsjx4thqhodhlvlvn0=/oh_modules/ctaccount/library/dlJson.har": "dljson@../oh_modules/.ohpm/ctaccount@qccjk9bmoqtng+2vpbi+2wqjznsjx4thqhodhlvlvn0=/oh_modules/ctaccount/library/dlJson.har",
|
||||
"unicom_login_harmony@../oh_modules/.ohpm/@getui+gysdk@1.0.10/oh_modules/@getui/gysdk/libs/unicom_login_harmony_v1.0.4AR001B0214.har": "unicom_login_harmony@../oh_modules/.ohpm/@getui+gysdk@1.0.10/oh_modules/@getui/gysdk/libs/unicom_login_harmony_v1.0.4AR001B0214.har"
|
||||
},
|
||||
"packages": {
|
||||
"@getui/gtc@../oh_modules/.ohpm/@getui+gysdk@1.0.10/oh_modules/@getui/gysdk/libs/GTC-HM-1.0.5-20241203.har": {
|
||||
"name": "@getui/gtc",
|
||||
"version": "1.0.5",
|
||||
"resolved": "../oh_modules/.ohpm/@getui+gysdk@1.0.10/oh_modules/@getui/gysdk/libs/GTC-HM-1.0.5-20241203.har",
|
||||
"registryType": "local"
|
||||
},
|
||||
"@getui/gysdk@1.0.10": {
|
||||
"name": "@getui/gysdk",
|
||||
"version": "1.0.10",
|
||||
"integrity": "sha512-wsPJMEtrDgVi3uWizD1Yg96hkoK9uhPUzXkR6daNGsxHaf0bRtjg79aRDkE7o6xTHNyOVkPI/1l/5cDiZqbIow==",
|
||||
"resolved": "https://repo.harmonyos.com/ohpm/@getui/gysdk/-/gysdk-1.0.10.har",
|
||||
"registryType": "ohpm",
|
||||
"dependencies": {
|
||||
"@getui/gtc": "file:./libs/GTC-HM-1.0.5-20241203.har",
|
||||
"unicom_login_harmony": "file:./libs/unicom_login_harmony_v1.0.4AR001B0214.har",
|
||||
"cmccssosdk": "file:./libs/quick_login_hm_1.0.2.har",
|
||||
"ctaccount": "file:./libs/ctaccount_v1.1.2.har"
|
||||
}
|
||||
},
|
||||
"@ohos/axios@2.2.6": {
|
||||
"name": "@ohos/axios",
|
||||
"version": "2.2.6",
|
||||
"integrity": "sha512-A1JqGe6XaeqWyjQETitFW4EkubQS7Fv7h0YG5a/ry3/a/vOgVGzwC4y5KAhvMzVv1tYjfY0ntMtV2kJGlmOHcQ==",
|
||||
"resolved": "https://repo.harmonyos.com/ohpm/@ohos/axios/-/axios-2.2.6.har",
|
||||
"registryType": "ohpm"
|
||||
},
|
||||
"cmccssosdk@../oh_modules/.ohpm/@getui+gysdk@1.0.10/oh_modules/@getui/gysdk/libs/quick_login_hm_1.0.2.har": {
|
||||
"name": "cmccssosdk",
|
||||
"version": "1.0.0",
|
||||
"resolved": "../oh_modules/.ohpm/@getui+gysdk@1.0.10/oh_modules/@getui/gysdk/libs/quick_login_hm_1.0.2.har",
|
||||
"registryType": "local"
|
||||
},
|
||||
"ctaccount@../oh_modules/.ohpm/@getui+gysdk@1.0.10/oh_modules/@getui/gysdk/libs/ctaccount_v1.1.2.har": {
|
||||
"name": "ctaccount",
|
||||
"version": "1.1.2",
|
||||
"resolved": "../oh_modules/.ohpm/@getui+gysdk@1.0.10/oh_modules/@getui/gysdk/libs/ctaccount_v1.1.2.har",
|
||||
"registryType": "local",
|
||||
"dependencies": {
|
||||
"dljson": "file:library/dlJson.har"
|
||||
}
|
||||
},
|
||||
"dljson@../oh_modules/.ohpm/ctaccount@qccjk9bmoqtng+2vpbi+2wqjznsjx4thqhodhlvlvn0=/oh_modules/ctaccount/library/dlJson.har": {
|
||||
"name": "dljson",
|
||||
"version": "0.0.5",
|
||||
"resolved": "../oh_modules/.ohpm/ctaccount@qccjk9bmoqtng+2vpbi+2wqjznsjx4thqhodhlvlvn0=/oh_modules/ctaccount/library/dlJson.har",
|
||||
"registryType": "local"
|
||||
},
|
||||
"unicom_login_harmony@../oh_modules/.ohpm/@getui+gysdk@1.0.10/oh_modules/@getui/gysdk/libs/unicom_login_harmony_v1.0.4AR001B0214.har": {
|
||||
"name": "unicom_login_harmony",
|
||||
"version": "1.0.4",
|
||||
"resolved": "../oh_modules/.ohpm/@getui+gysdk@1.0.10/oh_modules/@getui/gysdk/libs/unicom_login_harmony_v1.0.4AR001B0214.har",
|
||||
"registryType": "local"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"name": "entry",
|
||||
"version": "1.0.0",
|
||||
"description": "Please describe the basic information.",
|
||||
"main": "",
|
||||
"author": "",
|
||||
"license": "",
|
||||
"dependencies": {
|
||||
"@ohos/axios": "^2.2.6",
|
||||
"@getui/gysdk": "1.0.10"
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
import { AbilityStage } from '@kit.AbilityKit';
|
||||
import { PrefUtils } from './utils/PrefUtils';
|
||||
|
||||
export default class MyAbilityStage extends AbilityStage {
|
||||
|
||||
onCreate(): void {
|
||||
PrefUtils.init(this.context)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
export declare class DialogCallback {
|
||||
confirm?: () => void;
|
||||
|
||||
cancel?: () => void;
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
export class Constants {
|
||||
static readonly BASE_URL = "https://material.u8t.cn" //正式地址
|
||||
static readonly TEST_URL = "https://material.u8t.cn" //测试地址
|
||||
|
||||
static readonly WEB_URL = "" //网页版地址
|
||||
|
||||
static readonly APP_ID = "10040"
|
||||
//
|
||||
static readonly WX_APP_ID = "wx19e5013ad43754c8" //微信APPID
|
||||
static readonly MINI_PROGRAM_APP_ID = "gh_b38277bd004a" //小程序
|
||||
static readonly UMENG_APP_KEY = "6883311979267e0210c15cb9" //友盟
|
||||
//
|
||||
static readonly USER_AGREEMENT = "https://material.u8t.cn/static/policy/user.html" //用户协议
|
||||
static readonly PRIVACY_POLICY = "https://material.u8t.cn/static/policy/provacy.html" //隐私政策
|
||||
static readonly RENEW_AGREEMENT = "https://material.u8t.cn/static/policy/renew.html" //自动续费协议
|
||||
//
|
||||
static readonly ENCRYPT = "wE8x4EnIHgyGOyjnoluzI2vk60wz5eNI"
|
||||
static readonly SIGNATURE = "hfLLOtXRjd0e1Ac7O6sAXrECH2E828S9"
|
||||
}
|
||||
|
|
@ -0,0 +1,272 @@
|
|||
export class EventConstants {
|
||||
/*---------------------------------------------APP事件---------------------------------------------*/
|
||||
static readonly LoginSuccessEvent = "LoginSuccessEvent"
|
||||
static readonly LogoutSuccessEvent = "LogoutSuccessEvent"
|
||||
static readonly HomeRefreshEvent = "HomeRefreshEvent"
|
||||
static readonly RecordRefreshEvent = "RecordRefreshEvent"
|
||||
static readonly MineRefreshEvent = "MineRefreshEvent"
|
||||
static readonly MediaActionEvent = "MediaActionEvent"
|
||||
static readonly JumpToRecordEvent = "JumpToRecordEvent"
|
||||
static readonly DownloadHistoryRefreshEvent = "DownloadHistoryRefreshEvent"
|
||||
|
||||
|
||||
/*-------------------------------------------客户端上报事件-------------------------------------------*/
|
||||
static readonly APP_LAUNCH = "client.launch" //app启动
|
||||
|
||||
static readonly GUIDE_LAUNCH = "client.guide.launch" //引导页启动
|
||||
|
||||
static readonly GUIDE_OPPORTUNITY_SCROLL = "client.guide.content.scroll" //滑动切换引导页内容
|
||||
|
||||
static readonly GUIDE_SKIP = "client.guide.pay.skip" //跳过引导页支付
|
||||
|
||||
static readonly APP_ACTIVE = "client.home.active" //app激活
|
||||
|
||||
static readonly HOME_BOTTOM_TAB_CHECK = "client.main.bottom.tab.check" //底部tab切换
|
||||
|
||||
static readonly HOME_NOTICE_CHECK = "client.main.notice.check" //首页通知点击
|
||||
|
||||
static readonly GOODS_SELECT = "client.goods.select" //点击切换支付的会员类型
|
||||
|
||||
static readonly PAY_SELECT = "client.pay.select" //点击切换支付类型
|
||||
|
||||
static readonly PAY_PAY = "client.pay.pay" //支付按钮点击
|
||||
|
||||
static readonly CHALLENGE_TASK_PAY_PAY = "client.challenge.task.pay.pay" //0元挑战支付按钮点击
|
||||
|
||||
static readonly PAY_SUCCESS = "client.pay.success" //支付成功
|
||||
|
||||
static readonly PAY_CANCEL = "client.pay.cancel" //支付取消
|
||||
|
||||
static readonly ERROR_CLIENT_WXPAY_ERR = "client.wxpay.err" //微信支付失败
|
||||
|
||||
static readonly ERROR_CLIENT_ALIPAY_ERR = "client.alipay.err" //支付宝支付失败
|
||||
|
||||
static readonly ERROR_CLIENT_DOWNLOAD_IMG = "client.download.img.err" //图片下载失败
|
||||
|
||||
static readonly ERROR_CLIENT_DOWNLOAD_VIDEO = "client.download.video.err" //视频下载失败
|
||||
|
||||
static readonly ERROR_CLIENT_DOWNLOAD_AUDIO = "client.download.audio.err" //音频下载失败
|
||||
|
||||
static readonly CANCEL_DOWNLOAD_VIDEO = "client.download.video.cancel" //取消视频下载
|
||||
|
||||
static readonly PAUSE_DOWNLOAD_VIDEO = "client.download.video.pause" //暂停视频下载
|
||||
|
||||
static readonly CONTINUE_DOWNLOAD_VIDEO = "client.download.video.continue" //继续视频下载
|
||||
|
||||
static readonly RESTART_DOWNLOAD_VIDEO = "client.download.video.restart" //重新视频下载
|
||||
|
||||
static readonly SPEED_UP_DOWNLOAD_VIDEO = "client.download.video.speed.up" //加速视频下载
|
||||
|
||||
static readonly BACKGROUND_CLIENT_DOWNLOAD = "client.download.background" //后台下载
|
||||
|
||||
static readonly FLOAT_WINDOW_CLICK = "client.float.window.click" //点击悬浮窗
|
||||
|
||||
static readonly PKG_UPDATE = "client.pkg.update" //升级弹窗点击更新
|
||||
|
||||
static readonly PKG_CANCEL = "client.pkg.cancel" //升级弹窗点击取消
|
||||
|
||||
static readonly GET_MATERIAL = "client.get.material" //获取素材
|
||||
|
||||
static readonly GET_MATERIAL_CANCEL = "client.get.material.cancel" //取消获取素材
|
||||
|
||||
static readonly DIALOG_CONFIRM_SAVE_FILE = "client.dialog.confirm.save.file" //保存文件地址弹框确认
|
||||
|
||||
static readonly DIALOG_GO_TO_VIEW = "client.dialog.go.to.view" //前往保存文件的地址查看
|
||||
|
||||
static readonly JUMP_TO_ABOUT_US = "client.jump.to.about.us" //界面跳转
|
||||
|
||||
static readonly JUMP_TO_LINK_EXTRACT = "client.jump.to.link.extract" //跳转链接提取
|
||||
|
||||
static readonly JUMP_TO_WECHAT_VIDEO = "client.jump.to.wechat.video" //跳转视频号
|
||||
|
||||
static readonly JUMP_TO_WECHAT_PLAYBACK = "client.jump.to.wechat.video.playback" //跳转直播回放
|
||||
|
||||
static readonly JUMP_TO_COURSE_WX_VIDEO = "client.course.wechat.video" //视频号视频教程
|
||||
|
||||
static readonly JUMP_TO_COURSE_PLAYBACK = "client.course.playback" //直播回放视频教程
|
||||
|
||||
static readonly JUMP_TO_HOME_TOOL = "client.jump.to.home.tool" //跳转首页工具
|
||||
|
||||
static readonly MAIN_CENTER_ENABLE = "client.main.center.enable" //首页跳转个人中心
|
||||
|
||||
static readonly JUMP_TO_MEMBER_RECHARGE = "client.jump.to.member.recharge" //跳转到充值页
|
||||
|
||||
static readonly JUMP_TO_LOGIN = "client.jump.to.login" //跳转到登录页
|
||||
|
||||
static readonly JUMP_TO_SYSTEM_SETTING = "client.jump.to.system.setting" //跳转到系统设置
|
||||
|
||||
static readonly JUMP_TO_USER_SETTING = "client.jump.to.user.setting" //跳转到用户设置
|
||||
|
||||
static readonly JUMP_TO_FEEDBACK = "client.jump.to.feedback" //跳转到意见反馈
|
||||
|
||||
static readonly JUMP_TO_ACCOUNT_BIND = "client.jump.to.account.bind" //跳转到账号绑定
|
||||
|
||||
static readonly JUMP_TO_ACCOUNT_MANAGE = "client.jump.to.account.manage" //跳转到账号管理
|
||||
|
||||
static readonly JUMP_TO_DOWNLOAD_HISTORY = "client.jump.to.download.history" //跳转到下载记录
|
||||
|
||||
static readonly JUMP_TO_DOWNLOAD_TASK_LIST = "client.jump.to.download.task.list" //跳转到下载任务列表
|
||||
|
||||
static readonly JUMP_TO_RECHARGE_DIAMOND = "client.jump.to.recharge.diamond" //跳转到钻石充值
|
||||
|
||||
static readonly JUMP_TO_COUPON_LIST = "client.jump.to.coupon.list" //跳转优惠券列表
|
||||
|
||||
static readonly JUMP_TO_CHALLENGE_TASK = "client.jump.to.challenge.task" //跳转到0元挑战
|
||||
|
||||
static readonly JUMP_TO_SHARE_WX_VIDEO = "client.jump.to.wechat.share.video" //跳转到视频号分享
|
||||
|
||||
static readonly JUMP_TO_SHARE_WX_PLAYBACK = "client.jump.to.wechat.share.playback" //跳转到直播回放分享
|
||||
|
||||
static readonly JUMP_TO_COURSE = "client.jump.to.course" //跳转到指导教程
|
||||
|
||||
static readonly DOWNLOAD_FILE = "client.download.file" //下载文件
|
||||
|
||||
static readonly TRANSPOND_FILE = "client.transpond.file" //转发文件
|
||||
|
||||
static readonly MATERIAL_COPY_TEXT = "client.material.copy.text" //复制文字
|
||||
|
||||
static readonly MATERIAL_TYPE_CHECK = "client.material.type.check" //素材切换
|
||||
|
||||
static readonly MATERIAL_ALL_SELECT = "client.material.all.select" //全部选中素材
|
||||
|
||||
static readonly MATERIAL_SELECT = "client.material.select" //选择素材
|
||||
|
||||
static readonly TOOLS_VIDEO_EXTRACT_AUDIO = "client.tools.video.audio" //提取音频
|
||||
|
||||
static readonly MATERIAL_PLAY_VIDEO = "client.material.play.video" //播发视频
|
||||
|
||||
static readonly GET_CODE = "client.get.code" //获取验证码
|
||||
|
||||
static readonly LOGIN = "client.login" //登录
|
||||
|
||||
static readonly SWITCH_ACCOUNT = "client.switch.account" //切换账户
|
||||
|
||||
static readonly ACCOUNT_BIND = "client.account.bind" //绑定账号
|
||||
|
||||
static readonly ACCOUNT_BIND_CANCEL = "client.account.bind.cancel" //取消绑定账号
|
||||
|
||||
static readonly CHECK_AGREEMENT = "client.check.agreement" //切换协议状态
|
||||
|
||||
static readonly VIEW_AGREEMENT = "client.view.agreement" //查看用户协议
|
||||
|
||||
static readonly PRIVACY_POLICY_CLICK_OK = "client.privacy.policy.click.ok" //同意隐私协议
|
||||
|
||||
static readonly SHARE_APP = "client.share.app" //分享app
|
||||
|
||||
static readonly CLEAR_CACHE = "client.clear.cache" //清除缓存
|
||||
|
||||
static readonly CONTACT_SERVICE = "client.contact.service" //联系客服
|
||||
|
||||
static readonly EXIT_LOGIN = "client.exit.login" //退出登录
|
||||
|
||||
static readonly CANCEL_ACCOUNT = "client.cancel.account" //注销账户
|
||||
|
||||
static readonly MEMBER_FORCE_LOGIN = "client.member.force.login" //会员强制登录
|
||||
|
||||
static readonly GET_MATERIAL_TIMES_USE_UP = "client.times.use.up.get.material" //获取素材次数已用完
|
||||
|
||||
static readonly PICTURE_HANDLE_TIMES_USE_UP = "client.times.use.up.picture.handle" //图片处理次数已用完
|
||||
|
||||
static readonly CHECK_LOGIN_TYPE = "client.check.login.type" //切换登录方式
|
||||
|
||||
static readonly OPEN_SCREEN_AD_SHOW = "client.ad.open.screen.show" //开屏广告展示
|
||||
|
||||
static readonly OPEN_SCREEN_AD_SKIP = "client.ad.open.screen.skip" //开屏广告跳过
|
||||
|
||||
static readonly OPEN_SCREEN_AD_CLICK = "client.ad.open.screen.click" //开屏广告点击
|
||||
|
||||
static readonly BANNER_AD_SHOW = "client.ad.banner.show" //banner广告展示
|
||||
|
||||
static readonly BANNER_AD_CLOSE = "client.ad.banner.close" //banner广告关闭
|
||||
|
||||
static readonly BANNER_AD_CLICK = "client.ad.banner.click" //banner广告点击
|
||||
|
||||
static readonly INSERT_SCREEN_AD_SHOW = "client.ad.insert.screen.show" //插屏广告展示
|
||||
|
||||
static readonly INSERT_SCREEN_AD_CLOSE = "client.ad.insert.screen.close" //插屏广告关闭
|
||||
|
||||
static readonly INSERT_SCREEN_AD_CLICK = "client.ad.insert.screen.click" //插屏广告点击
|
||||
|
||||
static readonly INSERT_SCREEN_AD_SKIP_VIDEO = "client.ad.insert.screen.skip.video" //跳过插屏广告
|
||||
|
||||
static readonly INCENTIVE_AD_SHOW = "client.ad.incentive.show" //激励广告展示
|
||||
|
||||
static readonly INCENTIVE_AD_CLOSE = "client.ad.incentive.close" //激励广告关闭
|
||||
|
||||
static readonly INCENTIVE_AD_REWARD = "client.ad.incentive.reward" //激励广告已获取到奖励
|
||||
|
||||
static readonly INCENTIVE_AD_SKIP_VIDEO = "client.ad.incentive.skip.video" //跳过激励广告
|
||||
|
||||
static readonly ACCOUNT_UNBIND = "client.account.unbind" //解除绑定账号
|
||||
|
||||
static readonly HISTORY_RECORD_TYPE_CHECK = "client.history.record.type.check" //历史记录切换
|
||||
|
||||
static readonly CLOSE_FREE_TIME_USES_UP_DIALOG =
|
||||
"client.free.time.uses.up.dialog.close" //关闭免费次数用完的提示框
|
||||
|
||||
static readonly CHECK_FREE_TIME_USES_UP_DIALOG =
|
||||
"client.free.time.uses.up.dialog.check" //免费次数用完的提示框切换充值类型
|
||||
|
||||
static readonly CONFIRM_FREE_TIME_USES_UP_DIALOG =
|
||||
"client.free.time.uses.up.dialog.confirm" //确认免费次数用完的提示框
|
||||
|
||||
static readonly MULTI_DELETE_FILE = "client.multi.delete.file" //批量删除文件
|
||||
|
||||
static readonly MULTI_TRANSMIT_FILE = "client.multi.transmit.file" //批量转发文件
|
||||
|
||||
static readonly PREVIEW_DELETE_FILE = "client.preview.delete.file" //预览时删除文件
|
||||
|
||||
static readonly PREVIEW_TRANSMIT_FILE = "client.preview.transmit.file" //预览时删除文件
|
||||
|
||||
static readonly PREVIEW_HANDLE_IMAGE = "client.preview.handle.image" //预览时进行图片处理
|
||||
|
||||
static readonly TOOLS_HANDLE_IMAGE_START = "client.tools.handle.image.start" //图片处理开始
|
||||
|
||||
static readonly TOOLS_HANDLE_SAVE_IMAGE = "client.tools.handle.save.image" //保存已处理过的图片至相册
|
||||
|
||||
static readonly AUTO_SWITCH_DOWNLOAD_URL = "client.auto.switch.download.url" //自动切换下载链接
|
||||
|
||||
static readonly HAND_SWITCH_DOWNLOAD_URL = "client.hand.switch.download.url" //手动切换下载链接立即加速
|
||||
|
||||
static readonly HOME_BANNER_CLICK = "client.home.banner.click"
|
||||
|
||||
static readonly COUPON_ANIMATION_PLAY = "client.coupon.animation.play" //播放优惠券动画
|
||||
|
||||
static readonly COUPON_ANIMATION_CLOSE = "client.coupon.animation.close" //关闭优惠券动画
|
||||
|
||||
static readonly COUPON_RECEIVE = "client.coupon.receive" //领取优惠券
|
||||
|
||||
static readonly COUPON_REDEEM_ENABLE = "client.coupon.redeem.enable" //优惠券兑换按钮点击
|
||||
|
||||
static readonly COUPON_REDEEM_INFO = "client.coupon.redeem.info" //优惠券兑换详情
|
||||
|
||||
static readonly COUPON_REDEEM = "client.coupon.redeem" //优惠券兑换
|
||||
|
||||
static readonly COUPON_REDEEM_SUCCESS = "client.coupon.redeem.success" //优惠券兑换成功
|
||||
|
||||
static readonly COUPON_REDEEM_SUCCESS_CONFIRM = "client.coupon.redeem.success.confirm" //优惠券兑换成功
|
||||
|
||||
static readonly COUPON_VIEW = "client.coupon.view" //查看优惠券
|
||||
|
||||
static readonly COUPON_DIALOG_CHECK = "client.coupon.dialog.check" //切换优惠券
|
||||
|
||||
static readonly COUPON_DIALOG_CLOSE = "client.coupon.dialog.close" //关闭优惠券
|
||||
|
||||
static readonly COUPON_DIALOG_CONFIRM = "client.coupon.dialog.confirm" //确认优惠券
|
||||
|
||||
static readonly COPY_USER_ID = "client.copy_user_id" //复制用户id
|
||||
|
||||
static readonly SHOW_PALYBACK_HINT_DIALOG = "client.show.playback.hint.dialog"
|
||||
|
||||
static readonly EXIT_APP = "client.exit.app" //退出APP
|
||||
|
||||
static readonly SHOW_DIALOG = "client.show.dialog" //弹出退出app的弹框
|
||||
|
||||
static readonly START_COUPON_ANIMATION = "client.start.coupon.animation"
|
||||
|
||||
static readonly CHALLENGE_TASK_SIGN_IN = "client.challenge.tasK.sign.in" //签到
|
||||
|
||||
static readonly CHALLENGE_TASK_SIGN_IN_SUCCESS = "client.challenge.tasK.sign.in.success" //签到成功
|
||||
|
||||
static readonly CHALLENGE_TASK_SIGN_IN_FAIL = "client.challenge.tasK.sign.in.fail" //签到失败
|
||||
}
|
||||
|
|
@ -0,0 +1,146 @@
|
|||
export class RouterUrls {
|
||||
/**
|
||||
* 通用web加载页
|
||||
*/
|
||||
static readonly WEB_PAGE = "pages/web/WebPage"
|
||||
|
||||
/**
|
||||
* 引导页
|
||||
*/
|
||||
static readonly GUIDE_PAGE = "pages/guide/GuidePage"
|
||||
|
||||
/**
|
||||
* 登录页
|
||||
*/
|
||||
static readonly LOGIN_PAGE = "pages/login/LoginPage"
|
||||
|
||||
/**
|
||||
* 扫码登录页
|
||||
*/
|
||||
static readonly QRCODE_LOGIN_PAGE = "pages/login/qrcode/QrcodeLoginPage"
|
||||
|
||||
/**
|
||||
* 主页
|
||||
*/
|
||||
static readonly MAIN_PAGE = "pages/main/MainPage"
|
||||
|
||||
/**
|
||||
* 链接提取页
|
||||
*/
|
||||
static readonly TAKE_MATERIAL_PAGE = "pages/main/home/link/TakeMaterialPage"
|
||||
|
||||
/**
|
||||
* 提取教程页
|
||||
*/
|
||||
static readonly COURSE_PAGE = "pages/main/home/course/CoursePage"
|
||||
|
||||
/**
|
||||
* 视频号提取页
|
||||
*/
|
||||
static readonly WX_VIDEO_PAGE = "pages/main/home/wx/WxVideoPage"
|
||||
|
||||
/**
|
||||
* 添加水印页
|
||||
*/
|
||||
static readonly ADD_WATER_MARKER_PAGE = "pages/main/home/tools/AddWaterMarkerPage"
|
||||
|
||||
/**
|
||||
* MD5去重页
|
||||
*/
|
||||
static readonly MD5_RESET_PAGE = "pages/main/home/tools/MD5ResetPage"
|
||||
|
||||
/**
|
||||
* 视频倒放页
|
||||
*/
|
||||
static readonly VIDEO_REVERSE_PAGE = "pages/main/home/tools/VideoReversePage"
|
||||
|
||||
/**
|
||||
* 视频裁剪页
|
||||
*/
|
||||
static readonly VIDEO_MIRROR_PAGE = "pages/main/home/tools/VideoMirrorPage"
|
||||
|
||||
/**
|
||||
* 视频裁剪页
|
||||
*/
|
||||
static readonly CLIP_VIDEO_PAGE = "pages/main/home/tools/ClipVideoPage"
|
||||
|
||||
/**
|
||||
* 去除音乐页
|
||||
*/
|
||||
static readonly REMOVE_AUDIO_PAGE = "pages/main/home/tools/RemoveAudioPage"
|
||||
|
||||
/**
|
||||
* 添加音乐页
|
||||
*/
|
||||
static readonly ADD_AUDIO_PAGE = "pages/main/home/tools/AddAudioPage"
|
||||
|
||||
/**
|
||||
* 视频转音频页
|
||||
*/
|
||||
static readonly TAKE_AUDIO_PAGE = "pages/main/home/tools/TakeAudioPage"
|
||||
|
||||
/**
|
||||
* 素材详情页
|
||||
*/
|
||||
static readonly MATERIAL_DETAIL_PAGE = "pages/main/home/material/MaterialDetailPage"
|
||||
|
||||
/**
|
||||
* 用户设置页
|
||||
*/
|
||||
static readonly USER_SETTINGS_PAGE = "pages/main/mine/user/UserSettingsPage"
|
||||
|
||||
/**
|
||||
* vip页
|
||||
*/
|
||||
static readonly VIP_PAGE = "pages/main/mine/vip/VipPage"
|
||||
|
||||
/**
|
||||
* 下载记录页
|
||||
*/
|
||||
static readonly DOWNLOAD_HISTORY_PAGE = "pages/main/mine/history/DownloadHistoryPage"
|
||||
|
||||
/**
|
||||
* 钻石充值页
|
||||
*/
|
||||
static readonly RECHARGE_DIAMOND_PAGE = "pages/main/mine/diamond/DiamondPage"
|
||||
|
||||
/**
|
||||
* 设置页
|
||||
*/
|
||||
static readonly SETTING_PAGE = "pages/main/mine/setting/SettingsPage"
|
||||
|
||||
/**
|
||||
* 意见反馈页
|
||||
*/
|
||||
static readonly FEEDBACK_PAGE = "pages/main/mine/setting/feedback/FeedbackPage"
|
||||
|
||||
/**
|
||||
* 关于页
|
||||
*/
|
||||
static readonly ABOUT_PAGE = "pages/main/mine/setting/about/AboutPage"
|
||||
|
||||
/**
|
||||
* 账号绑定页
|
||||
*/
|
||||
static readonly BIND_ACCOUNT_PAGE = "pages/main/mine/setting/account/BindAccountPage"
|
||||
|
||||
/**
|
||||
* 账号管理页
|
||||
*/
|
||||
static readonly MANAGE_ACCOUNT_PAGE = "pages/main/mine/setting/account/ManageAccountPage"
|
||||
|
||||
/**
|
||||
* 视频播放页
|
||||
*/
|
||||
static readonly VIDEO_PLAYER_PAGE = "pages/video/VideoPlayerPage"
|
||||
|
||||
/**
|
||||
* 音频播放页
|
||||
*/
|
||||
static readonly AUDIO_PLAYER_PAGE = "pages/audio/AudioPlayerPage"
|
||||
|
||||
/**
|
||||
* 图片查看页
|
||||
*/
|
||||
static readonly PHOTO_VIEW_PAGE = "pages/photo/PhotoViewPage"
|
||||
}
|
||||
|
|
@ -0,0 +1,205 @@
|
|||
import { StrUtil } from '@pura/harmony-utils';
|
||||
import { plainToInstance } from 'class-transformer';
|
||||
import { SendCodeEntity } from '../entity/SendCodeEntity';
|
||||
import { apiService } from '../net/ApiService';
|
||||
import { HttpResult } from '../net/HttpResult';
|
||||
import { ToastUtils } from '../utils/ToastUtils';
|
||||
import { LoadingDialog } from './LoadingDialog';
|
||||
|
||||
@CustomDialog
|
||||
export struct BindPhoneDialog {
|
||||
controller: CustomDialogController;
|
||||
|
||||
success: () => void = () => {}
|
||||
|
||||
phone: string = '';
|
||||
code: string = '';
|
||||
timestamp: string = '';
|
||||
intervalId: number = -1;
|
||||
|
||||
@State countDownTime: number = 0;
|
||||
|
||||
build() {
|
||||
RelativeContainer() {
|
||||
Text('绑定手机号')
|
||||
.width('auto')
|
||||
.fontColor($r('app.color.color_90ffffff'))
|
||||
.fontSize(16)
|
||||
.fontWeight(FontWeight.Medium)
|
||||
.alignRules({
|
||||
top: { anchor: '__container__', align: VerticalAlign.Top },
|
||||
left: { anchor: '__container__', align: HorizontalAlign.Start },
|
||||
right: { anchor: '__container__', align: HorizontalAlign.End },
|
||||
})
|
||||
.margin({ top: 18 })
|
||||
.id('tv_title')
|
||||
|
||||
Image($r('app.media.ic_close'))
|
||||
.width(20)
|
||||
.height(20)
|
||||
.alignRules({
|
||||
top: { anchor: '__container__', align: VerticalAlign.Top },
|
||||
right: { anchor: '__container__', align: HorizontalAlign.End }
|
||||
})
|
||||
.margin({ top: 12, right: 12 })
|
||||
.onClick(() => {
|
||||
this.controller.close();
|
||||
})
|
||||
|
||||
TextInput({ placeholder: '请输入手机号' })
|
||||
.height(48)
|
||||
.type(InputType.PhoneNumber)
|
||||
.fontColor($r('app.color.color_90ffffff'))
|
||||
.fontSize(15)
|
||||
.placeholderColor($r('app.color.color_30ffffff'))
|
||||
.placeholderFont({ size: 15 })
|
||||
.maxLength(11)
|
||||
.backgroundColor($r('app.color.color_222222'))
|
||||
.borderRadius(8)
|
||||
.margin({ top: 20, left: 16, right: 16 })
|
||||
.alignRules({
|
||||
top: { anchor: 'tv_title', align: VerticalAlign.Bottom }
|
||||
})
|
||||
.id('et_phone')
|
||||
.onChange((value: string) => {
|
||||
this.phone = value;
|
||||
})
|
||||
|
||||
Row() {
|
||||
TextInput({ placeholder: '请输入验证码' })
|
||||
.height(48)
|
||||
.type(InputType.Number)
|
||||
.fontColor($r('app.color.color_90ffffff'))
|
||||
.fontSize(15)
|
||||
.placeholderColor($r('app.color.color_30ffffff'))
|
||||
.placeholderFont({ size: 15 })
|
||||
.maxLength(6)
|
||||
.backgroundColor($r('app.color.color_222222'))
|
||||
.borderRadius(8)
|
||||
.margin({ left: 16, right: 12 })
|
||||
.id('et_code')
|
||||
.onChange((value: string) => {
|
||||
this.code = value;
|
||||
})
|
||||
.layoutWeight(1)
|
||||
|
||||
Text(this.countDownTime === 0 && StrUtil.isEmpty(this.timestamp) ? '获取验证码' : this.countDownTime > 0 ? `${this.countDownTime}s` : '重新发送')
|
||||
.width(110)
|
||||
.height(48)
|
||||
.textAlign(TextAlign.Center)
|
||||
.fontColor($r("app.color.color_466afd"))
|
||||
.fontSize(15)
|
||||
.backgroundColor($r('app.color.color_222222'))
|
||||
.borderRadius(8)
|
||||
.margin({ right: 16 })
|
||||
.onClick(() => {
|
||||
this.sendCode(this.phone);
|
||||
})
|
||||
}
|
||||
.alignRules({
|
||||
top: { anchor: 'et_phone', align: VerticalAlign.Bottom }
|
||||
})
|
||||
.margin({ top: 14 })
|
||||
.id('layout_code')
|
||||
|
||||
Stack() {
|
||||
Button('确定', { type: ButtonType.Capsule, stateEffect: true })
|
||||
.width('100%')
|
||||
.height(46)
|
||||
.fontColor(Color.White)
|
||||
.fontSize(15)
|
||||
.fontWeight(FontWeight.Medium)
|
||||
.linearGradient({
|
||||
colors: [['#F62C6C', 0.0], ['#FC4F54', 1.0]],
|
||||
direction: GradientDirection.Right
|
||||
})
|
||||
.onClick(() => {
|
||||
this.bindPhone();
|
||||
})
|
||||
}
|
||||
.padding({ left: 16, right: 16 })
|
||||
.margin({ top: 55 })
|
||||
.alignRules({
|
||||
top: { anchor: 'layout_code', align: VerticalAlign.Bottom }
|
||||
})
|
||||
}
|
||||
.width('100%')
|
||||
.height(320)
|
||||
.borderRadius(20)
|
||||
.backgroundColor($r('app.color.window_background'))
|
||||
}
|
||||
|
||||
sendCode(phone: string) {
|
||||
if (StrUtil.isEmpty(this.phone)) {
|
||||
ToastUtils.show('请输入手机号');
|
||||
return;
|
||||
}
|
||||
if (this.phone.length != 11) {
|
||||
ToastUtils.show('请输入正确的手机号');
|
||||
return;
|
||||
}
|
||||
LoadingDialog.show(this.getUIContext());
|
||||
try {
|
||||
apiService.sendCode(phone)
|
||||
.then((result: HttpResult) => {
|
||||
if (result.isSuccess()) {
|
||||
ToastUtils.show('验证码已发送');
|
||||
const codeEntity = plainToInstance(SendCodeEntity, result.data);
|
||||
this.timestamp = codeEntity.timestamp;
|
||||
this.countDownTime = 60;
|
||||
this.intervalId = setInterval(() => {
|
||||
if (this.countDownTime > 0) {
|
||||
this.countDownTime--
|
||||
} else {
|
||||
if (this.intervalId !== 0) {
|
||||
clearInterval(this.intervalId);
|
||||
}
|
||||
}
|
||||
}, 1000)
|
||||
} else {
|
||||
ToastUtils.show(result.message, true);
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
LoadingDialog.dismiss();
|
||||
})
|
||||
} catch (e) {
|
||||
LoadingDialog.dismiss();
|
||||
console.log(e);
|
||||
ToastUtils.show(e);
|
||||
}
|
||||
}
|
||||
|
||||
bindPhone() {
|
||||
if (StrUtil.isEmpty(this.phone)) {
|
||||
ToastUtils.show('请输入手机号');
|
||||
return;
|
||||
}
|
||||
if (this.phone.length != 11) {
|
||||
ToastUtils.show('请输入正确的手机号');
|
||||
return;
|
||||
}
|
||||
if (StrUtil.isEmpty(this.code)) {
|
||||
ToastUtils.show('请输入验证码');
|
||||
return;
|
||||
}
|
||||
LoadingDialog.show(this.getUIContext());
|
||||
try {
|
||||
apiService.loginByPhone(this.phone, this.code, this.timestamp, true)
|
||||
.then((result: HttpResult) => {
|
||||
if (result.isSuccess()) {
|
||||
ToastUtils.show('绑定成功');
|
||||
this.controller.close();
|
||||
this.success();
|
||||
} else {
|
||||
ToastUtils.show(result.message, true)
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
LoadingDialog.dismiss();
|
||||
})
|
||||
} catch (e) {
|
||||
LoadingDialog.dismiss();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
import { DiamondRuleEntity } from "../entity/DiamondRuleEntity";
|
||||
import { DiamondRuleItemView } from "../view/DiamondRuleItemView";
|
||||
|
||||
@CustomDialog
|
||||
export struct DiamondRuleDialog {
|
||||
controller: CustomDialogController;
|
||||
|
||||
build() {
|
||||
RelativeContainer() {
|
||||
Image($r('app.media.ic_diamond_rule_top_bg')).width('100%').aspectRatio(1.811)
|
||||
|
||||
Image($r('app.media.ic_diamond_rule_indicator')).width(86).height(16)
|
||||
.alignRules({
|
||||
left: {anchor: 'tv_title', align: HorizontalAlign.Start},
|
||||
right: {anchor: 'tv_title', align: HorizontalAlign.End},
|
||||
bottom: {anchor: 'tv_title', align: VerticalAlign.Bottom}
|
||||
})
|
||||
.margin({left: -8, bottom: -4})
|
||||
Text('规则说明').fontColor($r('app.color.color_1a1a1a')).fontSize(20).fontFamily('almmsht').id('tv_title')
|
||||
.alignRules({
|
||||
left: {anchor: '__container__', align: HorizontalAlign.Start},
|
||||
right: {anchor: '__container__', align: HorizontalAlign.End}
|
||||
})
|
||||
.width('auto')
|
||||
.margin({top: 20})
|
||||
|
||||
Image($r('app.media.ic_close2')).width(24).height(24)
|
||||
.alignRules({
|
||||
top: {anchor: 'tv_title', align: VerticalAlign.Top},
|
||||
right: {anchor: '__container__', align: HorizontalAlign.End},
|
||||
bottom: {anchor: 'tv_title', align: VerticalAlign.Bottom}
|
||||
})
|
||||
.margin({right: 16})
|
||||
.onClick(() => {
|
||||
this.controller.close()
|
||||
})
|
||||
|
||||
List({space: 20}) {
|
||||
ForEach(DiamondRuleEntity.getRuleList(), (item: DiamondRuleEntity) => {
|
||||
ListItem() {
|
||||
DiamondRuleItemView({entity: item})
|
||||
}
|
||||
})
|
||||
}
|
||||
.width('auto')
|
||||
.height('auto')
|
||||
.margin({left: 16, top: 24, right: 16, bottom: 30})
|
||||
.backgroundColor(Color.White)
|
||||
.borderRadius(10)
|
||||
.padding({left: 16, top: 20, right: 16, bottom: 20})
|
||||
.alignRules({
|
||||
top: {anchor: 'tv_title', align: VerticalAlign.Bottom}
|
||||
})
|
||||
}
|
||||
.width('100%')
|
||||
.height('auto')
|
||||
.backgroundColor('#F6F6F6')
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,220 @@
|
|||
import { ComponentContent } from '@kit.ArkUI';
|
||||
import { AppUtil, DisplayUtil, FileUtil, FormatUtil, NumberUtil, StrUtil, WindowUtil } from '@pura/harmony-utils';
|
||||
import { DialogCallback } from '../callback/DialogCallback';
|
||||
|
||||
export enum DownloadStatus {
|
||||
COMPLETED,
|
||||
DOWNLOADING,
|
||||
VIDEO_DOWNLOADING,
|
||||
AUDIO_DOWNLOADING,
|
||||
PROCESSING,
|
||||
PROCESSING_PROGRESS,
|
||||
TAKING
|
||||
}
|
||||
|
||||
export declare class DownloadDialogOption {
|
||||
status: DownloadStatus
|
||||
totalSize: number
|
||||
progress: number
|
||||
totalCount: number
|
||||
index: number
|
||||
isAudio?: boolean
|
||||
callback?: DialogCallback
|
||||
}
|
||||
|
||||
@Builder
|
||||
function defaultBuilder(option: DownloadDialogOption) {
|
||||
Column() {
|
||||
Text((option.status === DownloadStatus.DOWNLOADING ? '下载中' :
|
||||
option.status === DownloadStatus.VIDEO_DOWNLOADING ? '视频下载中' :
|
||||
option.status === DownloadStatus.AUDIO_DOWNLOADING ? '音频下载中' : '处理中') +
|
||||
(option.totalCount > 1 ? ` ${option.index + 1}/${option.totalCount}` : ''))
|
||||
.fontColor($r('app.color.color_90ffffff'))
|
||||
.fontSize(16)
|
||||
.visibility(option.status === DownloadStatus.COMPLETED ? Visibility.None : Visibility.Visible)
|
||||
|
||||
Image(option.status === DownloadStatus.COMPLETED ? $r('app.media.ic_completed') : $r('app.media.ic_downloading'))
|
||||
.width(80)
|
||||
.height(80)
|
||||
.margin({ top: 20 })
|
||||
|
||||
Stack() {
|
||||
Column() {
|
||||
Stack({ alignContent: Alignment.Start }) {
|
||||
Progress({ value: option.progress, total: option.totalSize, type: ProgressType.Linear })
|
||||
.width('100%')
|
||||
.style({ strokeWidth: 12, strokeRadius: 6 })
|
||||
.color('#FC4F54')
|
||||
.colorBlend($r('app.color.color_10ffffff'))
|
||||
.borderRadius(6)
|
||||
|
||||
Text(FormatUtil.getFormatPercentage(option.progress / option.totalSize, 1))
|
||||
.width(40)
|
||||
.height(18)
|
||||
.textAlign(TextAlign.Center)
|
||||
.fontColor(Color.White)
|
||||
.fontSize(10)
|
||||
.borderRadius(10)
|
||||
.borderWidth(1)
|
||||
.borderColor($r('app.color.color_80ffffff'))
|
||||
.backgroundColor($r("app.color.color_466afd"))
|
||||
.translate({ x: (AppUtil.getUIContext().px2vp(DisplayUtil.getWidth()) * 0.8 - 80) * option.progress / option.totalSize })
|
||||
}
|
||||
|
||||
Text(`${FileUtil.getFormatFileSize(option.progress)}/${option.totalSize !== 0 ?
|
||||
FileUtil.getFormatFileSize(option.totalSize) : '获取中'}`)
|
||||
.fontColor($r('app.color.color_999999'))
|
||||
.fontSize(12)
|
||||
.margin({ top: 16 })
|
||||
.visibility(option.status === DownloadStatus.PROCESSING ? Visibility.Hidden : Visibility.Visible)
|
||||
|
||||
Row() {
|
||||
Button('取消下载', { type: ButtonType.Capsule, stateEffect: true })
|
||||
.width(110)
|
||||
.height(36)
|
||||
.backgroundColor($r('app.color.color_333333'))
|
||||
.fontColor($r('app.color.color_50ffffff'))
|
||||
.fontSize(15)
|
||||
.onClick(() => {
|
||||
if (option.callback?.cancel) {
|
||||
option.callback.cancel()
|
||||
}
|
||||
DownloadDialog.dismiss()
|
||||
})
|
||||
|
||||
Button('后台下载', { type: ButtonType.Capsule, stateEffect: true })
|
||||
.width(110)
|
||||
.height(36)
|
||||
.linearGradient({
|
||||
colors: [['#F62C6C', 0.0], ['#FC4F54', 1.0]],
|
||||
direction: GradientDirection.Right
|
||||
})
|
||||
.fontColor($r('app.color.color_90ffffff'))
|
||||
.fontSize(15)
|
||||
.margin({ left: 10 })
|
||||
.onClick(() => {
|
||||
if (option.callback?.confirm) {
|
||||
option.callback.confirm()
|
||||
}
|
||||
DownloadDialog.dismiss()
|
||||
})
|
||||
.visibility(Visibility.None)
|
||||
}
|
||||
.margin({ top: 16 })
|
||||
}
|
||||
.margin({ top: 20 })
|
||||
.visibility(option.status === DownloadStatus.COMPLETED ? Visibility.None : Visibility.Visible)
|
||||
|
||||
Column() {
|
||||
Text(option.isAudio ? '已保存到本地' : '已保存到系统相册中').fontColor($r('app.color.color_90ffffff')).fontSize(16)
|
||||
|
||||
Text(option.isAudio ? '文件管理/我的手机/Download/素材魔方' : '文件管理/我的手机/Download/图库')
|
||||
.fontColor($r('app.color.color_999999'))
|
||||
.fontSize(12)
|
||||
.margin({ top: 10 })
|
||||
|
||||
Row() {
|
||||
Button('取消', { type: ButtonType.Capsule, stateEffect: true })
|
||||
.width(110)
|
||||
.height(36)
|
||||
.backgroundColor($r('app.color.color_333333'))
|
||||
.fontColor($r('app.color.color_50ffffff'))
|
||||
.fontSize(15)
|
||||
.onClick(() => {
|
||||
if (option.callback?.cancel) {
|
||||
option.callback.cancel()
|
||||
}
|
||||
DownloadDialog.dismiss()
|
||||
})
|
||||
|
||||
Blank().width(10)
|
||||
|
||||
Button('前往查看', { type: ButtonType.Capsule, stateEffect: true })
|
||||
.width(110)
|
||||
.height(36)
|
||||
.linearGradient({
|
||||
colors: [['#F62C6C', 0.0], ['#FC4F54', 1.0]],
|
||||
direction: GradientDirection.Right
|
||||
})
|
||||
.fontColor($r('app.color.color_90ffffff'))
|
||||
.fontSize(15)
|
||||
.onClick(() => {
|
||||
if (option.callback?.confirm) {
|
||||
option.callback.confirm()
|
||||
}
|
||||
DownloadDialog.dismiss()
|
||||
})
|
||||
}
|
||||
.margin({ top: 16 })
|
||||
}
|
||||
.margin({ top: 20 })
|
||||
.visibility(option.status === DownloadStatus.COMPLETED ? Visibility.Visible : Visibility.None)
|
||||
}
|
||||
}
|
||||
.width('80%')
|
||||
.borderRadius(10)
|
||||
.backgroundColor($r('app.color.color_222222'))
|
||||
.padding(20)
|
||||
}
|
||||
|
||||
export class DownloadDialog {
|
||||
context: UIContext | null = null;
|
||||
contentNode: ComponentContent<Object> | null = null;
|
||||
confirm?: () => void;
|
||||
cancel?: () => void;
|
||||
|
||||
private static instance: DownloadDialog | null = null;
|
||||
|
||||
static show(context: UIContext, option: DownloadDialogOption) {
|
||||
if (DownloadDialog.instance === null) {
|
||||
DownloadDialog.instance = new DownloadDialog(context, option);
|
||||
}
|
||||
DownloadDialog.instance?.openDialog();
|
||||
}
|
||||
|
||||
static update(option: DownloadDialogOption) {
|
||||
DownloadDialog.instance?.updateDialog(option);
|
||||
}
|
||||
|
||||
static dismiss() {
|
||||
if (DownloadDialog.instance !== null) {
|
||||
DownloadDialog.instance.closeDialog();
|
||||
DownloadDialog.instance = null;
|
||||
}
|
||||
}
|
||||
|
||||
constructor(context: UIContext, option: DownloadDialogOption) {
|
||||
this.context = context;
|
||||
this.confirm = option.callback?.confirm
|
||||
this.cancel = option.callback?.cancel
|
||||
this.contentNode = new ComponentContent(context, wrapBuilder(defaultBuilder), option);
|
||||
}
|
||||
|
||||
|
||||
openDialog() {
|
||||
if (this.context !== null && this.contentNode !== null) {
|
||||
this.context.getPromptAction().openCustomDialog(this.contentNode, {
|
||||
onWillDismiss: () => {
|
||||
return false
|
||||
}
|
||||
})
|
||||
.then(() => {
|
||||
console.info('OpenCustomDialog complete.');
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
closeDialog() {
|
||||
if (this.context !== null && this.contentNode !== null) {
|
||||
this.context.getPromptAction().closeCustomDialog(this.contentNode)
|
||||
.then(() => {
|
||||
console.info('CloseCustomDialog complete.');
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
updateDialog(option: DownloadDialogOption) {
|
||||
option.callback = { confirm: this.confirm, cancel: this.cancel }
|
||||
this.contentNode?.update(option);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,128 @@
|
|||
import { ComponentContent } from '@kit.ArkUI';
|
||||
import { StrUtil } from '@pura/harmony-utils';
|
||||
import { DialogCallback } from '../callback/DialogCallback';
|
||||
import { ToastUtils } from '../utils/ToastUtils';
|
||||
|
||||
export declare class EditTextDialogOption {
|
||||
title?: string;
|
||||
content?: string;
|
||||
hintText?: string;
|
||||
confirm?: (content: string) => void;
|
||||
}
|
||||
|
||||
@Builder
|
||||
function defaultBuilder(option: EditTextDialogOption) {
|
||||
Column() {
|
||||
RelativeContainer() {
|
||||
Text(option.title ?? '编辑')
|
||||
.width('auto')
|
||||
.fontColor($r('app.color.color_90ffffff'))
|
||||
.fontSize(18)
|
||||
.fontWeight(FontWeight.Medium)
|
||||
.alignRules( {
|
||||
left: {anchor: '__container__', align: HorizontalAlign.Start},
|
||||
right: {anchor: '__container__', align: HorizontalAlign.End}
|
||||
})
|
||||
|
||||
Image($r('app.media.ic_close')).width(20).height(20)
|
||||
.alignRules( {
|
||||
top: {anchor: '__container__', align: VerticalAlign.Top},
|
||||
right: {anchor: '__container__', align: HorizontalAlign.End}
|
||||
})
|
||||
.margin({ right: 16 })
|
||||
.onClick(() => {
|
||||
EditTextDialog.dismiss()
|
||||
})
|
||||
}
|
||||
.width('100%')
|
||||
.height(30)
|
||||
|
||||
TextInput({ placeholder: option.hintText ?? '请输入', text: option.content})
|
||||
.width('90%')
|
||||
.height(48)
|
||||
.fontColor($r('app.color.color_90ffffff'))
|
||||
.fontSize(15)
|
||||
.placeholderColor($r('app.color.color_30ffffff'))
|
||||
.placeholderFont({ size: 15 })
|
||||
.maxLength(12)
|
||||
.backgroundColor($r('app.color.color_222222'))
|
||||
.borderRadius(8)
|
||||
.margin({ top: 16 })
|
||||
.onChange((content) => {
|
||||
option.content = content
|
||||
})
|
||||
|
||||
Button('确定', { type: ButtonType.Capsule, stateEffect: true })
|
||||
.fontColor(Color.White)
|
||||
.fontSize(16)
|
||||
.linearGradient({
|
||||
colors: [['#F62C6C', 0.0], ['#FC4F54', 1.0]],
|
||||
direction: GradientDirection.Right
|
||||
})
|
||||
.width('90%')
|
||||
.height(46)
|
||||
.margin({ top: 30 })
|
||||
.onClick(() => {
|
||||
if (StrUtil.isEmpty(option.content)) {
|
||||
ToastUtils.show('内容不能为空')
|
||||
} else {
|
||||
if (option.confirm) {
|
||||
option.confirm(option.content!!);
|
||||
}
|
||||
EditTextDialog.dismiss();
|
||||
}
|
||||
})
|
||||
}
|
||||
.padding({ top: 22, bottom: 22 })
|
||||
.borderRadius(20)
|
||||
.backgroundColor($r('app.color.window_background'))
|
||||
.width('100%')
|
||||
}
|
||||
|
||||
export class EditTextDialog {
|
||||
context: UIContext | null = null;
|
||||
contentNode: ComponentContent<Object> | null = null;
|
||||
|
||||
private static instance: EditTextDialog | null = null;
|
||||
|
||||
static show(context: UIContext, option: EditTextDialogOption) {
|
||||
if (EditTextDialog.instance === null) {
|
||||
EditTextDialog.instance = new EditTextDialog(context, option);
|
||||
}
|
||||
EditTextDialog.instance?.openDialog();
|
||||
}
|
||||
|
||||
static dismiss() {
|
||||
if (EditTextDialog.instance !== null) {
|
||||
EditTextDialog.instance.closeDialog();
|
||||
EditTextDialog.instance = null;
|
||||
}
|
||||
}
|
||||
|
||||
constructor(context: UIContext, option: EditTextDialogOption) {
|
||||
this.context = context;
|
||||
this.contentNode = new ComponentContent(context, wrapBuilder(defaultBuilder), option);
|
||||
}
|
||||
|
||||
openDialog() {
|
||||
if (this.context !== null && this.contentNode !== null) {
|
||||
this.context.getPromptAction().openCustomDialog(this.contentNode, {
|
||||
maskColor: '#CC000000',
|
||||
autoCancel: false,
|
||||
alignment: DialogAlignment.Bottom
|
||||
})
|
||||
.then(() => {
|
||||
console.info('OpenCustomDialog complete.');
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
closeDialog() {
|
||||
if (this.context !== null && this.contentNode !== null) {
|
||||
this.context.getPromptAction().closeCustomDialog(this.contentNode)
|
||||
.then(() => {
|
||||
console.info('CloseCustomDialog complete.');
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,179 @@
|
|||
import { BusinessError, request } from '@kit.BasicServicesKit';
|
||||
import { AppUtil, FileUtil, PasteboardUtil } from '@pura/harmony-utils';
|
||||
import { ToastUtils } from '../utils/ToastUtils';
|
||||
import { SaveUtils } from '../utils/SaveUtils';
|
||||
import { LoginManager } from '../manager/LoginGlobalManager';
|
||||
import { Want } from '@kit.AbilityKit';
|
||||
import { WXApi } from '../utils/wechat/WXApiEventHandlerImpl';
|
||||
|
||||
@CustomDialog
|
||||
export struct JoinWxGroupCourseDialog {
|
||||
controller: CustomDialogController;
|
||||
|
||||
swiperController: SwiperController = new SwiperController()
|
||||
|
||||
isPlayback: boolean = true
|
||||
|
||||
images: Array<Resource> = [
|
||||
$r('app.media.ic_wx_group_tip1'),
|
||||
$r("app.media.ic_wx_group_tip2"),
|
||||
$r("app.media.ic_wx_group_tip3"),
|
||||
$r("app.media.ic_wx_group_tip4"),
|
||||
$r('app.media.ic_wx_group_tip5')
|
||||
];
|
||||
|
||||
steps: Array<string> = ['第一步', '第二步', '第三步', '第四步', '第五步']
|
||||
|
||||
qrCodePath = 'https://cdn.batiao8.com/kct/mp/kcsp_qrcode.png'
|
||||
|
||||
@State currentIndex: number = 0
|
||||
|
||||
downloadImage() {
|
||||
try {
|
||||
const cachePath = FileUtil.getCacheDirPath() + FileUtil.separator + 'kcsp_wx_group_qrcode.jpg';
|
||||
if (FileUtil.accessSync(cachePath)) {
|
||||
FileUtil.unlink(cachePath)
|
||||
}
|
||||
request.downloadFile(AppUtil.getContext(), {
|
||||
url: this.qrCodePath,
|
||||
filePath: cachePath
|
||||
}).then((downloadTask: request.DownloadTask) => {
|
||||
downloadTask.on('complete', () => {
|
||||
console.info('download complete');
|
||||
SaveUtils.saveImageVideoToAlbumDialog([cachePath], false)
|
||||
.then((saved) => {
|
||||
if (saved) {
|
||||
PasteboardUtil.setDataTextSync(LoginManager.getUserInfo()!!.user_id)
|
||||
ToastUtils.show('ID复制成功')
|
||||
this.jumpToWxScan()
|
||||
this.controller.close()
|
||||
} else {
|
||||
ToastUtils.show('二维码保存失败')
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
ToastUtils.show('二维码保存失败')
|
||||
})
|
||||
})
|
||||
}).catch((err: BusinessError) => {
|
||||
ToastUtils.show('二维码下载失败')
|
||||
});
|
||||
} catch (error) {
|
||||
ToastUtils.show('二维码下载失败')
|
||||
}
|
||||
}
|
||||
|
||||
async jumpToWxScan() {
|
||||
let intent: Want = {
|
||||
action: 'ohos.want.action.viewData',
|
||||
uri: 'weixin://dl/scan' // 微信扫一扫的固定协议
|
||||
};
|
||||
try {
|
||||
await AppUtil.getContext().startAbility(intent);
|
||||
} catch (error) {
|
||||
let err: BusinessError = error as BusinessError;
|
||||
console.error(err.message)
|
||||
}
|
||||
}
|
||||
|
||||
build() {
|
||||
RelativeContainer() {
|
||||
Image($r('app.media.ic_wx_group_tip_bg')).width('100%').height(320)
|
||||
|
||||
Text(this.isPlayback ? '添加直播回放助手流程' : '添加视频助手流程')
|
||||
.width('auto')
|
||||
.fontColor(Color.White)
|
||||
.fontSize(16)
|
||||
.fontWeight(FontWeight.Medium)
|
||||
.margin({ top: 16 })
|
||||
.alignRules({
|
||||
left: { anchor: '__container__', align: HorizontalAlign.Start },
|
||||
right: { anchor: '__container__', align: HorizontalAlign.End }
|
||||
})
|
||||
.id('tv_title')
|
||||
|
||||
List({space: 16}) {
|
||||
ForEach(this.steps, (item: string, index) => {
|
||||
ListItem() {
|
||||
Text(item)
|
||||
.fontColor(index == this.currentIndex ? Color.White : $r('app.color.color_bebebe'))
|
||||
.fontSize(index == this.currentIndex ? 16 : 14)
|
||||
.fontWeight(index == this.currentIndex ? FontWeight.Medium : FontWeight.Normal)
|
||||
}
|
||||
.onClick(() => {
|
||||
this.swiperController.changeIndex(index, true)
|
||||
})
|
||||
})
|
||||
}
|
||||
.width('100%')
|
||||
.height(24)
|
||||
.listDirection(Axis.Horizontal)
|
||||
.alignListItem(ListItemAlign.Center)
|
||||
.alignRules({
|
||||
top: {anchor: 'tv_title', align: VerticalAlign.Bottom}
|
||||
})
|
||||
.margin({top: 20})
|
||||
.padding({left: 16, right: 16})
|
||||
.id('li_step')
|
||||
|
||||
Swiper(this.swiperController) {
|
||||
ForEach(this.images, (item: Resource) => {
|
||||
Image(item).width('100%').aspectRatio(2.04).margin({ left: 16, right: 16 })
|
||||
.borderRadius(20)
|
||||
})
|
||||
}
|
||||
.indicator(false)
|
||||
.loop(true)
|
||||
.autoPlay(true)
|
||||
.interval(2000)
|
||||
.onChange((number) => {
|
||||
this.currentIndex = number
|
||||
})
|
||||
.alignRules({
|
||||
top: {anchor: 'li_step', align: VerticalAlign.Bottom}
|
||||
})
|
||||
.margin({top: 24})
|
||||
.id('swiper')
|
||||
|
||||
Row() {
|
||||
Button('取消', { type: ButtonType.Capsule, stateEffect: false })
|
||||
.fontColor($r('app.color.color_50ffffff'))
|
||||
.fontSize(15)
|
||||
.backgroundColor($r('app.color.color_333333'))
|
||||
.width(126)
|
||||
.height(46)
|
||||
.onClick(() => {
|
||||
this.controller.close()
|
||||
})
|
||||
Blank().width(9)
|
||||
Button('前往微信扫码加群', { type: ButtonType.Capsule, stateEffect: false })
|
||||
.fontColor(Color.White)
|
||||
.fontSize(15)
|
||||
.backgroundColor(Color.Transparent)
|
||||
.linearGradient({
|
||||
colors: [['#F62C6C', 0.0], ['#FC4F54', 1.0]],
|
||||
direction: GradientDirection.Right
|
||||
})
|
||||
.layoutWeight(1)
|
||||
.height(46)
|
||||
.onClick(() => {
|
||||
if (!WXApi.isWXAppInstalled()) {
|
||||
ToastUtils.show('未安装微信客户端,请先下载安装微信客户端');
|
||||
return;
|
||||
}
|
||||
this.downloadImage()
|
||||
})
|
||||
}
|
||||
.backgroundColor($r('app.color.color_222222'))
|
||||
.alignRules({
|
||||
top: {anchor: 'swiper', align: VerticalAlign.Bottom}
|
||||
})
|
||||
.margin({top: 28})
|
||||
.padding({left: 16, top: 9, right: 16, bottom: 30})
|
||||
}
|
||||
.width('100%')
|
||||
.height('auto')
|
||||
.borderRadius(20)
|
||||
.backgroundColor($r('app.color.window_background'))
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
import { ComponentContent } from '@kit.ArkUI';
|
||||
|
||||
@Builder
|
||||
function defaultBuilder() {
|
||||
Column() {
|
||||
LoadingProgress()
|
||||
.color(Color.White)
|
||||
.width(50)
|
||||
.height(50)
|
||||
|
||||
Text('加载中')
|
||||
.fontColor(Color.White)
|
||||
.fontSize(12)
|
||||
.margin({ top: 5 })
|
||||
.width('auto')
|
||||
.height('auto')
|
||||
}
|
||||
.justifyContent(FlexAlign.Center)
|
||||
.borderRadius(6)
|
||||
.backgroundColor('#CC000000')
|
||||
.width(86)
|
||||
.height(86)
|
||||
}
|
||||
|
||||
export class LoadingDialog {
|
||||
context: UIContext | null = null;
|
||||
contentNode: ComponentContent<Object> | null = null;
|
||||
|
||||
private static instance: LoadingDialog | null = null;
|
||||
|
||||
static show(context: UIContext, cancelable: boolean = false) {
|
||||
if (LoadingDialog.instance === null) {
|
||||
LoadingDialog.instance = new LoadingDialog(context);
|
||||
}
|
||||
LoadingDialog.instance?.openDialog(cancelable);
|
||||
}
|
||||
|
||||
static dismiss() {
|
||||
if (LoadingDialog.instance !== null) {
|
||||
LoadingDialog.instance.closeDialog();
|
||||
LoadingDialog.instance = null;
|
||||
}
|
||||
}
|
||||
|
||||
constructor(context: UIContext) {
|
||||
this.context = context;
|
||||
this.contentNode = new ComponentContent(context, wrapBuilder(defaultBuilder));
|
||||
}
|
||||
|
||||
openDialog(cancelable: boolean) {
|
||||
if (this.context !== null && this.contentNode !== null) {
|
||||
if (!cancelable) {
|
||||
this.context.getPromptAction().openCustomDialog(this.contentNode, {
|
||||
onWillDismiss: () => {
|
||||
return false
|
||||
},
|
||||
autoCancel: false
|
||||
})
|
||||
.then(() => {
|
||||
console.info('OpenCustomDialog complete.');
|
||||
})
|
||||
} else {
|
||||
this.context.getPromptAction().openCustomDialog(this.contentNode, {
|
||||
autoCancel: false
|
||||
})
|
||||
.then(() => {
|
||||
console.info('OpenCustomDialog complete.');
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
closeDialog() {
|
||||
if (this.context !== null && this.contentNode !== null) {
|
||||
this.context.getPromptAction().closeCustomDialog(this.contentNode)
|
||||
.then(() => {
|
||||
console.info('CloseCustomDialog complete.');
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,80 @@
|
|||
import { Constants } from '../common/Constants';
|
||||
import { RouterUrls } from '../common/RouterUrls';
|
||||
|
||||
@CustomDialog
|
||||
export struct LoginTipDialog {
|
||||
controller: CustomDialogController;
|
||||
cancel: () => void = () => {
|
||||
}
|
||||
confirm: () => void = () => {
|
||||
}
|
||||
|
||||
build() {
|
||||
RelativeContainer() {
|
||||
Image($r('app.media.ic_tip_dialog_top_bg')).width('100%').aspectRatio(2.72)
|
||||
|
||||
Column() {
|
||||
Text('温馨提示')
|
||||
.fontColor($r('app.color.color_212226'))
|
||||
.fontSize(24)
|
||||
.fontFamily('ysbth')
|
||||
.margin({ top: 20 })
|
||||
|
||||
Text() {
|
||||
Span('登录之前需查看并同意')
|
||||
Span('《用户协议》')
|
||||
.fontColor($r("app.color.color_466afd"))
|
||||
.onClick(() => {
|
||||
this.getUIContext().getRouter().pushUrl({
|
||||
url: RouterUrls.WEB_PAGE, params: {
|
||||
title: '用户协议',
|
||||
url: Constants.USER_AGREEMENT
|
||||
}
|
||||
})
|
||||
})
|
||||
Span('和')
|
||||
Span('《隐私政策》')
|
||||
.fontColor($r("app.color.color_466afd"))
|
||||
.onClick(() => {
|
||||
this.getUIContext().getRouter().pushUrl({
|
||||
url: RouterUrls.WEB_PAGE, params: {
|
||||
title: '隐私政策',
|
||||
url: Constants.PRIVACY_POLICY
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
.fontColor($r('app.color.color_727686'))
|
||||
.fontSize(14)
|
||||
.textAlign(TextAlign.Center)
|
||||
.margin({ top: 20, left: 20, right: 20 })
|
||||
|
||||
Button('同意', { type: ButtonType.Capsule, stateEffect: true })
|
||||
.width(110)
|
||||
.height(40)
|
||||
.fontColor(Color.White)
|
||||
.fontSize(16)
|
||||
.backgroundColor($r("app.color.color_466afd"))
|
||||
.margin({ top: 20, bottom: 20 })
|
||||
.onClick(() => {
|
||||
this.controller.close();
|
||||
if (this.confirm) {
|
||||
this.confirm();
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
Image($r('app.media.ic_close_dialog')).width(18).height(18)
|
||||
.margin({top: 10, right: 10})
|
||||
.alignRules({
|
||||
right: {anchor: '__container__', align: HorizontalAlign.End}
|
||||
})
|
||||
.onClick(() => {
|
||||
this.controller.close()
|
||||
})
|
||||
}
|
||||
.height('auto')
|
||||
.borderRadius(20)
|
||||
.backgroundColor(Color.White)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
import { ComponentContent } from '@kit.ArkUI';
|
||||
|
||||
@Builder
|
||||
function defaultBuilder(text: string) {
|
||||
Column() {
|
||||
LoadingProgress()
|
||||
.color(Color.White)
|
||||
.width(50)
|
||||
.height(50)
|
||||
|
||||
Text(text)
|
||||
.fontColor(Color.White)
|
||||
.fontSize(12)
|
||||
.maxLines(1)
|
||||
.textOverflow({ overflow: TextOverflow.Ellipsis })
|
||||
.ellipsisMode(EllipsisMode.END)
|
||||
.margin({ left:10, top: 5, right: 10 })
|
||||
.width('auto')
|
||||
.height('auto')
|
||||
}
|
||||
.width(192)
|
||||
.height(124)
|
||||
.justifyContent(FlexAlign.Center)
|
||||
.borderRadius(6)
|
||||
.backgroundColor($r('app.color.color_222222'))
|
||||
.padding({left: 10, right: 10})
|
||||
}
|
||||
|
||||
export class MaterialLoadingDialog {
|
||||
context: UIContext | null = null;
|
||||
contentNode: ComponentContent<Object> | null = null;
|
||||
|
||||
private static instance: MaterialLoadingDialog | null = null;
|
||||
|
||||
static show(context: UIContext, text?: string) {
|
||||
if (MaterialLoadingDialog.instance === null) {
|
||||
MaterialLoadingDialog.instance = new MaterialLoadingDialog(context, text ? text : '');
|
||||
}
|
||||
MaterialLoadingDialog.instance?.openDialog();
|
||||
}
|
||||
|
||||
static update(text: string) {
|
||||
MaterialLoadingDialog.instance?.updateDialog(text);
|
||||
}
|
||||
|
||||
static dismiss() {
|
||||
if (MaterialLoadingDialog.instance !== null) {
|
||||
MaterialLoadingDialog.instance.closeDialog();
|
||||
MaterialLoadingDialog.instance = null;
|
||||
}
|
||||
}
|
||||
|
||||
constructor(context: UIContext, text: string) {
|
||||
this.context = context;
|
||||
this.contentNode = new ComponentContent(context, wrapBuilder(defaultBuilder), text);
|
||||
}
|
||||
|
||||
|
||||
openDialog() {
|
||||
if (this.context !== null && this.contentNode !== null) {
|
||||
this.context.getPromptAction().openCustomDialog(this.contentNode, {
|
||||
onWillDismiss: () => {
|
||||
return false
|
||||
}
|
||||
})
|
||||
.then(() => {
|
||||
console.info('OpenCustomDialog complete.');
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
closeDialog() {
|
||||
if (this.context !== null && this.contentNode !== null) {
|
||||
this.context.getPromptAction().closeCustomDialog(this.contentNode)
|
||||
.then(() => {
|
||||
console.info('CloseCustomDialog complete.');
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
updateDialog(text: string) {
|
||||
this.contentNode?.update(text);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,100 @@
|
|||
import { Constants } from '../common/Constants';
|
||||
import { RouterUrls } from '../common/RouterUrls';
|
||||
import { LengthMetrics } from '@kit.ArkUI';
|
||||
|
||||
@CustomDialog
|
||||
export struct PrivacyPolicyDialog {
|
||||
controller: CustomDialogController;
|
||||
cancel: () => void = () => {
|
||||
}
|
||||
confirm: () => void = () => {
|
||||
}
|
||||
|
||||
build() {
|
||||
Stack({alignContent: Alignment.Top}) {
|
||||
Image($r('app.media.ic_tip_dialog_top_bg')).width('100%').aspectRatio(2.72)
|
||||
|
||||
Column() {
|
||||
Text('欢迎使用')
|
||||
.fontColor($r('app.color.color_212226'))
|
||||
.fontSize(24)
|
||||
.fontFamily('ysbth')
|
||||
.margin({ top: 20 })
|
||||
|
||||
Text() {
|
||||
Span('请你务必审慎阅读、充分理解')
|
||||
Span('《服务协议》')
|
||||
.fontColor($r("app.color.color_466afd"))
|
||||
.onClick(() => {
|
||||
this.getUIContext().getRouter().pushUrl({
|
||||
url: RouterUrls.WEB_PAGE, params: {
|
||||
title: '用户协议',
|
||||
url: Constants.USER_AGREEMENT
|
||||
}
|
||||
})
|
||||
})
|
||||
Span('和')
|
||||
Span('《隐私政策》')
|
||||
.fontColor($r("app.color.color_466afd"))
|
||||
.onClick(() => {
|
||||
this.getUIContext().getRouter().pushUrl({
|
||||
url: RouterUrls.WEB_PAGE, params: {
|
||||
title: '隐私政策',
|
||||
url: Constants.PRIVACY_POLICY
|
||||
}
|
||||
})
|
||||
})
|
||||
Span('各条款,包括但不限于:为了更好的向你提供服务,我们需要访问你的相册、位置信息等。你可阅读')
|
||||
Span('《隐私政策》')
|
||||
.fontColor($r("app.color.color_466afd"))
|
||||
.onClick(() => {
|
||||
this.getUIContext().getRouter().pushUrl({
|
||||
url: RouterUrls.WEB_PAGE, params: {
|
||||
title: '隐私政策',
|
||||
url: Constants.PRIVACY_POLICY
|
||||
}
|
||||
})
|
||||
})
|
||||
Span('了解详细信息。如果你同意,请点击下面同意按钮开始接受我们的服务。')
|
||||
}
|
||||
.fontColor($r('app.color.color_727686'))
|
||||
.fontSize(14)
|
||||
.lineSpacing(LengthMetrics.px(20))
|
||||
.margin({ top: 10, left: 20, right: 20 })
|
||||
|
||||
Row(){
|
||||
Button('拒绝', { type: ButtonType.Capsule, stateEffect: true })
|
||||
.width(110)
|
||||
.height(40)
|
||||
.fontColor($r('app.color.color_80859B'))
|
||||
.fontSize(16)
|
||||
.backgroundColor($r("app.color.color_f1f2f6"))
|
||||
.margin({left: 20})
|
||||
.onClick(() => {
|
||||
this.controller.close();
|
||||
if (this.cancel) {
|
||||
this.cancel();
|
||||
}
|
||||
})
|
||||
Blank().layoutWeight(1)
|
||||
Button('同意', { type: ButtonType.Capsule, stateEffect: true })
|
||||
.width(110)
|
||||
.height(40)
|
||||
.fontColor(Color.White)
|
||||
.fontSize(16)
|
||||
.backgroundColor($r("app.color.color_466afd"))
|
||||
.margin({right: 20})
|
||||
.onClick(() => {
|
||||
this.controller.close();
|
||||
if (this.confirm) {
|
||||
this.confirm();
|
||||
}
|
||||
})
|
||||
}
|
||||
.margin({ top: 20, bottom: 20 })
|
||||
}
|
||||
}
|
||||
.borderRadius(20)
|
||||
.backgroundColor(Color.White)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,111 @@
|
|||
import { ComponentContent } from '@kit.ArkUI';
|
||||
import { StrUtil } from '@pura/harmony-utils';
|
||||
import { DialogCallback } from '../callback/DialogCallback';
|
||||
|
||||
export declare class TipDialogOption {
|
||||
title?: string;
|
||||
content: string;
|
||||
buttonText?: string;
|
||||
callback?: DialogCallback;
|
||||
}
|
||||
|
||||
@Builder
|
||||
function defaultBuilder(option: TipDialogOption) {
|
||||
RelativeContainer() {
|
||||
Image($r('app.media.ic_tip_dialog_top_bg')).width('100%').aspectRatio(2.72)
|
||||
|
||||
Column() {
|
||||
Text(option.title)
|
||||
.fontColor($r('app.color.color_212226'))
|
||||
.fontSize(22)
|
||||
.fontWeight(FontWeight.Medium)
|
||||
.visibility(StrUtil.isEmpty(option.title) ? Visibility.Hidden : Visibility.Visible)
|
||||
Text(option.content)
|
||||
.textAlign(TextAlign.Center)
|
||||
.fontColor(StrUtil.isNotEmpty(option.title) ? $r('app.color.color_727686') : $r('app.color.color_212226'))
|
||||
.fontSize(StrUtil.isNotEmpty(option.title) ? 14 : 22)
|
||||
.fontWeight(StrUtil.isNotEmpty(option.title) ? FontWeight.Normal : FontWeight.Medium)
|
||||
.margin({ left: 27, top: 12, right: 27 })
|
||||
.maxLines(5)
|
||||
Button(StrUtil.isNotEmpty(option.buttonText) ? option.buttonText : '确定', { type: ButtonType.Capsule, stateEffect: true })
|
||||
.width(110)
|
||||
.height(40)
|
||||
.fontColor(Color.White)
|
||||
.fontSize(16)
|
||||
.backgroundColor($r("app.color.color_466afd"))
|
||||
.margin({ top: 20, bottom: 20 })
|
||||
.onClick(() => {
|
||||
SimpleTipDialog.dismiss();
|
||||
if (option.callback?.confirm) {
|
||||
option.callback?.confirm();
|
||||
}
|
||||
})
|
||||
}
|
||||
.padding({ top: 22, bottom: 22 })
|
||||
|
||||
Image($r('app.media.ic_close_dialog')).width(18).height(18)
|
||||
.margin({top: 10, right: 10})
|
||||
.alignRules({
|
||||
right: {anchor: '__container__', align: HorizontalAlign.End}
|
||||
})
|
||||
.onClick(() => {
|
||||
SimpleTipDialog.dismiss();
|
||||
})
|
||||
}
|
||||
.borderRadius(20)
|
||||
.backgroundColor(Color.White)
|
||||
.width('80%')
|
||||
}
|
||||
|
||||
export class SimpleTipDialog {
|
||||
context: UIContext | null = null;
|
||||
contentNode: ComponentContent<Object> | null = null;
|
||||
|
||||
private static instance: SimpleTipDialog | null = null;
|
||||
|
||||
static show(context: UIContext, option: TipDialogOption, canCancel: boolean = true) {
|
||||
if (SimpleTipDialog.instance === null) {
|
||||
SimpleTipDialog.instance = new SimpleTipDialog(context, option);
|
||||
}
|
||||
SimpleTipDialog.instance?.openDialog(canCancel);
|
||||
}
|
||||
|
||||
static dismiss() {
|
||||
if (SimpleTipDialog.instance !== null) {
|
||||
SimpleTipDialog.instance.closeDialog();
|
||||
SimpleTipDialog.instance = null;
|
||||
}
|
||||
}
|
||||
|
||||
constructor(context: UIContext, option: TipDialogOption) {
|
||||
this.context = context;
|
||||
this.contentNode = new ComponentContent(context, wrapBuilder(defaultBuilder), option);
|
||||
}
|
||||
|
||||
openDialog(canCancel: boolean) {
|
||||
if (this.context !== null && this.contentNode !== null) {
|
||||
this.context.getPromptAction().openCustomDialog(this.contentNode, {
|
||||
maskColor: '#CC000000',
|
||||
onWillDismiss: () => {
|
||||
return canCancel
|
||||
}
|
||||
})
|
||||
.then(() => {
|
||||
console.info('OpenCustomDialog complete.');
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
closeDialog() {
|
||||
if (this.context !== null && this.contentNode !== null) {
|
||||
this.context.getPromptAction().closeCustomDialog(this.contentNode)
|
||||
.then(() => {
|
||||
console.info('CloseCustomDialog complete.');
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
updateDialog(options: TipDialogOption) {
|
||||
this.contentNode?.update(options)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,121 @@
|
|||
import { ComponentContent } from '@kit.ArkUI';
|
||||
import { StrUtil } from '@pura/harmony-utils';
|
||||
import { DialogCallback } from '../callback/DialogCallback';
|
||||
|
||||
export declare class TipDialogOption {
|
||||
title?: string;
|
||||
content: string;
|
||||
leftText?: string;
|
||||
rightText?: string;
|
||||
callback?: DialogCallback;
|
||||
}
|
||||
|
||||
@Builder
|
||||
function defaultBuilder(option: TipDialogOption) {
|
||||
Column() {
|
||||
Text(option.title)
|
||||
.fontColor($r('app.color.color_90ffffff'))
|
||||
.fontSize(18)
|
||||
.fontWeight(FontWeight.Medium)
|
||||
.visibility(StrUtil.isEmpty(option.title) ? Visibility.Hidden : Visibility.Visible)
|
||||
Text(option.content)
|
||||
.textAlign(TextAlign.Center)
|
||||
.fontColor(StrUtil.isNotEmpty(option.title) ? $r('app.color.color_80ffffff') : $r('app.color.color_90ffffff'))
|
||||
.fontSize(StrUtil.isNotEmpty(option.title) ? 14 : 18)
|
||||
.fontWeight(StrUtil.isNotEmpty(option.title) ? FontWeight.Normal : FontWeight.Medium)
|
||||
.textOverflow({ overflow: TextOverflow.Ellipsis })
|
||||
.ellipsisMode(EllipsisMode.END)
|
||||
.margin({ left: 27, top: 12, right: 27 })
|
||||
.maxLines(5)
|
||||
Row() {
|
||||
Button(StrUtil.isNotEmpty(option.leftText) ? option.leftText : '取消', { type: ButtonType.Capsule, stateEffect: false })
|
||||
.fontColor($r('app.color.color_50ffffff'))
|
||||
.fontSize(14)
|
||||
.backgroundColor($r('app.color.color_333333'))
|
||||
.layoutWeight(1)
|
||||
.height(40)
|
||||
.onClick(() => {
|
||||
TipDialog.dismiss();
|
||||
if (option.callback?.cancel) {
|
||||
option.callback?.cancel();
|
||||
}
|
||||
})
|
||||
Blank().width(12)
|
||||
Button(StrUtil.isNotEmpty(option.rightText) ? option.rightText : '确定', { type: ButtonType.Capsule, stateEffect: false })
|
||||
.fontColor(Color.White)
|
||||
.fontSize(14)
|
||||
.backgroundColor(Color.Transparent)
|
||||
.linearGradient({
|
||||
colors: [['#F62C6C', 0.0], ['#FC4F54', 1.0]],
|
||||
direction: GradientDirection.Right
|
||||
})
|
||||
.layoutWeight(1)
|
||||
.height(40)
|
||||
.onClick(() => {
|
||||
TipDialog.dismiss();
|
||||
if (option.callback?.confirm) {
|
||||
option.callback?.confirm();
|
||||
}
|
||||
})
|
||||
}
|
||||
.padding({ left: 14, right: 14 })
|
||||
.margin({ top: 20 })
|
||||
}
|
||||
.padding({ top: 22, bottom: 22 })
|
||||
.borderRadius(20)
|
||||
.backgroundColor($r('app.color.color_222222'))
|
||||
.width('80%')
|
||||
}
|
||||
|
||||
export class TipDialog {
|
||||
context: UIContext | null = null;
|
||||
contentNode: ComponentContent<Object> | null = null;
|
||||
|
||||
private static instance: TipDialog | null = null;
|
||||
|
||||
static show(context: UIContext, option: TipDialogOption, canCancel: boolean = true) {
|
||||
if (TipDialog.instance === null) {
|
||||
TipDialog.instance = new TipDialog(context, option);
|
||||
}
|
||||
TipDialog.instance?.openDialog(canCancel);
|
||||
}
|
||||
|
||||
static dismiss() {
|
||||
if (TipDialog.instance !== null) {
|
||||
TipDialog.instance.closeDialog();
|
||||
TipDialog.instance = null;
|
||||
}
|
||||
}
|
||||
|
||||
constructor(context: UIContext, option: TipDialogOption) {
|
||||
this.context = context;
|
||||
this.contentNode = new ComponentContent(context, wrapBuilder(defaultBuilder), option);
|
||||
}
|
||||
|
||||
openDialog(canCancel: boolean) {
|
||||
if (this.context !== null && this.contentNode !== null) {
|
||||
this.context.getPromptAction().openCustomDialog(this.contentNode, {
|
||||
maskColor: '#CC000000',
|
||||
onWillDismiss: () => {
|
||||
return canCancel;
|
||||
}
|
||||
})
|
||||
.then(() => {
|
||||
console.info('OpenCustomDialog complete.');
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
closeDialog() {
|
||||
if (this.context !== null && this.contentNode !== null) {
|
||||
this.context.getPromptAction().closeCustomDialog(this.contentNode)
|
||||
.then(() => {
|
||||
console.info('CloseCustomDialog complete.');
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
updateDialog(options: TipDialogOption) {
|
||||
this.contentNode?.update(options)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
|
||||
export class AccountEntity {
|
||||
avater: string = '';
|
||||
bind: Array<string> = new Array();
|
||||
create_time: string = '';
|
||||
name: string = '';
|
||||
phone: string = '';
|
||||
role: number = 0;
|
||||
temp: boolean = true;
|
||||
user_id: string = '';
|
||||
vip_name: string = '';
|
||||
vip_type: number = 1;
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
export class BannerEntity {
|
||||
image: string = "";
|
||||
page: string = "";
|
||||
type: string = "";
|
||||
}
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
import { Expose, Type } from 'class-transformer';
|
||||
import { BannerEntity } from './BannerEntity';
|
||||
import "reflect-metadata";
|
||||
import { WxVideoConfigEntity } from './WxVideoConfig';
|
||||
|
||||
export class ConfigEntity {
|
||||
@Expose({ name: 'client.guide.pay.enable' })
|
||||
guidePayEnable: boolean = true; //引导页是否开启支付,默认可以
|
||||
|
||||
@Expose({ name: 'client.guide.enable' })
|
||||
guideEnable: boolean = true; //是否开启引导页
|
||||
|
||||
@Expose({ name: 'client.start.function.hint' })
|
||||
guideHint: string = ""; //引导页提示语
|
||||
|
||||
@Expose({ name: 'client.nologin.pay.enable' })
|
||||
noLoginPayEnable: boolean = false; //是否开启未登录支付
|
||||
|
||||
@Expose({ name: 'client.pay.agreement' })
|
||||
payAgreementEnable: boolean = true; //是否显示支付协议
|
||||
|
||||
@Expose({ name: 'client.login.type' })
|
||||
loginType: Array<string> = new Array(); //支持的登录类型
|
||||
|
||||
@Expose({ name: 'client.banner.urls' })
|
||||
@Type(() => BannerEntity)
|
||||
homeBanners: Array<BannerEntity> = new Array(); //首页轮播图
|
||||
|
||||
@Expose({ name: 'client.wechat.video.share.enable' })
|
||||
wxVideoEnable: boolean = true; //视频号开关
|
||||
|
||||
@Expose({ name: 'client.wechat.video.playback.share.enable' })
|
||||
playbackEnable: boolean = true; //直播回放开关
|
||||
|
||||
@Expose({ name: 'client.course.wechat.video' })
|
||||
wxVideoCourse: string = ""; //视频号教程
|
||||
|
||||
@Expose({ name: 'client.course.playback' })
|
||||
wxPlaybackCourse: string = ""; //直播回放教程
|
||||
|
||||
@Expose({ name: 'client.playback.join.type' })
|
||||
wxPlaybackJoinType: string = ""; //直播加群方式
|
||||
|
||||
@Type(() => WxVideoConfigEntity)
|
||||
@Expose({ name: 'client.mp.share.config.kcsp' })
|
||||
wxVideoConfig: WxVideoConfigEntity = new WxVideoConfigEntity() //直播回放小程序跳转配置
|
||||
|
||||
@Expose({ name: 'client.hmos.video.service.enable' }) //视频号助手是否可用
|
||||
wxVideoServiceEnable: boolean = true
|
||||
|
||||
@Expose({ name: 'client.link.collection' })
|
||||
domainMap: Record<string, string> = {}; //网站主机名
|
||||
|
||||
@Expose({ name: 'client.copy.contains' })
|
||||
copyContainsList: Array<string> = []; //链接识别配置
|
||||
|
||||
@Expose({ name: 'client.challenge.enable' })
|
||||
challengeEnable?: boolean = true; //0元挑战
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
export class DiamondDetailEntity {
|
||||
buy_total: number = 0
|
||||
buy_used: number = 0
|
||||
month_total: number = 0
|
||||
month_used: number = 0
|
||||
remain: number = 0
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
export class DiamondRuleEntity {
|
||||
title: string = ''
|
||||
desc: string = ''
|
||||
|
||||
constructor(title: string, desc: string) {
|
||||
this.title = title
|
||||
this.desc = desc
|
||||
}
|
||||
|
||||
static getRuleList(): Array<DiamondRuleEntity> {
|
||||
const list = new Array<DiamondRuleEntity>()
|
||||
list.push(new DiamondRuleEntity('一、固定钻石领取', '会员用户每月最后一天,系统会固定发放500钻石到用户平台账户。'))
|
||||
list.push(new DiamondRuleEntity('二、固定钻石刷新', '若会员用户在第一个月有没用完的钻石,那么会在本月最后一天重置不会留存到第二月。'))
|
||||
list.push(new DiamondRuleEntity('三、兑换钻石', '会员兑换后的钻石统一叫【兑换钻石】,【兑换钻石】不同于【固定钻石】每月刷新钻石数量;用户兑换了多少就可以使用多少,用完截止,没有时间限制,也没有每月最后一天刷新。'))
|
||||
list.push(new DiamondRuleEntity('四、重复兑换钻石', '兑换钻石可重复购买,用完截止,没有时间限制,也没有每月最后一天刷新。'))
|
||||
return list
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,102 @@
|
|||
export class DownloadHistoryEntity {
|
||||
id: string = ''
|
||||
title: string = ''
|
||||
status: string = ''
|
||||
description: string = ''
|
||||
create_time: string = ''
|
||||
domain: string = ''
|
||||
request: string = ''
|
||||
save_cost: string = ''
|
||||
save_end_time: string = ''
|
||||
save_size: string = ''
|
||||
save_start_time: string = ''
|
||||
save_status: string = ''
|
||||
|
||||
getTypeBgColor(): string {
|
||||
switch (this.domain) {
|
||||
case 'b23.tv':
|
||||
case 'm.bilibili.com':
|
||||
case 'www.bilibili.com':
|
||||
return '#F4306F'
|
||||
case 'v.douyin.com':
|
||||
case 'www.iesdouyin.com':
|
||||
case 'vt.tiktok.com':
|
||||
return '#80FFFFFF'
|
||||
case 'm.toutiao.com':
|
||||
return '#F91716'
|
||||
case 'video.weibo.com':
|
||||
case 'weibo.com':
|
||||
case 'm.weibo.cn':
|
||||
case 'shop.sc.weibo.com':
|
||||
return '#DE860C'
|
||||
case 'v.kuaishou.com':
|
||||
return '#DE440D'
|
||||
case 'wxapp.tc.qq.com':
|
||||
case 'm.v.qq.com':
|
||||
return '#0D95F3'
|
||||
case 'twitter.com':
|
||||
case 'x.com':
|
||||
return '#139EEA'
|
||||
case 'xhslink.com':
|
||||
case 'www.xiaohongshu.com':
|
||||
return '#EA3046'
|
||||
case 'instagram.com':
|
||||
case 'www.instagram.com':
|
||||
return '#8D32F4'
|
||||
case 'mr.baidu.com':
|
||||
case 'm.baidu.com':
|
||||
case 'mbd.baidu.com':
|
||||
return '#0D95F3'
|
||||
case 'youtu.be':
|
||||
case 'youtube.com':
|
||||
case 'm.youtube.com':
|
||||
case 'www.youtube.com':
|
||||
return '#F92C2C'
|
||||
case 'mp.weixin.qq.com':
|
||||
return '#1DDB50'
|
||||
case 'e.tb.cn':
|
||||
case 'm.tb.cn':
|
||||
return '#F96E12'
|
||||
case 'www.facebook.com':
|
||||
return '#1B6EF6'
|
||||
case 'v.ixigua.com':
|
||||
case 'www.ixigua.com':
|
||||
return '#F01566'
|
||||
case 'mobile.yangkeduo.com':
|
||||
return '#F40F18'
|
||||
case 'm.youku.com':
|
||||
return '#0CB3E2'
|
||||
case '163cn.tv':
|
||||
return '#F42C34'
|
||||
case 'qishui.douyin.com':
|
||||
return '#20C485'
|
||||
case 'qr.1688.com':
|
||||
case 'detail.m.1688.com':
|
||||
return '#F65611'
|
||||
case 'h5.pipix.com':
|
||||
return '#EE3958'
|
||||
case 'app.cctv.com':
|
||||
return '#80FFFFFF'
|
||||
case 'vk.com':
|
||||
return '#1E82F3'
|
||||
case 'www.finkapp.cn':
|
||||
return '#F62C2C'
|
||||
case 'novelquickapp.com':
|
||||
return '#F18221'
|
||||
case 'video.weishi.qq.com':
|
||||
return '#2E5DF0'
|
||||
case 'm.ctrip.com':
|
||||
return '#177DF0'
|
||||
}
|
||||
return '#33FFFFFF'
|
||||
}
|
||||
|
||||
getTypeTextColor(): string {
|
||||
switch (this.domain) {
|
||||
case 'v.douyin.com':
|
||||
case 'app.cctv.com':
|
||||
return '#CC000000'
|
||||
}
|
||||
return '#CCFFFFFF'
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
import { ArrayList } from "@kit.ArkTS";
|
||||
|
||||
export class HomeMenuEntity {
|
||||
icon: Resource | null = null;
|
||||
title: string = "";
|
||||
alias: string = "";
|
||||
|
||||
constructor(icon: Resource, title: string, alias: string) {
|
||||
this.icon = icon;
|
||||
this.title = title;
|
||||
this.alias = alias;
|
||||
}
|
||||
}
|
||||
|
||||
export function homeMenuList(): ArrayList<HomeMenuEntity> {
|
||||
let list = new ArrayList<HomeMenuEntity>()
|
||||
list.add(new HomeMenuEntity($r('app.media.ic_home_icon6'), "视频转音频", "videoToAudio"))
|
||||
list.add(new HomeMenuEntity($r('app.media.ic_home_icon8'), "视频加水印", "addWatermark"))
|
||||
list.add(new HomeMenuEntity($r('app.media.ic_home_icon5'), "视频转文字", "videoToText"))
|
||||
list.add(new HomeMenuEntity($r('app.media.ic_home_icon9'), "长图拼接", "longImageMerge"))
|
||||
list.add(new HomeMenuEntity($r('app.media.ic_home_icon10'), "更多功能", "moreTools"))
|
||||
return list;
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
|
||||
export class LoginEntity {
|
||||
user_id: string = "";
|
||||
name: string = "";
|
||||
avater: string = "";
|
||||
token: string = "";
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
import { UploadImgEntity } from './UploadImgEntity';
|
||||
|
||||
export class MaterialEntity {
|
||||
id: string = '';
|
||||
title: string = '';
|
||||
pic?: UploadImgEntity = undefined;
|
||||
pic_size: string = '';
|
||||
tags: Array<string> = [];
|
||||
user_id: string = '';
|
||||
download: string = '';
|
||||
update_time: string = '';
|
||||
create_time: string = '';
|
||||
}
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
import { Type } from 'class-transformer';
|
||||
import "reflect-metadata";
|
||||
import systemDateTime from '@ohos.systemDateTime';
|
||||
import { RandomUtil } from '@pura/harmony-utils';
|
||||
|
||||
export class MaterialInfoEntity{
|
||||
enc_user_id: string = '';
|
||||
logid: string = '';
|
||||
@Type(() => MaterialInfoEntity)
|
||||
material?: MaterialDetailEntity;
|
||||
offline: number = 0;
|
||||
status: number = 0;
|
||||
status_name: string = '';
|
||||
timeout: number = 0;
|
||||
user_id: string = '';
|
||||
}
|
||||
|
||||
export class MaterialDetailEntity {
|
||||
@Type(() => AudioMaterial)
|
||||
audio?: Array<AudioMaterial>;
|
||||
desc: string = '';
|
||||
@Type(() => ImageMaterial)
|
||||
image?: Array<ImageMaterial>;
|
||||
merge: boolean = false;
|
||||
proxyUrlList?: Array<string>;
|
||||
threading: boolean = false;
|
||||
title: string = '';
|
||||
@Type(() => VideoMaterial)
|
||||
video?: Array<VideoMaterial>;
|
||||
}
|
||||
|
||||
@ObservedV2
|
||||
export class MediaEntity {
|
||||
name: string = ""
|
||||
origin: string = ""
|
||||
title: string = ""
|
||||
url: string = ""
|
||||
origin_url: string = ""
|
||||
speed_up: number = 0 //1 加速
|
||||
isThreading: boolean = false
|
||||
isMerge: boolean = false
|
||||
currentLen: number = 0
|
||||
totalSize: number = 0
|
||||
continueDownload: boolean = false
|
||||
cacheName: string = ""
|
||||
logid: string = ""
|
||||
headers?: Map<string, string>
|
||||
isM3u8: boolean = false
|
||||
flag: number = 0
|
||||
@Trace isChecked: boolean = false
|
||||
|
||||
initFileName(): string {
|
||||
if (!this.name) {
|
||||
if (this instanceof VideoMaterial) {
|
||||
this.name = `kcsp_${systemDateTime.getTime() + RandomUtil.getRandomInt(1000, 2000)}.mp4`
|
||||
} else if (this instanceof AudioMaterial) {
|
||||
this.name = `kcsp_${systemDateTime.getTime() + RandomUtil.getRandomInt(1000, 2000)}.mp3`
|
||||
} else if (this instanceof ImageMaterial) {
|
||||
this.name = `kcsp_${systemDateTime.getTime() + RandomUtil.getRandomInt(1000, 2000)}.jpeg`
|
||||
}
|
||||
}
|
||||
return this.name
|
||||
}
|
||||
}
|
||||
|
||||
export class VideoMaterial extends MediaEntity {
|
||||
play: boolean = false
|
||||
thumb?: string = ''
|
||||
audio?: AudioMaterial
|
||||
decodeKey?: Int8Array
|
||||
sequenceNumber: number = 0
|
||||
keyInfo?: Map<string, string> = new Map()
|
||||
}
|
||||
|
||||
export class AudioMaterial extends MediaEntity {
|
||||
|
||||
}
|
||||
|
||||
export class ImageMaterial extends MediaEntity {
|
||||
|
||||
}
|
||||
|
||||
export class TextMaterial extends MediaEntity {
|
||||
title: string = ''
|
||||
desc: string = ''
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
import image from '@ohos.multimedia.image'
|
||||
|
||||
export class MediaRecordEntity {
|
||||
uri?: string = ''
|
||||
name?: string = ''
|
||||
thumb?: image.PixelMap = undefined
|
||||
duration: number = 0
|
||||
createTime: number = 0
|
||||
isChecked: boolean = false
|
||||
|
||||
constructor(uri: string) {
|
||||
this.uri = uri
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
|
||||
export class NoticeEntity {
|
||||
loop: boolean = true;
|
||||
|
||||
notice?: Array<string> = [];
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
export class OrderEntity {
|
||||
id: string = '';
|
||||
create_time: string = '';
|
||||
goods_name: string = '';
|
||||
invoice_major: boolean = false;
|
||||
invoice_status: string = '';
|
||||
invoice_url: string = '';
|
||||
out_trade_no: string = '';
|
||||
pay_params: string = '';
|
||||
pay_time: string = '';
|
||||
pay_type: string = '';
|
||||
status: string = '';
|
||||
total_fee: string = '';
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
export class PayOrderEntity {
|
||||
//支付宝
|
||||
appId: string = '';
|
||||
orderId: string = '';
|
||||
outTradeNo: string = '';
|
||||
payParam: string = '';
|
||||
payType: string = '';
|
||||
|
||||
//微信
|
||||
nonceStr: string = '';
|
||||
package: string = '';
|
||||
partnerId: string = '';
|
||||
prepayId: string = '';
|
||||
sign: string = '';
|
||||
timeStamp: string = '';
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
export class SendCodeEntity {
|
||||
timestamp: string = '';
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
export class UploadImgEntity {
|
||||
id: string = ''
|
||||
url: string = ''
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
import { Type } from 'class-transformer';
|
||||
import { ConfigEntity } from './ConfigEntity';
|
||||
import "reflect-metadata";
|
||||
|
||||
export class UserConfigEntity {
|
||||
token: string = "";
|
||||
temp: boolean = false;
|
||||
name: string = "";
|
||||
user_id: string = "";
|
||||
@Type(() => ConfigEntity)
|
||||
config: ConfigEntity = new ConfigEntity();
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
export class UserEntity {
|
||||
appleid: string = '';
|
||||
avater: string = '';
|
||||
balance: string = '';
|
||||
city: string = '';
|
||||
client_cid: string = '';
|
||||
country: string = '';
|
||||
coupon_count: number = 0;
|
||||
imei: string = '';
|
||||
month_download_count: string = '0';
|
||||
month_download_size: string = '0';
|
||||
name: string = '';
|
||||
oaid: string = '';
|
||||
os_version: string = '';
|
||||
phone: string = '';
|
||||
province: string = '';
|
||||
role: string = '';
|
||||
sex: number = 0;
|
||||
show_contact_menu: boolean = true;
|
||||
show_masonry_menu: boolean = true;
|
||||
temp: boolean = true;
|
||||
unionid: string = '';
|
||||
user_id: string = '';
|
||||
vip: number = 1; // 1非会员 2会员 3终生会员
|
||||
vip_expire: string = '';
|
||||
vip_expire_time: string = '';
|
||||
vip_name: string = '';
|
||||
weixinAppOpenId: string = '';
|
||||
ip_area: string = '';
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
@ObservedV2
|
||||
export class VipMealEntity {
|
||||
@Trace checked: boolean = false;
|
||||
goods_id: string = '';
|
||||
goods_name: string = '';
|
||||
origin_price: string = '';
|
||||
pay_type: string = '';
|
||||
price: string = '';
|
||||
single_pay_price: string = '';
|
||||
tips: string = '';
|
||||
sign_value = '';
|
||||
value: string = '';
|
||||
image: string = '';
|
||||
description: string = '';
|
||||
weixinMpOriId: string = '';
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
export class VipPermissionEntity {
|
||||
auth: boolean = false
|
||||
auth_ad: boolean = false
|
||||
scene: string = ''
|
||||
user_id: number = 0
|
||||
vip: number = 0
|
||||
vip_expire: string = ''
|
||||
vip_expire_time: string = ''
|
||||
vip_goods_type: string = ''
|
||||
vip_message: string = ''
|
||||
vip_name: string = ''
|
||||
type: number = 0
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
import { Expose } from 'class-transformer';
|
||||
import "reflect-metadata";
|
||||
|
||||
export class WxServiceEntity {
|
||||
corpid: string = ""
|
||||
@Expose({ name: 'kf.address' })
|
||||
address: string = ""
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
export class WxVideoConfigEntity {
|
||||
id: string = '';
|
||||
title: string = '';
|
||||
desc: string = '';
|
||||
descTitle: string = '';
|
||||
qrcode: string = '';
|
||||
tips: string = '';
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
import { MaterialInfoEntity } from "./MaterialInfoEntity"
|
||||
|
||||
export class WxVideoEntity {
|
||||
items?: Array<MaterialInfoEntity>
|
||||
playback: boolean = false
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
import { AbilityConstant, ConfigurationConstant, UIAbility, Want } from '@kit.AbilityKit';
|
||||
import { window } from '@kit.ArkUI';
|
||||
import { AppUtil } from '@pura/harmony-utils';
|
||||
import { WXApi, WXEventHandler } from '../utils/wechat/WXApiEventHandlerImpl';
|
||||
|
||||
export default class EntryAbility extends UIAbility {
|
||||
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
|
||||
this.context.getApplicationContext().setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET);
|
||||
AppUtil.init(this.context);
|
||||
this.handleWeChatCallIfNeed(want);
|
||||
}
|
||||
|
||||
onNewWant(want: Want, launchParam: AbilityConstant.LaunchParam): void {
|
||||
this.handleWeChatCallIfNeed(want);
|
||||
}
|
||||
|
||||
onWindowStageCreate(windowStage: window.WindowStage): void {
|
||||
// Main window is created, set main page for this ability
|
||||
AppStorage.setOrCreate('windowStage', windowStage);
|
||||
windowStage.loadContent('pages/splash/SplashPage', (err) => {
|
||||
// this.registerFont();
|
||||
if (err.code) {
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
onWindowStageDestroy(): void {
|
||||
// Main window is destroyed, release UI related resources
|
||||
}
|
||||
|
||||
onDestroy(): void {
|
||||
}
|
||||
|
||||
onForeground(): void {
|
||||
// Ability has brought to foreground
|
||||
}
|
||||
|
||||
onBackground(): void {
|
||||
// Ability has back to background
|
||||
}
|
||||
|
||||
private handleWeChatCallIfNeed(want: Want) { //放在与onCreate同级
|
||||
WXApi.handleWant(want, WXEventHandler)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
import { hilog } from '@kit.PerformanceAnalysisKit';
|
||||
import { BackupExtensionAbility, BundleVersion } from '@kit.CoreFileKit';
|
||||
|
||||
const DOMAIN = 0x0000;
|
||||
|
||||
export default class EntryBackupAbility extends BackupExtensionAbility {
|
||||
async onBackup() {
|
||||
hilog.info(DOMAIN, 'testTag', 'onBackup ok');
|
||||
await Promise.resolve();
|
||||
}
|
||||
|
||||
async onRestore(bundleVersion: BundleVersion) {
|
||||
hilog.info(DOMAIN, 'testTag', 'onRestore ok %{public}s', JSON.stringify(bundleVersion));
|
||||
await Promise.resolve();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
import { audio } from "@kit.AudioKit";
|
||||
import { BusinessError } from "@kit.BasicServicesKit";
|
||||
|
||||
class AVSessionManager {
|
||||
private audioManager = audio.getAudioManager();
|
||||
private audioSessionManager: audio.AudioSessionManager = this.audioManager.getSessionManager();
|
||||
|
||||
private strategy: audio.AudioSessionStrategy = {
|
||||
concurrencyMode: audio.AudioConcurrencyMode.CONCURRENCY_PAUSE_OTHERS
|
||||
};
|
||||
|
||||
/**
|
||||
* 激活音频会话
|
||||
*/
|
||||
async activate() {
|
||||
if (!this.isActive()) {
|
||||
await this.audioSessionManager.activateAudioSession(this.strategy).then(() => {
|
||||
console.info('Succeeded in activating audio session.');
|
||||
}).catch((err: BusinessError) => {
|
||||
console.error(`Failed to activate audio session. Code: ${err.code}, message: ${err.message}`);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 停用音频会话
|
||||
*/
|
||||
async deactivate() {
|
||||
if (this.isActive()) {
|
||||
await this.audioSessionManager.deactivateAudioSession().then(() => {
|
||||
console.info('Succeeded in deactivating audio session.');
|
||||
}).catch((err: BusinessError) => {
|
||||
console.error(`Failed to deactivate audio session. Code: ${err.code}, message: ${err.message}`);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 会话是否激活
|
||||
* @returns
|
||||
*/
|
||||
isActive(): boolean {
|
||||
return this.audioSessionManager.isAudioSessionActivated();
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加会话停用监听
|
||||
*/
|
||||
setDeactivatedCallback(callback: Callback<audio.AudioSessionDeactivatedEvent>) {
|
||||
this.audioSessionManager.on('audioSessionDeactivated', callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除会话停用监听
|
||||
*/
|
||||
removeDeactivatedCallback(callback?: Callback<audio.AudioSessionDeactivatedEvent>) {
|
||||
this.audioSessionManager.off('audioSessionDeactivated', callback);
|
||||
}
|
||||
}
|
||||
|
||||
export const avSessionManager = new AVSessionManager()
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
import { apiService } from "../net/ApiService"
|
||||
|
||||
export class EventReportGlobalManager {
|
||||
static async eventReport(key: string, value: string = '', extra: string = '') {
|
||||
try {
|
||||
apiService.eventReport(key, value, extra)
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
import { PrefUtils } from '../utils/PrefUtils';
|
||||
import { JSON } from '@kit.ArkTS';
|
||||
|
||||
/**
|
||||
* 保存到相册的媒体列表
|
||||
*/
|
||||
export class LocalMediaManager {
|
||||
static add(uri: string) {
|
||||
let array = PrefUtils.getStringArray('local_record')
|
||||
if (!array.includes(uri)) {
|
||||
array.push(uri)
|
||||
}
|
||||
PrefUtils.put('local_record', JSON.stringify(array))
|
||||
}
|
||||
|
||||
static delete(uri: string) {
|
||||
let array = PrefUtils.getStringArray('local_record')
|
||||
if (array.includes(uri)) {
|
||||
array.splice(array.indexOf(uri), 1)
|
||||
}
|
||||
PrefUtils.put('local_record', JSON.stringify(array))
|
||||
}
|
||||
|
||||
static getAllVideos(): Array<string> {
|
||||
let array = PrefUtils.getStringArray('local_record')
|
||||
return array.filter(item => item.endsWith('.mp4'))
|
||||
}
|
||||
|
||||
static deleteAllVideos() {
|
||||
let imageArray = LocalMediaManager.getAllImages()
|
||||
let audioArray = LocalMediaManager.getAllAudios()
|
||||
let newArray = imageArray.concat(audioArray)
|
||||
PrefUtils.put('local_record', JSON.stringify(newArray))
|
||||
}
|
||||
|
||||
static getAllAudios(): Array<string> {
|
||||
let array = PrefUtils.getStringArray('local_record')
|
||||
return array.filter(item => item.endsWith('.mp3'))
|
||||
}
|
||||
|
||||
static deleteAllAudios() {
|
||||
let videoArray = LocalMediaManager.getAllVideos()
|
||||
let audioArray = LocalMediaManager.getAllImages()
|
||||
let newArray = videoArray.concat(audioArray)
|
||||
PrefUtils.put('local_record', JSON.stringify(newArray))
|
||||
}
|
||||
|
||||
static getAllImages(): Array<string> {
|
||||
let array = PrefUtils.getStringArray('local_record')
|
||||
return array.filter(item => item.endsWith('.jpeg'))
|
||||
}
|
||||
|
||||
static deleteAllImages() {
|
||||
let videoArray = LocalMediaManager.getAllVideos()
|
||||
let audioArray = LocalMediaManager.getAllAudios()
|
||||
let newArray = videoArray.concat(audioArray)
|
||||
PrefUtils.put('local_record', JSON.stringify(newArray))
|
||||
}
|
||||
|
||||
static getAll(): Array<string> {
|
||||
return PrefUtils.getStringArray('local_record')
|
||||
}
|
||||
|
||||
static deleteAll() {
|
||||
PrefUtils.remove('local_record')
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
import { StrUtil } from '@pura/harmony-utils';
|
||||
import { UserEntity } from '../entity/UserEntity';
|
||||
import { PrefUtils } from '../utils/PrefUtils';
|
||||
import { ConfigManager } from './UserConfigManager';
|
||||
import { JSON } from '@kit.ArkTS';
|
||||
import { plainToInstance } from 'class-transformer';
|
||||
|
||||
class LoginGlobalManager {
|
||||
|
||||
private userInfo?: UserEntity;
|
||||
|
||||
/**
|
||||
* 保存当前用户基本信息
|
||||
* @param userEntity
|
||||
*/
|
||||
setUserInfo(userEntity: UserEntity) {
|
||||
this.userInfo = userEntity;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前用户基本信息
|
||||
* @returns
|
||||
*/
|
||||
getUserInfo(): UserEntity | undefined {
|
||||
return this.userInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存上一个用户基本信息
|
||||
* @param userEntity
|
||||
*/
|
||||
saveLastUserInfo(userEntity: UserEntity) {
|
||||
PrefUtils.put('last_userinfo', JSON.stringify(userEntity));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取上一个用户基本信息
|
||||
* @returns
|
||||
*/
|
||||
getLastUserInfo(): UserEntity | null {
|
||||
const str = PrefUtils.getString('last_userinfo');
|
||||
if (StrUtil.isNotEmpty(str)) {
|
||||
const userEntity = plainToInstance(UserEntity, JSON.parse(str));
|
||||
return userEntity;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存上次登录方式
|
||||
* @param userEntity
|
||||
*/
|
||||
saveLastLoginType(type: string) {
|
||||
PrefUtils.put('last_login_type', type);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取上次登录方式
|
||||
* @returns
|
||||
*/
|
||||
getLastLoginType(): string {
|
||||
return PrefUtils.getString('last_login_type');
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户token
|
||||
* @param token
|
||||
*/
|
||||
saveToken(token: string) {
|
||||
PrefUtils.put('x-token', token);
|
||||
}
|
||||
|
||||
getToken(): string {
|
||||
return PrefUtils.getString('x-token');
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否已登录
|
||||
* @returns
|
||||
*/
|
||||
isLogin(): boolean {
|
||||
return !ConfigManager.isTemp();
|
||||
}
|
||||
|
||||
logout() {
|
||||
PrefUtils.remove('x-role');
|
||||
PrefUtils.remove('x-token');
|
||||
PrefUtils.remove('userConfig')
|
||||
}
|
||||
}
|
||||
|
||||
export const LoginManager = new LoginGlobalManager();
|
||||
|
|
@ -0,0 +1,119 @@
|
|||
import { MediaRecordEntity } from '../entity/MediaRecordEntity';
|
||||
import { LocalMediaManager } from './LocalMediaManager';
|
||||
import { FileUtil, NumberUtil } from '@pura/harmony-utils';
|
||||
import { fileIo as fs } from '@kit.CoreFileKit';
|
||||
import { media } from '@kit.MediaKit';
|
||||
|
||||
export enum MediaAction {
|
||||
ADD, DELETE, CLEAR
|
||||
}
|
||||
|
||||
export enum MediaType {
|
||||
VIDEO, IMAGE, AUDIO
|
||||
}
|
||||
|
||||
export class MediaManager {
|
||||
|
||||
/**
|
||||
* 获取相册中保存的视频
|
||||
* @returns
|
||||
*/
|
||||
static async getVideoList(): Promise<Array<MediaRecordEntity>> {
|
||||
try {
|
||||
let mediaList = new Array<MediaRecordEntity>()
|
||||
|
||||
let videoUris = LocalMediaManager.getAllVideos()
|
||||
for (let i = 0; i < videoUris.length; i++) {
|
||||
try {
|
||||
let uri = videoUris[i]
|
||||
let record = new MediaRecordEntity(uri)
|
||||
record.name = FileUtil.getFileName(uri)
|
||||
let file = FileUtil.openSync(uri)
|
||||
|
||||
let videoSize: media.PixelMapParams = {}
|
||||
let avMetaDataExtractor: media.AVMetadataExtractor = await media.createAVMetadataExtractor();
|
||||
avMetaDataExtractor.fdSrc = file;
|
||||
let metadata = await avMetaDataExtractor.fetchMetadata();
|
||||
videoSize.width = parseInt(metadata.videoWidth as string);
|
||||
videoSize.height = parseInt(metadata.videoHeight as string);
|
||||
|
||||
let avImageGenerator = await media.createAVImageGenerator();
|
||||
if (avImageGenerator) {
|
||||
avImageGenerator.fdSrc = file;
|
||||
record.thumb =
|
||||
await avImageGenerator.fetchFrameByTime(0, media.AVImageQueryOptions.AV_IMAGE_QUERY_CLOSEST_SYNC,
|
||||
videoSize);
|
||||
} else {
|
||||
console.error('Create AVImageGenerator failed!');
|
||||
}
|
||||
mediaList.push(record)
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
}
|
||||
return Promise.resolve(mediaList)
|
||||
} catch (err) {
|
||||
console.error('video failed with err: ' + err);
|
||||
return Promise.reject(err)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取相册中保存的图片
|
||||
* @returns
|
||||
*/
|
||||
static async getImageList(): Promise<Array<MediaRecordEntity>> {
|
||||
let mediaList = new Array<MediaRecordEntity>()
|
||||
|
||||
let imageUri = LocalMediaManager.getAllImages()
|
||||
for (let i = 0; i < imageUri.length; i++) {
|
||||
try {
|
||||
let uri = imageUri[i]
|
||||
let file = FileUtil.openSync(uri)
|
||||
let record = new MediaRecordEntity(uri)
|
||||
record.name = FileUtil.getFileName(uri)
|
||||
mediaList.push(record)
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
}
|
||||
return Promise.resolve(mediaList)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取保存的音频
|
||||
* @returns
|
||||
*/
|
||||
static async getAudioList(): Promise<Array<MediaRecordEntity>> {
|
||||
try {
|
||||
let mediaList = new Array<MediaRecordEntity>()
|
||||
|
||||
let audioUris = LocalMediaManager.getAllAudios()
|
||||
for (let i = 0; i < audioUris.length; i++) {
|
||||
let uri = audioUris[i]
|
||||
let filePath = FileUtil.getFilePath(uri)
|
||||
if (FileUtil.accessSync(filePath)) {
|
||||
let record = new MediaRecordEntity(filePath)
|
||||
record.name = FileUtil.getFileName(filePath)
|
||||
let file = fs.openSync(filePath, fs.OpenMode.READ_WRITE)
|
||||
let stat = fs.statSync(file.fd)
|
||||
record.createTime = stat.ctime
|
||||
let avMetadataExtractor = await media.createAVMetadataExtractor()
|
||||
avMetadataExtractor.fdSrc = file
|
||||
// 获取元数据(promise模式)
|
||||
let result = await avMetadataExtractor.fetchMetadata()
|
||||
record.duration = result.duration ? NumberUtil.toNumber(result.duration) : 0
|
||||
avMetadataExtractor.release()
|
||||
fs.close(file)
|
||||
mediaList.push(record)
|
||||
} else {
|
||||
LocalMediaManager.delete(uri)
|
||||
}
|
||||
}
|
||||
return Promise.resolve(mediaList)
|
||||
} catch (err) {
|
||||
console.error('audio failed with err: ' + err);
|
||||
return Promise.reject(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
import { systemShare } from '@kit.ShareKit';
|
||||
import { uniformTypeDescriptor as utd } from '@kit.ArkData';
|
||||
import { BusinessError } from '@kit.BasicServicesKit';
|
||||
import { AppUtil, FileUtil } from '@pura/harmony-utils';
|
||||
|
||||
export class ShareManager {
|
||||
/**
|
||||
* 分享文件
|
||||
* @param path
|
||||
*/
|
||||
static shareFile(path: string) {
|
||||
// 获取精准的utd类型
|
||||
let ext = ''
|
||||
let type = ''
|
||||
if (path.endsWith('.mp4')) {
|
||||
ext = '.mp4'
|
||||
type = utd.UniformDataType.VIDEO
|
||||
} else if (path.endsWith('.mp3')) {
|
||||
ext = '.mp3'
|
||||
type = utd.UniformDataType.AUDIO
|
||||
} else if (path.endsWith('.jpeg')) {
|
||||
ext = '.jpeg'
|
||||
type = utd.UniformDataType.IMAGE
|
||||
}
|
||||
let utdTypeId = utd.getUniformDataTypeByFilenameExtension(ext, type);
|
||||
let shareData: systemShare.SharedData = new systemShare.SharedData({
|
||||
utd: utdTypeId,
|
||||
uri: FileUtil.getUriFromPath(path)
|
||||
});
|
||||
let controller: systemShare.ShareController = new systemShare.ShareController(shareData);
|
||||
controller.show(AppUtil.getContext(), {
|
||||
selectionMode: systemShare.SelectionMode.SINGLE,
|
||||
previewMode: systemShare.SharePreviewMode.DETAIL,
|
||||
}).then(() => {
|
||||
console.info('ShareController show success.');
|
||||
}).catch((error: BusinessError) => {
|
||||
console.error(`ShareController show error. code: ${error.code}, message: ${error.message}`);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,368 @@
|
|||
import { ArrayUtil, PermissionUtil, StrUtil } from '@pura/harmony-utils';
|
||||
import { apiService } from '../net/ApiService';
|
||||
import { PrefUtils } from '../utils/PrefUtils';
|
||||
import { JSON } from '@kit.ArkTS';
|
||||
import { UserConfigEntity } from '../entity/UserConfigEntity';
|
||||
import { instanceToPlain, plainToInstance } from 'class-transformer';
|
||||
import { BannerEntity } from '../entity/BannerEntity';
|
||||
import identifier from '@ohos.identifier.oaid';
|
||||
import { LoginManager } from './LoginGlobalManager';
|
||||
import { WxVideoConfigEntity } from '../entity/WxVideoConfig';
|
||||
|
||||
class UserConfigManager {
|
||||
private INVALID_OAID = "00000000-0000-0000-0000-000000000000";
|
||||
|
||||
async getOaid(): Promise<string> {
|
||||
try {
|
||||
const isGranted = await PermissionUtil.checkRequestPermissions('ohos.permission.APP_TRACKING_CONSENT');
|
||||
if (isGranted) {
|
||||
const oaid = await identifier.getOAID();
|
||||
if (StrUtil.isNotEmpty(oaid) && oaid !== this.INVALID_OAID) {
|
||||
PrefUtils.put("oaid", oaid)
|
||||
return Promise.resolve(oaid);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
return Promise.resolve('');
|
||||
}
|
||||
|
||||
async getUserConfig(): Promise<void> {
|
||||
if (StrUtil.isNotEmpty(PrefUtils.getString('userConfig'))) {
|
||||
const str = PrefUtils.getString('userConfig');
|
||||
const userConfig = plainToInstance(UserConfigEntity, JSON.parse(str));
|
||||
this.saveUserConfig(userConfig);
|
||||
return Promise.resolve()
|
||||
} else {
|
||||
return this.userConfig();
|
||||
}
|
||||
}
|
||||
|
||||
async userConfig(): Promise<void> {
|
||||
try {
|
||||
const oaid = PrefUtils.getString('oaid');
|
||||
const result = await apiService.userConfig(oaid);
|
||||
if (result.isSuccess()) {
|
||||
const userConfig = plainToInstance(UserConfigEntity, result.data);
|
||||
PrefUtils.put("userConfig", JSON.stringify(instanceToPlain(userConfig)))
|
||||
this.saveUserConfig(userConfig);
|
||||
return Promise.resolve();
|
||||
} else {
|
||||
return Promise.reject(result.message);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
return Promise.reject(e);
|
||||
}
|
||||
}
|
||||
|
||||
private saveUserConfig(config: UserConfigEntity) {
|
||||
LoginManager.saveToken(config.token);
|
||||
this.saveIsTemp(config.temp);
|
||||
if (config.config !== null) {
|
||||
this.saveGuideEnable(config.config.guideEnable);
|
||||
this.saveGuideHint(config.config.guideHint);
|
||||
this.saveGuidePayEnable(config.config.guidePayEnable);
|
||||
this.saveNoLoginPayEnable(config.config.noLoginPayEnable);
|
||||
this.savePayAgreementEnable(config.config.payAgreementEnable);
|
||||
this.saveWxVideoEnable(config.config.wxVideoEnable);
|
||||
this.savePlaybackEnable(config.config.playbackEnable);
|
||||
this.saveLoginType(config.config.loginType);
|
||||
this.saveWxVideoCourse(config.config.wxVideoCourse);
|
||||
this.savePlaybackCourse(config.config.wxPlaybackCourse);
|
||||
this.saveWxPlaybackJoinType(config.config.wxPlaybackJoinType);
|
||||
this.saveWxVideoConfig(config.config.wxVideoConfig);
|
||||
this.saveWxVideoServiceEnable(config.config.wxVideoServiceEnable);
|
||||
this.saveDomainMap(config.config.domainMap);
|
||||
this.saveCopyContainsList(config.config.copyContainsList);
|
||||
this.saveHomeBanner(config.config.homeBanners);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否同意隐私政策
|
||||
* @param agree
|
||||
*/
|
||||
saveIsAgreePrivacy(agree: boolean) {
|
||||
PrefUtils.put('agree_privacy', agree);
|
||||
}
|
||||
|
||||
isAgreePrivacy(): boolean {
|
||||
return PrefUtils.getBoolean('agree_privacy');
|
||||
}
|
||||
|
||||
/**
|
||||
* 首次使用app
|
||||
* @param isFirst
|
||||
*/
|
||||
saveFirstUse(isFirst: boolean) {
|
||||
PrefUtils.put('is_first', isFirst);
|
||||
}
|
||||
|
||||
isFirstUse(): boolean {
|
||||
return PrefUtils.getBoolean('is_first', true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户角色
|
||||
* @param temp true临时用户 ,false登录用户
|
||||
*/
|
||||
saveIsTemp(temp: boolean) {
|
||||
PrefUtils.put('x-role', temp);
|
||||
}
|
||||
|
||||
isTemp(): boolean {
|
||||
return PrefUtils.getBoolean('x-role', true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否启用引导页
|
||||
* @param enable
|
||||
*/
|
||||
saveGuideEnable(enable: boolean) {
|
||||
PrefUtils.put('guide_enable', enable);
|
||||
}
|
||||
|
||||
isGuideEnable(): boolean {
|
||||
return PrefUtils.getBoolean('guide_enable', true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 引导页提示语
|
||||
* @param enable
|
||||
*/
|
||||
saveGuideHint(hint: string) {
|
||||
PrefUtils.put('guide_hint', hint);
|
||||
}
|
||||
|
||||
getGuideHint(): string {
|
||||
return PrefUtils.getString('guide_hint');
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否启用引导页支付
|
||||
* @param enable
|
||||
*/
|
||||
saveGuidePayEnable(enable: boolean) {
|
||||
PrefUtils.put('guide_pay_enable', enable);
|
||||
}
|
||||
|
||||
isGuidePayEnable(): boolean {
|
||||
return PrefUtils.getBoolean('guide_pay_enable', true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否启用未登录支付
|
||||
* @param enable
|
||||
*/
|
||||
saveNoLoginPayEnable(enable: boolean) {
|
||||
PrefUtils.put('nologin_pay', enable);
|
||||
}
|
||||
|
||||
isNoLoginPayEnable(): boolean {
|
||||
return PrefUtils.getBoolean('nologin_pay', true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否显示支付协议
|
||||
* @param enable
|
||||
*/
|
||||
savePayAgreementEnable(enable: boolean) {
|
||||
PrefUtils.put('pay_agreement', enable);
|
||||
}
|
||||
|
||||
isPayAgreementEnable(): boolean {
|
||||
return PrefUtils.getBoolean('pay_agreement', true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否启用视频号功能
|
||||
* @param enable
|
||||
*/
|
||||
saveWxVideoEnable(enable: boolean) {
|
||||
PrefUtils.put('wx_video_enable', enable);
|
||||
}
|
||||
|
||||
isWxVideoEnable(): boolean {
|
||||
return PrefUtils.getBoolean('wx_video_enable', true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否启用直播回放功能
|
||||
* @param enable
|
||||
*/
|
||||
savePlaybackEnable(enable: boolean) {
|
||||
PrefUtils.put('playback_enable', enable);
|
||||
}
|
||||
|
||||
isPlaybackEnable(): boolean {
|
||||
return PrefUtils.getBoolean('playback_enable', true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否已绑定视频号助手
|
||||
* @param isBind
|
||||
*/
|
||||
saveBindWxVideoHelper(isBind: boolean) {
|
||||
PrefUtils.put('bind_wx_video', isBind);
|
||||
}
|
||||
|
||||
isBindWxVideoHelper(): boolean {
|
||||
return PrefUtils.getBoolean('bind_wx_video');
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否已绑定直播回放助手
|
||||
* @param isBind
|
||||
*/
|
||||
saveBindWxPlaybackHelper(isBind: boolean) {
|
||||
PrefUtils.put('bind_wx_playback', isBind);
|
||||
}
|
||||
|
||||
isBindWxPlaybackHelper(): boolean {
|
||||
return PrefUtils.getBoolean('bind_wx_playback');
|
||||
}
|
||||
|
||||
/**
|
||||
* 支持的登录类型
|
||||
* @param array
|
||||
*/
|
||||
saveLoginType(array?: Array<string>) {
|
||||
if (ArrayUtil.isNotEmpty(array)) {
|
||||
PrefUtils.put('login_type', JSON.stringify(array));
|
||||
}
|
||||
}
|
||||
|
||||
getLoginType(): Array<string> {
|
||||
const str = PrefUtils.getString('login_type');
|
||||
if (StrUtil.isNotEmpty(str)) {
|
||||
return JSON.parse(str) as Array<string>;
|
||||
}
|
||||
return new Array('phone');
|
||||
}
|
||||
|
||||
/**
|
||||
* 视频号教程链接
|
||||
* @param url
|
||||
*/
|
||||
saveWxVideoCourse(url?: string) {
|
||||
if (StrUtil.isNotEmpty(url)) {
|
||||
PrefUtils.put('wx_video_course', url!!);
|
||||
}
|
||||
}
|
||||
|
||||
getWxVideoCourse(): string {
|
||||
return PrefUtils.getString('wx_video_course');
|
||||
}
|
||||
|
||||
/**
|
||||
* 直播回放教程链接
|
||||
* @param url
|
||||
*/
|
||||
savePlaybackCourse(url?: string) {
|
||||
if (StrUtil.isNotEmpty(url)) {
|
||||
PrefUtils.put('playback_course', url!!);
|
||||
}
|
||||
}
|
||||
|
||||
getPlaybackCourse(): string {
|
||||
return PrefUtils.getString('playback_course');
|
||||
}
|
||||
|
||||
/**
|
||||
* 直播回放加群方式
|
||||
* @param type
|
||||
*/
|
||||
saveWxPlaybackJoinType(type?: string) {
|
||||
if (StrUtil.isNotEmpty(type)) {
|
||||
PrefUtils.put('playback_join_type', type!!);
|
||||
}
|
||||
}
|
||||
|
||||
getPlaybackJoinType(): string {
|
||||
return PrefUtils.getString('playback_join_type');
|
||||
}
|
||||
|
||||
/**
|
||||
* 直播回放小程序跳转配置
|
||||
* @param config
|
||||
*/
|
||||
saveWxVideoConfig(config: WxVideoConfigEntity) {
|
||||
PrefUtils.put('wx_video_config', JSON.stringify(config))
|
||||
}
|
||||
|
||||
getWxVideoConfig(): WxVideoConfigEntity | null {
|
||||
const str = PrefUtils.getString('wx_video_config')
|
||||
if (StrUtil.isNotEmpty(str)) {
|
||||
return JSON.parse(str) as WxVideoConfigEntity
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* 视频号助手是否可用
|
||||
* @param enable
|
||||
*/
|
||||
saveWxVideoServiceEnable(enable: boolean) {
|
||||
PrefUtils.put("wx_video_service_enable", enable)
|
||||
}
|
||||
|
||||
isWxVideoServiceEnable(): boolean {
|
||||
return PrefUtils.getBoolean('wx_video_service_enable', true)
|
||||
}
|
||||
|
||||
/**
|
||||
* 网站主机名
|
||||
* @param domains
|
||||
*/
|
||||
saveDomainMap(domains: object) {
|
||||
if (domains) {
|
||||
PrefUtils.put('domain_map', JSON.stringify(domains));
|
||||
}
|
||||
}
|
||||
|
||||
getDomainMap(): object {
|
||||
const str = PrefUtils.getString('domain_map');
|
||||
if (StrUtil.isNotEmpty(str)) {
|
||||
return JSON.parse(str)!!
|
||||
}
|
||||
return new Object();
|
||||
}
|
||||
|
||||
/**
|
||||
* 链接识别配置
|
||||
* @param array
|
||||
*/
|
||||
saveCopyContainsList(array: Array<string>) {
|
||||
PrefUtils.put('copy_contains_list', JSON.stringify(array))
|
||||
}
|
||||
|
||||
getCopyContainsList(): Array<string> {
|
||||
let array = PrefUtils.getStringArray('copy_contains_list')
|
||||
if (array.length !== 0) {
|
||||
return array
|
||||
}
|
||||
return ['http://', 'https://']
|
||||
}
|
||||
|
||||
/**
|
||||
* 首页banner
|
||||
* @param array
|
||||
*/
|
||||
saveHomeBanner(array?: Array<BannerEntity>) {
|
||||
if (ArrayUtil.isNotEmpty(array)) {
|
||||
PrefUtils.put('home_banner', JSON.stringify(array));
|
||||
}
|
||||
}
|
||||
|
||||
getHomeBanner(): Array<BannerEntity> {
|
||||
const str = PrefUtils.getString('home_banner');
|
||||
if (StrUtil.isNotEmpty(str)) {
|
||||
return JSON.parse(str) as Array<BannerEntity>;
|
||||
}
|
||||
return new Array();
|
||||
}
|
||||
}
|
||||
|
||||
export const ConfigManager = new UserConfigManager()
|
||||
|
|
@ -0,0 +1,116 @@
|
|||
export class Api {
|
||||
/**
|
||||
* 获取用户配置信息
|
||||
*/
|
||||
static readonly USER_CONFIG = '/api/user/config';
|
||||
|
||||
/**
|
||||
* 用户基本信息
|
||||
*/
|
||||
static readonly USERINFO = '/api/user';
|
||||
|
||||
/**
|
||||
* 事件上报
|
||||
*/
|
||||
static readonly EVENT_REPORT = '/api/user/event'
|
||||
|
||||
/**
|
||||
* 图片上传
|
||||
*/
|
||||
static readonly UPLOAD_IMAGE = '/api/user/upload'
|
||||
|
||||
/**
|
||||
* 意见反馈
|
||||
*/
|
||||
static readonly FEEDBACK = '/api/user/feedback'
|
||||
|
||||
/**
|
||||
* 发送验证码
|
||||
*/
|
||||
static readonly SEND_CODE = '/api/user/code';
|
||||
|
||||
/**
|
||||
* 用户登录
|
||||
*/
|
||||
static readonly LOGIN = '/api/user/login';
|
||||
|
||||
/**
|
||||
* 扫码登录
|
||||
*/
|
||||
static readonly QRCODE_LOGIN = '/api/app/code';
|
||||
|
||||
/**
|
||||
* 用户注销
|
||||
*/
|
||||
static readonly USER_DESTROY = '/api/user/destroy';
|
||||
|
||||
/**
|
||||
* 用户账号列表
|
||||
*/
|
||||
static readonly ACCOUNT_LIST = '/api/user/account';
|
||||
|
||||
/**
|
||||
* 套餐列表
|
||||
*/
|
||||
static readonly GOODS_LIST = '/api/order/goods';
|
||||
|
||||
/**
|
||||
* 创建订单
|
||||
*/
|
||||
static readonly CREATE_ORDER = '/api/order';
|
||||
|
||||
/**
|
||||
* 微信客服
|
||||
*/
|
||||
static readonly WX_SERVICE = '/api/weixin/service'
|
||||
|
||||
/**
|
||||
* 钻石信息
|
||||
*/
|
||||
static readonly USER_DIAMOND_INFO = '/api/diamond'
|
||||
|
||||
/**
|
||||
* 权限验证
|
||||
*/
|
||||
static readonly USER_AUTH = '/api/user/auth';
|
||||
|
||||
/**
|
||||
* 首页顶部通知
|
||||
*/
|
||||
static readonly NOTICE_LIST = '/api/user/notice';
|
||||
|
||||
/**
|
||||
* 链接提取
|
||||
*/
|
||||
static readonly MATERIAL_INFO = '/api/material';
|
||||
|
||||
/**
|
||||
* 视频号和直播回放提取
|
||||
*/
|
||||
static readonly WX_VIDEO = '/api/weixin/video/log';
|
||||
|
||||
/**
|
||||
* 跳转至微信发送视频号给客服
|
||||
*/
|
||||
static readonly WX_VIDEO_SERVICE = '/api/weixin/video/service'
|
||||
|
||||
/**
|
||||
* 绑定微信用户信息
|
||||
*/
|
||||
static readonly BIND_WX_USER_INFO = '/api/weixin/user/info'
|
||||
|
||||
/**
|
||||
* 下载记录
|
||||
*/
|
||||
static readonly DOWNLOAD_HISTORY_LIST = '/api/material/log'
|
||||
|
||||
/**
|
||||
* 素材列表
|
||||
*/
|
||||
static readonly MATERIAL_LIST = '/api/user/mat/search'
|
||||
|
||||
/**
|
||||
* 素材分类列表
|
||||
*/
|
||||
static readonly MATERIAL_CATE_LIST = '/api/mat/cate'
|
||||
}
|
||||
|
|
@ -0,0 +1,390 @@
|
|||
import { Api } from './Api';
|
||||
import { AxiosRequest } from './AxiosRequest';
|
||||
import { HttpResult } from './HttpResult';
|
||||
import { deviceInfo } from '@kit.BasicServicesKit';
|
||||
import { DeviceUtil, FileUtil } from '@pura/harmony-utils';
|
||||
import { LoginRequest } from './request/LoginRequest';
|
||||
import { FormData } from '@ohos/axios';
|
||||
import { fileIo } from '@kit.CoreFileKit';
|
||||
import { JSON } from '@kit.ArkTS';
|
||||
|
||||
class ApiService {
|
||||
/**
|
||||
* 用户配置
|
||||
* @param oaid
|
||||
* @returns
|
||||
*/
|
||||
userConfig(oaid: string): Promise<HttpResult> {
|
||||
const params: Record<string, string> = {
|
||||
'oaid': oaid,
|
||||
'os_version': deviceInfo.buildVersion.toString(),
|
||||
'imei': DeviceUtil.getDeviceId(),
|
||||
'cid': ''
|
||||
}
|
||||
return AxiosRequest.get<HttpResult>(Api.USER_CONFIG, params)
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户信息
|
||||
* @returns
|
||||
*/
|
||||
userinfo(): Promise<HttpResult> {
|
||||
return AxiosRequest.get<HttpResult>(Api.USERINFO)
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新用户信息
|
||||
* @returns
|
||||
*/
|
||||
updateUserinfo(params: Record<string, string>): Promise<HttpResult> {
|
||||
return AxiosRequest.put<HttpResult>(Api.USERINFO, params)
|
||||
}
|
||||
|
||||
/**
|
||||
* 事件上报
|
||||
* @param key
|
||||
* @param value
|
||||
* @param extra
|
||||
* @returns
|
||||
*/
|
||||
eventReport(key: string, value: string, extra: string): Promise<HttpResult> {
|
||||
const params: Record<string, string> = {
|
||||
'source': 'android',
|
||||
'type': 'click',
|
||||
'key': key,
|
||||
'value': value,
|
||||
'extra': extra
|
||||
}
|
||||
return AxiosRequest.post<HttpResult>(Api.EVENT_REPORT, params);
|
||||
}
|
||||
|
||||
/**
|
||||
* 图片上传
|
||||
* @returns
|
||||
*/
|
||||
uploadImage(base64: string, scene: string): Promise<HttpResult> {
|
||||
const data: Record<string, string> = {
|
||||
'file': base64
|
||||
}
|
||||
const params: Record<string, string> = {
|
||||
'type': 'base64',
|
||||
'scene': scene
|
||||
}
|
||||
return AxiosRequest.request({
|
||||
url: Api.UPLOAD_IMAGE,
|
||||
method: 'post',
|
||||
data: data,
|
||||
params: params // query参数
|
||||
})
|
||||
}
|
||||
|
||||
feedback(type: string, content: string, contact: string, images: Array<string>): Promise<HttpResult> {
|
||||
const params: Record<string, Object> = {
|
||||
'type': type,
|
||||
'content': content,
|
||||
'contact': contact,
|
||||
'images': images
|
||||
}
|
||||
return AxiosRequest.post(Api.FEEDBACK, params)
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送验证码
|
||||
* @returns
|
||||
*/
|
||||
sendCode(phone: string): Promise<HttpResult> {
|
||||
const params: Record<string, string> = { 'phone': phone }
|
||||
return AxiosRequest.post<HttpResult>(Api.SEND_CODE, params)
|
||||
}
|
||||
|
||||
/**
|
||||
* 手机号登录
|
||||
* @returns
|
||||
*/
|
||||
loginByPhone(phone: string, code: string, timestamp: string, isBind: boolean = false): Promise<HttpResult> {
|
||||
const params: LoginRequest = {
|
||||
login_type: 'phone',
|
||||
phone: {
|
||||
'phone': phone,
|
||||
'code': code,
|
||||
'timestamp': timestamp
|
||||
},
|
||||
bind: isBind
|
||||
}
|
||||
return AxiosRequest.post<HttpResult>(Api.LOGIN, params)
|
||||
}
|
||||
|
||||
/**
|
||||
* 微信登录
|
||||
* @returns
|
||||
*/
|
||||
loginByWX(code: string, isBind: boolean = false): Promise<HttpResult> {
|
||||
const params: LoginRequest = {
|
||||
login_type: 'weixin',
|
||||
weixin: {
|
||||
'code': code,
|
||||
'code_type': ''
|
||||
},
|
||||
bind: isBind
|
||||
}
|
||||
return AxiosRequest.post<HttpResult>(Api.LOGIN, params)
|
||||
}
|
||||
|
||||
/**
|
||||
* 微信登录
|
||||
* @returns
|
||||
*/
|
||||
loginByCode(code: string): Promise<HttpResult> {
|
||||
const params: Record<string, string> = { 'key': code }
|
||||
return AxiosRequest.put<HttpResult>(Api.QRCODE_LOGIN, params)
|
||||
}
|
||||
|
||||
/**
|
||||
* 注销账户
|
||||
* @returns
|
||||
*/
|
||||
userDestroy(): Promise<HttpResult> {
|
||||
return AxiosRequest.post<HttpResult>(Api.USER_DESTROY)
|
||||
}
|
||||
|
||||
/**
|
||||
* 解绑账号
|
||||
* @returns
|
||||
*/
|
||||
unbind(loginType: string): Promise<HttpResult> {
|
||||
const params: LoginRequest = {
|
||||
login_type: loginType,
|
||||
unbind: true
|
||||
}
|
||||
return AxiosRequest.post<HttpResult>(Api.LOGIN, params);
|
||||
}
|
||||
|
||||
/**
|
||||
* 账号列表
|
||||
* @returns
|
||||
*/
|
||||
accountList(scene: string): Promise<HttpResult> {
|
||||
const params: Record<string, string> = { 'scene': scene }
|
||||
return AxiosRequest.get<HttpResult>(Api.ACCOUNT_LIST, params);
|
||||
}
|
||||
|
||||
/**
|
||||
* 切换账户
|
||||
* @param userId
|
||||
* @returns
|
||||
*/
|
||||
changeAccount(userId: string): Promise<HttpResult> {
|
||||
const params: LoginRequest = {
|
||||
login_type: 'device',
|
||||
device: {
|
||||
'user_id': userId
|
||||
}
|
||||
}
|
||||
return AxiosRequest.post<HttpResult>(Api.LOGIN, params)
|
||||
}
|
||||
|
||||
/**
|
||||
* 套餐列表
|
||||
* @returns
|
||||
*/
|
||||
goodsList(type: string): Promise<HttpResult> {
|
||||
const params: Record<string, string> = { 'type': type }
|
||||
return AxiosRequest.get<HttpResult>(Api.GOODS_LIST, params)
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建订单
|
||||
* @returns
|
||||
*/
|
||||
createOrder(goodsId: string, payType: string, source: string, coupon: string): Promise<HttpResult> {
|
||||
const params: Record<string, string> = {
|
||||
'goods_id': goodsId,
|
||||
'pay_type': payType,
|
||||
'source': source,
|
||||
'pay_source': 'app',
|
||||
'coupon': coupon
|
||||
}
|
||||
return AxiosRequest.post<HttpResult>(Api.CREATE_ORDER, params)
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询订单
|
||||
* @param orderId
|
||||
* @returns
|
||||
*/
|
||||
getOrderInfo(orderId: string): Promise<HttpResult> {
|
||||
const params: Record<string, string> = { 'order_id': orderId}
|
||||
return AxiosRequest.get<HttpResult>(Api.CREATE_ORDER, params)
|
||||
}
|
||||
|
||||
/**
|
||||
* 微信客服
|
||||
* @returns
|
||||
*/
|
||||
wxService(): Promise<HttpResult> {
|
||||
return AxiosRequest.get<HttpResult>(Api.WX_SERVICE)
|
||||
}
|
||||
|
||||
/**
|
||||
* 钻石信息
|
||||
*/
|
||||
getDiamondInfo(): Promise<HttpResult> {
|
||||
return AxiosRequest.get(Api.USER_DIAMOND_INFO)
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查权限
|
||||
* @param scene wechat download
|
||||
* @returns
|
||||
*/
|
||||
checkPermission(scene: string): Promise<HttpResult> {
|
||||
const params: Record<string, string> = { 'scene': scene }
|
||||
return AxiosRequest.get<HttpResult>(Api.USER_AUTH, params)
|
||||
}
|
||||
|
||||
/**
|
||||
* 上报权限
|
||||
* @param scene
|
||||
* @param count
|
||||
* @returns
|
||||
*/
|
||||
sendCheckPermission(scene: string, count: number): Promise<HttpResult> {
|
||||
const params: Record<string, Object> = { 'scene': scene, 'count': count }
|
||||
return AxiosRequest.post<HttpResult>(Api.USER_AUTH, params)
|
||||
}
|
||||
|
||||
/**
|
||||
* 首页顶部通知
|
||||
* @returns
|
||||
*/
|
||||
noticeList(): Promise<HttpResult> {
|
||||
return AxiosRequest.get<HttpResult>(Api.NOTICE_LIST)
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送链接
|
||||
* @returns
|
||||
*/
|
||||
getMaterialInfo(content: string): Promise<HttpResult> {
|
||||
const params: Record<string, string> = { 'content': content }
|
||||
return AxiosRequest.post<HttpResult>(Api.MATERIAL_INFO, params)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取提取状态信息
|
||||
* @returns
|
||||
*/
|
||||
analysisMaterial(logId: string): Promise<HttpResult> {
|
||||
const params: Record<string, string> = { 'logid': logId }
|
||||
return AxiosRequest.get<HttpResult>(Api.MATERIAL_INFO, params)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取视频号和直播回放
|
||||
* @returns
|
||||
*/
|
||||
wxVideoList(scene: string): Promise<HttpResult> {
|
||||
const params: Record<string, string> = { 'v': 'v2', 'scene': scene }
|
||||
return AxiosRequest.get<HttpResult>(Api.WX_VIDEO, params)
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除视频号和直播回放
|
||||
* @returns
|
||||
*/
|
||||
deleteWxVideo(logId: string): Promise<HttpResult> {
|
||||
const params: Record<string, string> = { 'logId': logId }
|
||||
return AxiosRequest.delete<HttpResult>(Api.WX_VIDEO, params)
|
||||
}
|
||||
|
||||
/**
|
||||
* 上报下载状态
|
||||
*/
|
||||
reportDownLoadStatus(logId: string, status: string, size: string, message: string): Promise<HttpResult> {
|
||||
const params: Record<string, string> = {
|
||||
'logid': logId,
|
||||
'status': status,
|
||||
'size': size,
|
||||
'message': message
|
||||
}
|
||||
return AxiosRequest.put<HttpResult>(Api.MATERIAL_INFO, params)
|
||||
}
|
||||
|
||||
/**
|
||||
* 跳转至微信发送视频号给客服
|
||||
*/
|
||||
wxVideoService(): Promise<HttpResult> {
|
||||
return AxiosRequest.get<HttpResult>(Api.WX_VIDEO_SERVICE)
|
||||
}
|
||||
|
||||
/**
|
||||
* 跳转至微信发送视频号给客服
|
||||
*/
|
||||
bindWxUserInfo(code: string): Promise<HttpResult> {
|
||||
return AxiosRequest.request({
|
||||
url: Api.BIND_WX_USER_INFO,
|
||||
method: 'post',
|
||||
params: { code: code } // query参数
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取下载记录
|
||||
* @returns
|
||||
*/
|
||||
getDownloadHistoryList(page: string, startTime: string, endTime: string): Promise<HttpResult> {
|
||||
const params: Record<string, string> = {
|
||||
'status': '2',
|
||||
'is_deleted': '0',
|
||||
'page': page,
|
||||
'size': '20',
|
||||
'start_time': startTime,
|
||||
'end_time': endTime
|
||||
}
|
||||
return AxiosRequest.get<HttpResult>(Api.DOWNLOAD_HISTORY_LIST, params)
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除下载记录
|
||||
* @returns
|
||||
*/
|
||||
deleteDownloadHistory(startTime: string, endTime: string): Promise<HttpResult> {
|
||||
const params: Record<string, string> = {
|
||||
'status': '2',
|
||||
'is_deleted': '0',
|
||||
'page': '1',
|
||||
'size': '9999',
|
||||
'start_time': startTime,
|
||||
'end_time': endTime
|
||||
}
|
||||
return AxiosRequest.delete<HttpResult>(Api.DOWNLOAD_HISTORY_LIST, params)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取素材列表
|
||||
* @returns
|
||||
*/
|
||||
getMaterialList(page: string, cateId: string = '', keywords: string = ''): Promise<HttpResult> {
|
||||
const params: Record<string, string> = {
|
||||
'page': page,
|
||||
'size': '20',
|
||||
'cate_id': cateId,
|
||||
'keywords': keywords
|
||||
}
|
||||
return AxiosRequest.get<HttpResult>(Api.MATERIAL_LIST, params)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取素材分类列表
|
||||
* @returns
|
||||
*/
|
||||
getMaterialCateList(page: string): Promise<HttpResult> {
|
||||
const params: Record<string, string> = {
|
||||
'page': page,
|
||||
'size': '50'
|
||||
}
|
||||
return AxiosRequest.get<HttpResult>(Api.MATERIAL_CATE_LIST, params)
|
||||
}
|
||||
}
|
||||
|
||||
export const apiService = new ApiService();
|
||||
|
|
@ -0,0 +1,168 @@
|
|||
import axios, { AxiosError, AxiosRequestConfig, AxiosResponse,
|
||||
FormData,
|
||||
InternalAxiosRequestConfig } from '@ohos/axios';
|
||||
import BuildProfile from 'BuildProfile';
|
||||
import { Constants } from '../common/Constants';
|
||||
import deviceInfo from '@ohos.deviceInfo';
|
||||
import { AppUtil, DeviceUtil, JSONUtil, MD5, RandomUtil, StrUtil } from '@pura/harmony-utils';
|
||||
import systemDateTime from '@ohos.systemDateTime';
|
||||
import { JSON } from '@kit.ArkTS';
|
||||
import { AESpkcs7paddingUtil } from '../utils/AESpkcs7paddingUtil';
|
||||
import { HttpResult } from './HttpResult';
|
||||
import { plainToInstance } from 'class-transformer';
|
||||
import { LoginManager } from '../manager/LoginGlobalManager';
|
||||
import { router } from '@kit.ArkUI';
|
||||
import { RouterUrls } from '../common/RouterUrls';
|
||||
import { EventConstants } from '../common/EventConstants';
|
||||
|
||||
const instance = axios.create({
|
||||
baseURL: BuildProfile.DEBUG ? Constants.TEST_URL : Constants.BASE_URL,
|
||||
timeout: 20000
|
||||
});
|
||||
|
||||
// 请求头拦截器
|
||||
instance.interceptors.request.use((config: InternalAxiosRequestConfig) => {
|
||||
config.headers.set('x-token', LoginManager.getToken())
|
||||
config.headers.set('x-app-id', Constants.APP_ID)
|
||||
config.headers.set('x-device-id', DeviceUtil.getDeviceId())
|
||||
config.headers.set('x-version', BuildProfile.VERSION_NAME)
|
||||
config.headers.set('x-mobile-brand', deviceInfo.brand)
|
||||
config.headers.set('x-mobile-model', deviceInfo.productModel)
|
||||
config.headers.set('x-base-version', BuildProfile.VERSION_NAME)
|
||||
config.headers.set('x-package', 'com.yuan.scmf')
|
||||
config.headers.set('x-platform', 'android')
|
||||
config.headers.set('x-channel', 'scmf_hmos')
|
||||
return config;
|
||||
}, (error: AxiosError) => {
|
||||
return Promise.reject(error);
|
||||
});
|
||||
|
||||
// 请求内容拦截器
|
||||
instance.interceptors.request.use((config: InternalAxiosRequestConfig) => {
|
||||
let url = config.url;
|
||||
if (!url?.includes("user/upload")) {
|
||||
let method = config.method?.toLowerCase();
|
||||
if (method === "post" || method === "put") {
|
||||
config.headers.set("Content-Type", "application/json; charset=utf-8");
|
||||
}
|
||||
}
|
||||
return config;
|
||||
}, (error: AxiosError) => {
|
||||
return Promise.reject(error);
|
||||
});
|
||||
|
||||
// 请求内容加密拦截器
|
||||
instance.interceptors.request.use((config: InternalAxiosRequestConfig) => {
|
||||
if (config.baseURL === Constants.BASE_URL) {
|
||||
config.params = config.params || {};
|
||||
config.params.nonce = RandomUtil.generateUUID36()
|
||||
config.params.timestamp = Math.trunc(systemDateTime.getTime() / 1000)
|
||||
let paramsMap = JSONUtil.jsonToMap(JSON.stringify(config.params));
|
||||
let arrayMap = Array.from(paramsMap);
|
||||
arrayMap.sort((a, b) => {
|
||||
return a[0].localeCompare(b[0])
|
||||
})
|
||||
paramsMap = new Map(arrayMap)
|
||||
let sortQueryString = "";
|
||||
paramsMap.forEach((value, key) => {
|
||||
sortQueryString += key + "=" + value + "&"
|
||||
})
|
||||
sortQueryString = sortQueryString.substring(0, sortQueryString.length - 1)
|
||||
let signature = MD5.digestSync(sortQueryString + '&' + MD5.digestSync(Constants.SIGNATURE));
|
||||
let method = config.method?.toLowerCase();
|
||||
if (method === "post" || method === "put") {
|
||||
if (config.data) {
|
||||
let dataStr = JSON.stringify(config.data);
|
||||
if (StrUtil.isNotEmpty(dataStr)) {
|
||||
signature = MD5.digestSync(sortQueryString + '&' + dataStr + "&" + MD5.digestSync(Constants.SIGNATURE));
|
||||
}
|
||||
}
|
||||
}
|
||||
config.params.signature = signature;
|
||||
}
|
||||
return config;
|
||||
}, (error: AxiosError) => {
|
||||
return Promise.reject(error);
|
||||
});
|
||||
|
||||
// 响应拦截器
|
||||
instance.interceptors.response.use((response: AxiosResponse) => {
|
||||
if (response.config.baseURL === (BuildProfile.DEBUG ? Constants.TEST_URL : Constants.BASE_URL)) {
|
||||
try {
|
||||
let contentType = response.headers['content-type'] as string;
|
||||
let dataString: string = '';
|
||||
if (StrUtil.isNotEmpty(contentType) && contentType?.includes("application/json")) {
|
||||
if (response.data !== null) {
|
||||
let isEncrypt = response.data['encrypt'] as boolean
|
||||
dataString = response.data['data'] as string;
|
||||
if (isEncrypt) {
|
||||
dataString = AESpkcs7paddingUtil.decryptNormal(dataString, Constants.ENCRYPT);
|
||||
let decData = JSON.parse(dataString) as Record<string, Object>;
|
||||
let decCode = decData['code'] as number;
|
||||
switch (decCode) {
|
||||
case 11018: {
|
||||
// 刷新首页
|
||||
AppUtil.getContext().eventHub.emit(EventConstants.HomeRefreshEvent);
|
||||
AppUtil.getContext().eventHub.emit(EventConstants.MineRefreshEvent);
|
||||
break;
|
||||
}
|
||||
case 19000: {
|
||||
// 跳转Vip页面
|
||||
router.push({url: RouterUrls.VIP_PAGE, params: { origin: response.config.url }})
|
||||
break;
|
||||
}
|
||||
case 1001003: {
|
||||
}
|
||||
case 1001004: {
|
||||
|
||||
}
|
||||
case 1001005: {
|
||||
// 跳转登录
|
||||
LoginManager.logout()
|
||||
router.push({url: RouterUrls.LOGIN_PAGE})
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
response.data = JSON.parse(dataString);
|
||||
console.error('AxiosResponse:' + JSON.stringify(response.data))
|
||||
return plainToInstance(HttpResult, JSON.parse(dataString));
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
return new HttpResult(-1, e);
|
||||
}
|
||||
}
|
||||
return response.data;
|
||||
}, (error: AxiosError) => {
|
||||
// 响应失败
|
||||
return Promise.reject(error);
|
||||
});
|
||||
|
||||
export class AxiosRequest {
|
||||
// 万能请求
|
||||
static request<T>(config: AxiosRequestConfig): Promise<T> {
|
||||
return instance.request<null, T>(config)
|
||||
}
|
||||
|
||||
// get请求
|
||||
static get<T>(url: string, params?: object): Promise<T> {
|
||||
return instance.get<null, T>(url, { params });
|
||||
}
|
||||
|
||||
// post请求
|
||||
static post<T>(url: string, data?: object): Promise<T> {
|
||||
return instance.post<null, T>(url, data);
|
||||
}
|
||||
|
||||
// put请求
|
||||
static put<T>(url: string, data?: object): Promise<T> {
|
||||
return instance.put<null, T>(url, data);
|
||||
}
|
||||
|
||||
// delete请求
|
||||
static delete<T>(url: string, params?: object): Promise<T> {
|
||||
return instance.delete<null, T>(url, { params });
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
export class HttpResult {
|
||||
code: number = 0;
|
||||
message: string = ""
|
||||
data?: object = undefined;
|
||||
|
||||
constructor(code: number, message: string, data?: object) {
|
||||
this.code = code;
|
||||
this.message = message;
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
isSuccess(): boolean {
|
||||
return this.code === 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,426 @@
|
|||
import { AppUtil, FileUtil, JSONUtil, StrUtil } from '@pura/harmony-utils';
|
||||
import { MediaEntity, VideoMaterial } from '../entity/MaterialInfoEntity';
|
||||
import url from '@ohos.url';
|
||||
import { Constants } from '../common/Constants';
|
||||
import axios, { AxiosHeaders, AxiosResponse, AxiosResponseHeaders } from '@ohos/axios';
|
||||
import { BusinessError, request } from '@kit.BasicServicesKit';
|
||||
import { MP4Parser } from '@ohos/mp4parser';
|
||||
import { JSON } from '@kit.ArkTS';
|
||||
|
||||
export interface DownloadCallback {
|
||||
onGetTotal?:(total: number) => void;
|
||||
onProgress?:(progress: number) => void;
|
||||
onPause?:() => void;
|
||||
onMerge?:(step: number) => void;
|
||||
onSuccess?:(filePath: string) => void;
|
||||
onCancel?:() => void;
|
||||
onFailed?:(err: string) => void;
|
||||
}
|
||||
|
||||
export class MediaDownloader {
|
||||
static getInstance(): MediaDownloader {
|
||||
return new MediaDownloader();
|
||||
}
|
||||
|
||||
/**
|
||||
* 缓存文件夹
|
||||
*/
|
||||
private cacheDir = FileUtil.getCacheDirPath() + FileUtil.separator;
|
||||
|
||||
/**
|
||||
* 任务对象
|
||||
*/
|
||||
private task?: request.agent.Task | null
|
||||
|
||||
/**
|
||||
* 下载回调
|
||||
*/
|
||||
private mCallback?: DownloadCallback;
|
||||
|
||||
/**
|
||||
* 文件名
|
||||
*/
|
||||
private fileName = '';
|
||||
|
||||
/**
|
||||
* 代理池
|
||||
*/
|
||||
private proxyList = new Array<string>();
|
||||
|
||||
callback(callback: DownloadCallback): MediaDownloader {
|
||||
this.mCallback = callback;
|
||||
return this;
|
||||
}
|
||||
|
||||
createHeaders(map?: Map<string, Object>): Record<string, string> {
|
||||
const headers: Record<string, string> = {};
|
||||
map?.forEach((value, key) => {
|
||||
headers[key] = value.toString();
|
||||
})
|
||||
return headers;
|
||||
}
|
||||
|
||||
setProxyList(list?: Array<string>): MediaDownloader {
|
||||
if (list && list.length > 0) {
|
||||
this.proxyList = list
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
async down(media: MediaEntity) {
|
||||
this.fileName = media.name;
|
||||
if (media.isM3u8) {
|
||||
// this.doM3u8Down();
|
||||
this.doException('暂不支持')
|
||||
} else if (media.isThreading) {
|
||||
// this.doThreadingDown();
|
||||
this.doMediaDown(media, media.isMerge ? 1 : 0);
|
||||
} else {
|
||||
this.doMediaDown(media, media.isMerge ? 1 : 0);
|
||||
}
|
||||
}
|
||||
|
||||
async doMediaDown(media: MediaEntity, step: number) {
|
||||
if (media instanceof VideoMaterial && step === 0) {
|
||||
await this.decodeWxVideo(media)
|
||||
}
|
||||
|
||||
let url = media.origin;
|
||||
if (step === 2 && media instanceof VideoMaterial) {
|
||||
url = media.speed_up === 1 || media.isThreading ? media.audio!!.url : media.audio!!.origin_url;
|
||||
} else {
|
||||
url = media.speed_up === 1 || media.isThreading ? media.url : media.origin_url;
|
||||
}
|
||||
|
||||
let headers: Record<string, string> = {}
|
||||
if (media.headers) {
|
||||
headers = this.createHeaders(JSONUtil.jsonToMap(JSON.stringify(media.headers)));
|
||||
}
|
||||
headers['User-Agent'] = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:139.0) Gecko/20100101 Firefox/139.0'
|
||||
headers['Accept'] = '*/*'
|
||||
|
||||
let isCanContinue = false;
|
||||
/*if (step === 0 || step === 1) {
|
||||
isCanContinue = await this.isCanContinue(url, media.currentLen)
|
||||
media.continueDownload = true;
|
||||
} else if (step === 2 && media instanceof VideoMaterial && media.audio) {
|
||||
isCanContinue = await this.isCanContinue(url, media.audio.currentLen)
|
||||
media.continueDownload = true;
|
||||
}*/
|
||||
|
||||
if (step === 0 && FileUtil.accessSync(this.cacheDir + this.fileName) && isCanContinue) {
|
||||
headers['Range'] = `bytes=${media.currentLen}-`;
|
||||
} else if (step == 1 && FileUtil.accessSync(this.cacheDir + media.cacheName) &&
|
||||
(isCanContinue || media.totalSize !== 0 && media.currentLen === media.totalSize)) {
|
||||
if (media instanceof VideoMaterial && media.audio && media.totalSize !== 0 && media.currentLen === media.totalSize) {
|
||||
this.doMerge(4) // 音频提取中
|
||||
this.doMediaDown(media, 2)
|
||||
} else {
|
||||
headers['Range'] = `bytes=${media.currentLen}-`;
|
||||
}
|
||||
} else if (step === 2 && media instanceof VideoMaterial && media.audio && FileUtil.accessSync(this.cacheDir + media.audio.cacheName) &&
|
||||
(isCanContinue || media.audio.totalSize !== 0 && media.audio.currentLen === media.audio.totalSize)) {
|
||||
if (media.audio.totalSize !== 0 && media.audio.currentLen == media.audio.totalSize) {
|
||||
this.doMerge(5) // 音视频合并中
|
||||
let videoPath = this.cacheDir + media.cacheName
|
||||
let audioPath = this.cacheDir + media.audio.cacheName
|
||||
if (FileUtil.accessSync(videoPath) && FileUtil.accessSync(audioPath)) {
|
||||
this.mergeVideoAndAudio(videoPath, audioPath, url)
|
||||
} else {
|
||||
throw Error('file not exists')
|
||||
}
|
||||
} else {
|
||||
headers['Range'] = `bytes=${media.audio.currentLen}-`;
|
||||
}
|
||||
} else {
|
||||
if (step === 0 || step === 1) {
|
||||
media.currentLen = 0
|
||||
} else if (step === 2 && media instanceof VideoMaterial && media.audio) {
|
||||
media.audio.currentLen = 0
|
||||
}
|
||||
}
|
||||
|
||||
if (this.canceled) return
|
||||
try {
|
||||
let filePath = ''
|
||||
if (step == 1 && media instanceof VideoMaterial) {
|
||||
filePath = this.cacheDir + media.cacheName
|
||||
} else if (step == 2 && media instanceof VideoMaterial) {
|
||||
filePath = this.cacheDir + media.audio!!.cacheName
|
||||
} else {
|
||||
filePath = this.cacheDir + this.fileName
|
||||
}
|
||||
let config: request.agent.Config = {
|
||||
action: request.agent.Action.DOWNLOAD,
|
||||
url: url,
|
||||
overwrite: true,
|
||||
saveas: filePath,
|
||||
headers: headers,
|
||||
gauge: true,
|
||||
priority:0
|
||||
}
|
||||
let total = 0;
|
||||
request.agent.create(AppUtil.getApplicationContext(), config)
|
||||
.then((task: request.agent.Task) => {
|
||||
this.task = task
|
||||
task.start((err: BusinessError) => {
|
||||
if (err) {
|
||||
console.error(err.message);
|
||||
this.doException(err.message);
|
||||
return;
|
||||
}
|
||||
});
|
||||
task.on('progress', (progress) => {
|
||||
if (total === 0) {
|
||||
total = progress.sizes[0] as number;
|
||||
if (step === 0 || step === 1) {
|
||||
total += media.currentLen
|
||||
media.totalSize = total
|
||||
} else if (step === 2 && media instanceof VideoMaterial && media.audio) {
|
||||
total += media.audio.currentLen
|
||||
media.audio.totalSize = total
|
||||
}
|
||||
this.doGetTotal(total);
|
||||
console.debug(`total: ${progress.sizes[0].toString()}`)
|
||||
}
|
||||
if (step === 0 || step === 1) {
|
||||
media.currentLen = progress.processed
|
||||
} else if (step === 2 && media instanceof VideoMaterial && media.audio) {
|
||||
media.audio.currentLen = progress.processed
|
||||
}
|
||||
this.doProgress(progress.processed);
|
||||
console.debug(`progress: ${progress.processed.toString()}`);
|
||||
})
|
||||
task.on('completed', () => {
|
||||
console.debug('download completed');
|
||||
if (step == 1 && media instanceof VideoMaterial && media.audio) {
|
||||
this.doMerge(4) // 音频提取中
|
||||
this.doMediaDown(media, 2)
|
||||
} else if (step == 2 && media instanceof VideoMaterial) {
|
||||
this.doMerge(5) // 音视频合并中
|
||||
let videoPath = this.cacheDir + media.cacheName
|
||||
let audioPath = this.cacheDir + media.audio!!.cacheName
|
||||
if (FileUtil.accessSync(videoPath) && FileUtil.accessSync(audioPath)) {
|
||||
this.mergeVideoAndAudio(videoPath, audioPath, url)
|
||||
} else {
|
||||
this.doException('文件不存在')
|
||||
}
|
||||
} else {
|
||||
this.doSuccess(this.cacheDir + this.fileName);
|
||||
}
|
||||
request.agent.remove(task.tid);
|
||||
})
|
||||
task.on('failed', (progress) => {
|
||||
console.log('download failed');
|
||||
request.agent.show(task.tid).then((taskInfo: request.agent.TaskInfo) => {
|
||||
request.agent.remove(task.tid);
|
||||
if (this.proxyList.length > 0 && this.replaceUrlWithProxy(media)) {
|
||||
this.doMediaDown(media, step)
|
||||
} else {
|
||||
this.doException(taskInfo.reason);
|
||||
}
|
||||
}).catch((err: BusinessError) => {
|
||||
this.doException(err.message);
|
||||
request.agent.remove(task.tid);
|
||||
});
|
||||
});
|
||||
})
|
||||
.catch((err: BusinessError) => {
|
||||
console.error(err.message);
|
||||
this.doException(err.message);
|
||||
})
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
this.doException(e);
|
||||
}
|
||||
}
|
||||
|
||||
async mergeVideoAndAudio(videoPath: string, audioPath: string, url: string) {
|
||||
let outputPath = this.cacheDir + this.fileName
|
||||
if (FileUtil.accessSync(outputPath)) {
|
||||
FileUtil.unlinkSync(outputPath)
|
||||
}
|
||||
let cmd = `ffmpeg -i ${videoPath} -i ${audioPath} -c copy ${outputPath}`
|
||||
MP4Parser.ffmpegCmd(cmd, {
|
||||
callBackResult: (code: number) => {
|
||||
if (code === 0) {
|
||||
this.doSuccess(outputPath)
|
||||
} else {
|
||||
this.doException('合并失败')
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
async fixM4s(filePath: string) {
|
||||
const file = FileUtil.openSync(filePath, 0o2);
|
||||
const stat = FileUtil.lstatSync(filePath);
|
||||
const buffer = new ArrayBuffer(stat.size);
|
||||
FileUtil.readSync(file.fd, buffer);
|
||||
FileUtil.fsyncSync(file.fd);
|
||||
FileUtil.closeSync(file.fd);
|
||||
|
||||
let bytes = new Uint8Array(buffer)
|
||||
if (bytes.length > 9) {
|
||||
bytes = bytes.subarray(9)
|
||||
FileUtil.writeEasy(filePath, bytes.buffer, false)
|
||||
}
|
||||
}
|
||||
|
||||
async decodeWxVideo(video: VideoMaterial) {
|
||||
if (!video.url.includes("wechatDecode=batiao")) {
|
||||
return
|
||||
}
|
||||
try {
|
||||
const parseUrl = url.URL.parseURL(video.url);
|
||||
const realUrl = parseUrl.params.get('url') as string;
|
||||
const decodeKey = parseUrl.params.get("decodeKey");
|
||||
const keyUrl = Constants.BASE_URL + "/api/weixin/video/key?decodeKey=" + decodeKey;
|
||||
const response: AxiosResponse = await axios({
|
||||
url: keyUrl,
|
||||
method: 'get',
|
||||
responseType: 'array_buffer',
|
||||
})
|
||||
if (response.status === 200) {
|
||||
video.url = realUrl;
|
||||
video.origin_url = realUrl;
|
||||
video.decodeKey = new Int8Array(response.data)
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
async isCanContinue(url: string, start: number): Promise<boolean> {
|
||||
try {
|
||||
const headers = new AxiosHeaders();
|
||||
headers.set('RANGE', `bytes=${start}-`);
|
||||
headers.set('Connection', 'close');
|
||||
const response: AxiosResponse = await axios({
|
||||
url: url,
|
||||
method: 'get',
|
||||
headers: headers,
|
||||
responseType: 'array_buffer'
|
||||
})
|
||||
if (response.status === 206) { //支持
|
||||
return Promise.resolve(true);
|
||||
} else {
|
||||
const acceptRangesHeaderValue = (response.headers as AxiosResponseHeaders).get('Accept-Ranges') as string
|
||||
if ("bytes" === acceptRangesHeaderValue?.toLowerCase()) { //支持
|
||||
return Promise.resolve(true);
|
||||
} else { //不支持
|
||||
return Promise.resolve(false);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
return Promise.resolve(false);
|
||||
}
|
||||
}
|
||||
|
||||
replaceUrlWithProxy(media: MediaEntity): boolean {
|
||||
try {
|
||||
let vUrl = url.URL.parseURL(media.url)
|
||||
|
||||
let domainAndPort = vUrl?.host ? vUrl?.host : ''
|
||||
for (let i = 0; i < this.proxyList.length; i++) {
|
||||
const proxy = this.proxyList[i];
|
||||
if (i < this.proxyList.length - 1) {
|
||||
if (proxy.includes(domainAndPort)) {
|
||||
domainAndPort = this.proxyList[i + 1]
|
||||
break
|
||||
}
|
||||
} else return false
|
||||
}
|
||||
|
||||
// 获取原始 URL 的路径和查询参数
|
||||
media.url = domainAndPort + vUrl?.pathname + vUrl?.search
|
||||
if (media instanceof VideoMaterial && media.audio) {
|
||||
let aUrl = url.URL.parseURL(media.audio.url)
|
||||
media.audio!!.url = domainAndPort + aUrl?.pathname + aUrl?.search
|
||||
}
|
||||
return true
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
getDomainFromUrl(urlString: string): string {
|
||||
try {
|
||||
let parseURL = url.URL.parseURL(urlString)
|
||||
return parseURL.protocol + "//" + parseURL.host
|
||||
} catch (e) {
|
||||
return ''
|
||||
}
|
||||
}
|
||||
|
||||
getUrlFileExt(srcUrl: string): string {
|
||||
try {
|
||||
let url = srcUrl.substring(0, srcUrl.indexOf('?'))
|
||||
if (url) {
|
||||
return url.substring(url.lastIndexOf('.') + 1)
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
return ''
|
||||
}
|
||||
|
||||
private canceled = false
|
||||
async cancel() {
|
||||
this.canceled = true
|
||||
if (this.task) {
|
||||
this.task.stop()
|
||||
.then(() => {
|
||||
this.task = null
|
||||
this.doCancel()
|
||||
})
|
||||
.catch((e: Error) => {
|
||||
this.doException(e.message)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
doGetTotal(total: number) {
|
||||
if (this.mCallback?.onGetTotal) {
|
||||
this.mCallback.onGetTotal(total);
|
||||
}
|
||||
}
|
||||
|
||||
doProgress(progress: number) {
|
||||
if (this.mCallback?.onProgress) {
|
||||
this.mCallback.onProgress(progress);
|
||||
}
|
||||
}
|
||||
|
||||
doPause() {
|
||||
if (this.mCallback?.onPause) {
|
||||
this.mCallback.onPause();
|
||||
}
|
||||
}
|
||||
|
||||
doMerge(step: number) {
|
||||
if (this.mCallback?.onMerge) {
|
||||
this.mCallback.onMerge(step);
|
||||
}
|
||||
}
|
||||
|
||||
doSuccess(filePath: string) {
|
||||
if (this.mCallback?.onSuccess) {
|
||||
this.mCallback.onSuccess(filePath)
|
||||
}
|
||||
}
|
||||
|
||||
doCancel() {
|
||||
if (this.mCallback?.onCancel) {
|
||||
this.mCallback.onCancel();
|
||||
}
|
||||
}
|
||||
|
||||
doException(err: string) {
|
||||
if (this.mCallback?.onFailed) {
|
||||
this.mCallback.onFailed(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
|
||||
export interface LoginRequest {
|
||||
login_type: string;
|
||||
bind?: boolean;
|
||||
unbind?: boolean;
|
||||
phone?: Record<string, Object>;
|
||||
weixin?: Record<string, Object>;
|
||||
device?: Record<string, Object>;
|
||||
}
|
||||
|
|
@ -0,0 +1,237 @@
|
|||
import { TipDialog } from '../../dialog/TipDialog'
|
||||
import { ShareManager } from '../../manager/ShareManager'
|
||||
import { TitleBar } from '../../view/TitleBar'
|
||||
import { ToastUtils } from '../../utils/ToastUtils'
|
||||
import { AppUtil } from '@pura/harmony-utils'
|
||||
import { EventConstants } from '../../common/EventConstants'
|
||||
import { MediaAction, MediaType } from '../../manager/MediaManager'
|
||||
import { media } from '@kit.MediaKit'
|
||||
import { fileIo } from '@kit.CoreFileKit'
|
||||
import { LocalMediaManager } from '../../manager/LocalMediaManager'
|
||||
import { avSessionManager } from '../../manager/AVSessionManager'
|
||||
|
||||
@Entry
|
||||
@ComponentV2
|
||||
struct AudioPlayerPage {
|
||||
@Local title: string = ''
|
||||
@Local uri: string = ''
|
||||
@Local showActions: boolean = false
|
||||
@Local currentTime: number = 0
|
||||
@Local durationTime: number = 0
|
||||
@Local isPlaying: boolean = false
|
||||
|
||||
avPlayer?: media.AVPlayer;
|
||||
|
||||
aboutToAppear(): void {
|
||||
this.initParams()
|
||||
this.initPlayer()
|
||||
}
|
||||
|
||||
onPageHide(): void {
|
||||
if (this.avPlayer) {
|
||||
this.avPlayer.pause()
|
||||
}
|
||||
}
|
||||
|
||||
aboutToDisappear(): void {
|
||||
if (this.avPlayer) {
|
||||
this.avPlayer.release()
|
||||
}
|
||||
}
|
||||
|
||||
initParams() {
|
||||
const params = this.getUIContext().getRouter().getParams() as Record<string, Object>;
|
||||
if (params) {
|
||||
this.title = params.title as string
|
||||
this.uri = params.uri as string;
|
||||
this.showActions = params.showActions as boolean
|
||||
}
|
||||
}
|
||||
|
||||
async initPlayer() {
|
||||
this.avPlayer = await media.createAVPlayer();
|
||||
// 创建状态机变化回调函数
|
||||
this.setAVPlayerCallback();
|
||||
// 打开相应的资源文件地址获取fd
|
||||
let file = await fileIo.open(this.uri);
|
||||
this.avPlayer.url = 'fd://' + file.fd;
|
||||
}
|
||||
|
||||
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}`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 注册avplayer回调函数
|
||||
setAVPlayerCallback() {
|
||||
this.avPlayer!!.on('error', (err) => {
|
||||
console.error(`播放器发生错误,错误码:${err.code}, 错误信息:${err.message}`);
|
||||
// 调用reset重置资源,触发idle状态
|
||||
this.isPlaying = false
|
||||
this.avPlayer!!.reset();
|
||||
avSessionManager.deactivate()
|
||||
})
|
||||
// 状态机变化回调函数
|
||||
this.avPlayer!!.on('stateChange', async (state, reason) => {
|
||||
switch (state) {
|
||||
case 'initialized':
|
||||
console.info('资源初始化完成');
|
||||
// 资源初始化完成,开始准备文件
|
||||
this.avPlayer!!.prepare();
|
||||
break;
|
||||
case 'prepared':
|
||||
console.info('资源准备完成');
|
||||
// 资源准备完成,开始准备文件
|
||||
this.durationTime = Math.trunc(this.avPlayer!!.duration / 1000)
|
||||
this.currentTime = this.avPlayer!!.currentTime;
|
||||
|
||||
await avSessionManager.activate()
|
||||
this.avPlayer!!.play();
|
||||
break;
|
||||
case 'completed':
|
||||
console.info('播放完成');
|
||||
this.isPlaying = false
|
||||
this.avPlayer!!.off('bufferingUpdate')
|
||||
AppStorage.setOrCreate('currentTime', this.durationTime);
|
||||
avSessionManager.deactivate()
|
||||
break;
|
||||
case 'playing':
|
||||
console.info('播放开始');
|
||||
this.isPlaying = true
|
||||
break;
|
||||
case 'released':
|
||||
case 'stopped':
|
||||
case 'error':
|
||||
case 'paused':
|
||||
console.info('播放暂停');
|
||||
this.isPlaying = false
|
||||
avSessionManager.deactivate()
|
||||
break;
|
||||
}
|
||||
})
|
||||
// 时间上报监听函数
|
||||
this.avPlayer!!.on('timeUpdate', (time: number) => {
|
||||
this.currentTime = Math.trunc(time / 1000);
|
||||
});
|
||||
}
|
||||
|
||||
build() {
|
||||
Column() {
|
||||
TitleBar().width('100%')
|
||||
|
||||
RelativeContainer() {
|
||||
Image($r('app.media.ic_audio_thumb'))
|
||||
|
||||
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.avPlayer!!.pause()
|
||||
} else {
|
||||
await avSessionManager.activate()
|
||||
this.avPlayer!!.play()
|
||||
}
|
||||
})
|
||||
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.avPlayer!!.seek(value * 1000, 2); // 设置视频播放的进度跳转到value处
|
||||
this.currentTime = value;
|
||||
})
|
||||
.layoutWeight(1)
|
||||
Text(this.formatTime(this.durationTime)).width(35).fontColor(Color.White).fontSize(12)
|
||||
}
|
||||
.opacity(0.8)
|
||||
.width("100%")
|
||||
.padding({ left: 30, right: 30 })
|
||||
.margin({ bottom: this.showActions ? 0 : 50})
|
||||
.alignRules({
|
||||
bottom: { anchor: '__container__', align: VerticalAlign.Bottom }
|
||||
})
|
||||
}.layoutWeight(1)
|
||||
|
||||
Row() {
|
||||
Column() {
|
||||
Image($r('app.media.ic_action_share')).width(50).height(50)
|
||||
Text('转发').fontSize(12).fontColor($r('app.color.color_50ffffff')).margin({ top: 13 })
|
||||
}
|
||||
.id('btn_share')
|
||||
.alignRules({
|
||||
right: { anchor: '__container__', align: HorizontalAlign.Center }
|
||||
})
|
||||
.margin({ right: 40 })
|
||||
.onClick(() => {
|
||||
ShareManager.shareFile(this.uri)
|
||||
})
|
||||
|
||||
Column() {
|
||||
Image($r('app.media.ic_action_delete')).width(50).height(50)
|
||||
Text('删除').fontSize(12).fontColor($r('app.color.color_50ffffff')).margin({ top: 13 })
|
||||
}
|
||||
.id('btn_delete')
|
||||
.alignRules({
|
||||
left: { anchor: '__container__', align: HorizontalAlign.Center },
|
||||
})
|
||||
.margin({ left: 40 })
|
||||
.onClick(() => {
|
||||
this.avPlayer!!.pause()
|
||||
TipDialog.show(this.getUIContext(), {
|
||||
title: '提示', content: '确定删除该音频?', callback: {
|
||||
confirm: () => {
|
||||
fileIo.unlink(this.uri)
|
||||
.then(() => {
|
||||
ToastUtils.show('删除成功')
|
||||
LocalMediaManager.delete(this.title)
|
||||
AppUtil.getContext().eventHub.emit(EventConstants.MediaActionEvent, MediaType.AUDIO, MediaAction.DELETE)
|
||||
this.getUIContext().getRouter().back()
|
||||
})
|
||||
.catch(() => {
|
||||
ToastUtils.show('删除失败, 请到文件管理中手动删除')
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
.height(200)
|
||||
.margin({ top: 10 })
|
||||
.visibility(this.showActions ? Visibility.Visible : Visibility.None)
|
||||
}
|
||||
.width('100%')
|
||||
.height('100%')
|
||||
.backgroundColor($r('app.color.window_background'))
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
import { RouterUrls } from '../../common/RouterUrls';
|
||||
import { ToastUtils } from '../../utils/ToastUtils';
|
||||
import systemDateTime from '@ohos.systemDateTime';
|
||||
import { router } from '@kit.ArkUI';
|
||||
import { AppUtil } from '@pura/harmony-utils';
|
||||
import { ConfigManager } from '../../manager/UserConfigManager';
|
||||
import { EventReportGlobalManager } from '../../manager/EventReportGlobalManager';
|
||||
import { EventConstants } from '../../common/EventConstants';
|
||||
|
||||
@Entry
|
||||
@ComponentV2
|
||||
struct GuidePage {
|
||||
child = [
|
||||
$r('app.media.ic_guide_1'),
|
||||
$r('app.media.ic_guide_2'),
|
||||
$r('app.media.ic_guide_3'),
|
||||
$r('app.media.ic_guide_4')
|
||||
]
|
||||
currentIndex: number = 0;
|
||||
|
||||
clickTime: number = 0;
|
||||
|
||||
@Local showHomePage: boolean = true
|
||||
|
||||
aboutToAppear(): void {
|
||||
EventReportGlobalManager.eventReport(EventConstants.GUIDE_LAUNCH)
|
||||
}
|
||||
|
||||
build() {
|
||||
Stack() {
|
||||
Image($r('app.media.ic_guide_bg')).width('100%').height('100%')
|
||||
if (this.showHomePage) {
|
||||
Column() {
|
||||
Image($r('app.media.ic_guide_cover')).width('100%').aspectRatio(0.75)
|
||||
Text('视频搬运工具').fontColor('#0B2449').fontSize(32).fontFamily('almmsht')
|
||||
.margin({top: 27})
|
||||
Text(ConfigManager.getGuideHint()).fontColor('#1E385D').fontSize(16).margin({top: 12, left: 54, right: 54})
|
||||
Blank().layoutWeight(1)
|
||||
Button('立即使用')
|
||||
.width(180)
|
||||
.height(40)
|
||||
.fontColor(Color.White)
|
||||
.fontSize(16)
|
||||
.borderRadius(20)
|
||||
.backgroundColor($r("app.color.color_466afd"))
|
||||
.margin({bottom: 30})
|
||||
.onClick(() => {
|
||||
this.showHomePage = false
|
||||
})
|
||||
}
|
||||
.width('100%')
|
||||
.height('100%')
|
||||
} else {
|
||||
Swiper() {
|
||||
ForEach(this.child, (item: Resource) => {
|
||||
Image(item).width('100%').height('100%')
|
||||
})
|
||||
}
|
||||
.indicator(false)
|
||||
.onChange((index: number) => {
|
||||
this.currentIndex = index;
|
||||
EventReportGlobalManager.eventReport(EventConstants.GUIDE_OPPORTUNITY_SCROLL, `${index + 1}`)
|
||||
})
|
||||
.onGestureSwipe((index: number, extraInfo: SwiperAnimationEvent) => {
|
||||
if (index === this.child.length - 1 && extraInfo.currentOffset < -60) {
|
||||
// 跳转VIP充值页面
|
||||
if (ConfigManager.isGuidePayEnable()) {
|
||||
this.getUIContext().getRouter().replaceUrl({ url: RouterUrls.VIP_PAGE, params: { origin: 'bootpage'} });
|
||||
} else {
|
||||
this.getUIContext().getRouter().replaceUrl({ url: RouterUrls.MAIN_PAGE }, router.RouterMode.Single);
|
||||
}
|
||||
}
|
||||
})
|
||||
.loop(false)
|
||||
.width('100%')
|
||||
.height('100%')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onBackPress(): boolean | void {
|
||||
if (systemDateTime.getTime() - this.clickTime < 1500) {
|
||||
AppUtil.getContext().terminateSelf();
|
||||
} else {
|
||||
this.clickTime = systemDateTime.getTime();
|
||||
ToastUtils.show('双击退出应用');
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,355 @@
|
|||
import { TitleBar } from '../../view/TitleBar';
|
||||
import systemDateTime from '@ohos.systemDateTime';
|
||||
import { ToastUtils } from '../../utils/ToastUtils';
|
||||
import { common } from '@kit.AbilityKit';
|
||||
import { RouterUrls } from '../../common/RouterUrls';
|
||||
import { Constants } from '../../common/Constants';
|
||||
import LoginViewModel from '../../viewModel/LoginViewModel';
|
||||
import { AppUtil, RandomUtil, StrUtil } from '@pura/harmony-utils';
|
||||
import { SendCodeEntity } from '../../entity/SendCodeEntity';
|
||||
import { LoginEntity } from '../../entity/LoginEntity';
|
||||
import { ConfigManager } from '../../manager/UserConfigManager';
|
||||
import { LoginTipDialog } from '../../dialog/LoginTipDialog';
|
||||
import { LevelMode, router } from '@kit.ArkUI';
|
||||
import { LoginManager } from '../../manager/LoginGlobalManager';
|
||||
import { OnWXResp, WXApi, WXEventHandler } from '../../utils/wechat/WXApiEventHandlerImpl';
|
||||
import * as WxOpenSdk from '@tencent/wechat_open_sdk';
|
||||
import { ErrCode, SendAuthResp } from '@tencent/wechat_open_sdk';
|
||||
import BuildProfile from 'BuildProfile';
|
||||
import { LoadingDialog } from '../../dialog/LoadingDialog';
|
||||
import { EventConstants } from '../../common/EventConstants';
|
||||
import { EventReportGlobalManager } from '../../manager/EventReportGlobalManager';
|
||||
|
||||
@Entry
|
||||
@ComponentV2
|
||||
struct LoginPage {
|
||||
@Local from: number = 0;
|
||||
@Local isAgree: boolean = false;
|
||||
@Local countDownTime: number = 0;
|
||||
|
||||
loginTipDialogController?: CustomDialogController | null;
|
||||
|
||||
viewModel: LoginViewModel = new LoginViewModel(this.getUIContext());
|
||||
|
||||
clickTime: number = 0;
|
||||
phone: string = '';
|
||||
code: string = '';
|
||||
timestamp: string = '';
|
||||
intervalId: number = -1;
|
||||
//从微信返回的回调
|
||||
onWXResp: OnWXResp = (resp) => {
|
||||
//微信返回的数据
|
||||
if (resp instanceof SendAuthResp && resp.state?.endsWith('phone')) {
|
||||
const authResult = JSON.stringify(resp ?? {}, null , 2);
|
||||
const errCode = JSON.parse(authResult).errCode as number;
|
||||
if (errCode === ErrCode.ERR_OK) {
|
||||
const authCode = JSON.parse(authResult).code as string;
|
||||
this.viewModel.wxLogin(authCode);
|
||||
} else {
|
||||
ToastUtils.show(JSON.parse(authResult).errStr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Monitor('viewModel.codeEntity')
|
||||
onCodeChange(monitor: IMonitor) {
|
||||
const code = monitor.value()?.now as SendCodeEntity;
|
||||
ToastUtils.show('验证码已发送');
|
||||
this.timestamp = code.timestamp;
|
||||
this.countDownTime = 60;
|
||||
this.intervalId = setInterval(() => {
|
||||
if (this.countDownTime > 0) {
|
||||
this.countDownTime--
|
||||
} else {
|
||||
if (this.intervalId !== 0) {
|
||||
clearInterval(this.intervalId);
|
||||
}
|
||||
}
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
@Monitor('viewModel.phoneLoginEntity')
|
||||
onPhoneLogin(monitor: IMonitor) {
|
||||
const loginEntity = monitor.value()?.now as LoginEntity;
|
||||
EventReportGlobalManager.eventReport(EventConstants.LOGIN, 'phone', this.phone)
|
||||
LoginManager.saveToken(loginEntity.token);
|
||||
LoginManager.saveLastLoginType('phone')
|
||||
ConfigManager.userConfig()
|
||||
.then(() => {
|
||||
if (this.from === 0) {
|
||||
this.toMainPage();
|
||||
} else {
|
||||
this.getUIContext().getRouter().back()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@Monitor('viewModel.wxLoginEntity')
|
||||
onWxLogin(monitor: IMonitor) {
|
||||
const loginEntity = monitor.value()?.now as LoginEntity;
|
||||
EventReportGlobalManager.eventReport(EventConstants.LOGIN, 'weixin')
|
||||
LoginManager.saveToken(loginEntity.token);
|
||||
LoginManager.saveLastLoginType('weixin')
|
||||
ConfigManager.userConfig()
|
||||
.then(() => {
|
||||
if (this.from === 0) {
|
||||
this.toMainPage();
|
||||
} else {
|
||||
this.getUIContext().getRouter().back()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
aboutToAppear() {
|
||||
WXEventHandler.registerOnWXRespCallback(this.onWXResp)
|
||||
this.initParams();
|
||||
}
|
||||
|
||||
aboutToDisappear() {
|
||||
WXEventHandler.unregisterOnWXRespCallback(this.onWXResp)
|
||||
this.loginTipDialogController = null
|
||||
}
|
||||
|
||||
initParams() {
|
||||
const params = this.getUIContext().getRouter().getParams() as Record<string, Object>;
|
||||
if (params) {
|
||||
this.from = params.from as number;
|
||||
}
|
||||
}
|
||||
|
||||
sendCode() {
|
||||
if (StrUtil.isEmpty(this.phone)) {
|
||||
ToastUtils.show('请输入手机号');
|
||||
return;
|
||||
}
|
||||
if (this.phone.length != 11) {
|
||||
ToastUtils.show('请输入正确的手机号');
|
||||
return;
|
||||
}
|
||||
this.viewModel.sendCode(this.phone);
|
||||
EventReportGlobalManager.eventReport(EventConstants.GET_CODE, "code_login", this.phone)
|
||||
}
|
||||
|
||||
toMainPage() {
|
||||
this.getUIContext().getRouter().replaceUrl({ url: RouterUrls.MAIN_PAGE }, router.RouterMode.Single);
|
||||
AppUtil.getContext().eventHub.emit(EventConstants.LoginSuccessEvent);
|
||||
}
|
||||
|
||||
async wxAuth() {
|
||||
if (!WXApi.isWXAppInstalled()) {
|
||||
ToastUtils.show('未安装微信客户端,请先下载安装微信客户端');
|
||||
return;
|
||||
}
|
||||
LoadingDialog.show(this.getUIContext());
|
||||
let req = new WxOpenSdk.SendAuthReq;
|
||||
req.isOption1 = false;
|
||||
req.nonAutomatic = true;
|
||||
req.scope = 'snsapi_userinfo';
|
||||
req.state = BuildProfile.BUNDLE_NAME + RandomUtil.getRandomInt(0, 1000) + '_phone';
|
||||
req.transaction ='';
|
||||
|
||||
await WXApi.sendReq(AppUtil.getContext(), req)
|
||||
LoadingDialog.dismiss();
|
||||
}
|
||||
|
||||
showLoginTipDialog(type: number) {
|
||||
this.loginTipDialogController = new CustomDialogController({
|
||||
builder: LoginTipDialog({
|
||||
confirm: () => {
|
||||
this.isAgree = true;
|
||||
if (type === 0) {
|
||||
this.viewModel.phoneLogin(this.phone, this.code, this.timestamp);
|
||||
} else if (type === 1) {
|
||||
this.wxAuth();
|
||||
}
|
||||
}
|
||||
}),
|
||||
cornerRadius: 20,
|
||||
maskColor: '#CC000000',
|
||||
levelMode: LevelMode.EMBEDDED,
|
||||
backgroundBlurStyle: BlurStyle.NONE
|
||||
})
|
||||
this.loginTipDialogController.open();
|
||||
}
|
||||
|
||||
onBackPress(): boolean | void {
|
||||
if (this.from === 0) {
|
||||
if (systemDateTime.getTime() - this.clickTime < 1500) {
|
||||
(this.getUIContext().getHostContext() as common.UIAbilityContext).terminateSelf();
|
||||
} else {
|
||||
EventReportGlobalManager.eventReport(EventConstants.EXIT_APP, 'login')
|
||||
this.clickTime = systemDateTime.getTime();
|
||||
ToastUtils.show('双击退出应用');
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
build() {
|
||||
Stack({alignContent: Alignment.TopStart}) {
|
||||
Image($r('app.media.ic_login_top_bg')).width('100%')
|
||||
|
||||
Column() {
|
||||
TitleBar({ showBack: this.from !== 0 }).width('100%')
|
||||
Image($r('app.media.ic_login_logo'))
|
||||
.margin({ top: 10 })
|
||||
.width(80)
|
||||
.height(80)
|
||||
|
||||
Text($r('app.string.app_name'))
|
||||
.fontColor($r('app.color.color_212226'))
|
||||
.fontSize(18)
|
||||
.fontFamily('almmsht')
|
||||
.margin({ top: 12 })
|
||||
.width('auto')
|
||||
|
||||
Row(){
|
||||
Image($r('app.media.ic_login_phone')).width(22).height(22)
|
||||
TextInput({ placeholder: '请输入您的手机号' })
|
||||
.type(InputType.PhoneNumber)
|
||||
.fontColor($r('app.color.color_1a1a1a'))
|
||||
.fontSize(16)
|
||||
.placeholderColor($r('app.color.color_bcbcbc'))
|
||||
.placeholderFont({ size: 16 })
|
||||
.maxLength(11)
|
||||
.backgroundColor(Color.Transparent)
|
||||
.onChange((value: string) => {
|
||||
this.phone = value;
|
||||
})
|
||||
}
|
||||
.height(50)
|
||||
.margin({ top: 50, left: 38, right: 38 })
|
||||
|
||||
Divider().strokeWidth(1).color($r('app.color.color_dfdfdf')).margin({ left: 38, right: 38 })
|
||||
|
||||
RelativeContainer() {
|
||||
Row() {
|
||||
Image($r('app.media.ic_login_code')).width(22).height(22)
|
||||
TextInput({ placeholder: '请输入验证码' })
|
||||
.type(InputType.Number)
|
||||
.fontColor($r('app.color.color_1a1a1a'))
|
||||
.fontSize(16)
|
||||
.placeholderColor($r('app.color.color_bcbcbc'))
|
||||
.placeholderFont({ size: 16 })
|
||||
.maxLength(6)
|
||||
.backgroundColor(Color.Transparent)
|
||||
.onChange((value: string) => {
|
||||
this.code = value;
|
||||
})
|
||||
}
|
||||
.id('row_code')
|
||||
|
||||
Text(this.countDownTime === 0 && StrUtil.isEmpty(this.timestamp) ? '获取验证码' :
|
||||
this.countDownTime > 0 ? `${this.countDownTime}s` : '重新发送')
|
||||
.fontColor(this.countDownTime === 0 ? $r("app.color.color_466afd") : $r('app.color.color_999999'))
|
||||
.fontSize(14)
|
||||
.alignRules({
|
||||
top: { anchor: 'row_code', align: VerticalAlign.Top },
|
||||
right: { anchor: 'row_code', align: HorizontalAlign.End },
|
||||
bottom: { anchor: 'row_code', align: VerticalAlign.Bottom },
|
||||
})
|
||||
.margin({ right: 16 })
|
||||
.width('auto')
|
||||
.onClick(() => {
|
||||
if (this.countDownTime === 0) {
|
||||
this.sendCode();
|
||||
}
|
||||
})
|
||||
}.margin({ top: 26, left: 38, right: 38 }).height(50)
|
||||
|
||||
Divider().strokeWidth(1).color($r('app.color.color_dfdfdf')).margin({ left: 38, right: 38 })
|
||||
|
||||
Stack() {
|
||||
Button('登录', { type: ButtonType.Capsule, stateEffect: true })
|
||||
.width('100%')
|
||||
.height(50)
|
||||
.fontColor(Color.White)
|
||||
.fontSize(16)
|
||||
.fontWeight(FontWeight.Medium)
|
||||
.backgroundColor($r("app.color.color_466afd"))
|
||||
}.margin({ top: 40 }).padding({ left: 38, right: 38 })
|
||||
.onClick(() => {
|
||||
if (StrUtil.isEmpty(this.phone)) {
|
||||
ToastUtils.show('请输入手机号');
|
||||
return;
|
||||
}
|
||||
if (this.phone.length != 11) {
|
||||
ToastUtils.show('请输入正确的手机号');
|
||||
return;
|
||||
}
|
||||
if (StrUtil.isEmpty(this.code)) {
|
||||
ToastUtils.show('请输入验证码');
|
||||
return;
|
||||
}
|
||||
if (this.isAgree) {
|
||||
this.viewModel.phoneLogin(this.phone, this.code, this.timestamp);
|
||||
} else {
|
||||
this.showLoginTipDialog(0);
|
||||
}
|
||||
})
|
||||
|
||||
Row() {
|
||||
Image(this.isAgree ? $r('app.media.ic_check_true') : $r('app.media.ic_check_false')).width(16).height(16)
|
||||
Text() {
|
||||
Span('我已阅读并同意')
|
||||
Span('《用户协议》').fontColor($r("app.color.color_466afd"))
|
||||
.onClick(() => {
|
||||
this.getUIContext()
|
||||
.getRouter()
|
||||
.pushUrl({ url: RouterUrls.WEB_PAGE, params: { title: '用户协议', url: Constants.USER_AGREEMENT } })
|
||||
})
|
||||
Span('和')
|
||||
Span('《隐私政策》').fontColor($r("app.color.color_466afd"))
|
||||
.onClick(() => {
|
||||
this.getUIContext()
|
||||
.getRouter()
|
||||
.pushUrl({ url: RouterUrls.WEB_PAGE, params: { title: '隐私政策', url: Constants.PRIVACY_POLICY } })
|
||||
})
|
||||
}
|
||||
.fontColor($r('app.color.color_999999'))
|
||||
.fontSize(12)
|
||||
.margin({ left: 4, top: 2 })
|
||||
}
|
||||
.alignItems(VerticalAlign.Top)
|
||||
.margin({ left: 38, top: 16, right: 38 })
|
||||
.onClick(() => {
|
||||
this.isAgree = !this.isAgree;
|
||||
})
|
||||
|
||||
Blank().layoutWeight(1)
|
||||
|
||||
Text('其他登录方式')
|
||||
.fontColor('#AAAAAA')
|
||||
.fontSize(10)
|
||||
.width('auto')
|
||||
.visibility(ConfigManager.getLoginType().length > 1 ? Visibility.Visible : Visibility.None)
|
||||
Row() {
|
||||
Image($r('app.media.ic_wx_login'))
|
||||
.margin({ left: 25, right: 25 })
|
||||
.width(38)
|
||||
.height(38)
|
||||
.id('iv_wx_login')
|
||||
.onClick(() => {
|
||||
if (this.isAgree) {
|
||||
this.wxAuth()
|
||||
} else {
|
||||
this.showLoginTipDialog(1);
|
||||
}
|
||||
})
|
||||
.visibility(ConfigManager.getLoginType().includes('weixin') ? Visibility.Visible : Visibility.None)
|
||||
|
||||
Image($r('app.media.ic_onekey_login'))
|
||||
.margin({ left: 25, right: 25 })
|
||||
.width(38)
|
||||
.height(38)
|
||||
.id('iv_onekey_login')
|
||||
.visibility(Visibility.None)
|
||||
}
|
||||
.margin({ top: 20, bottom: 50 })
|
||||
}
|
||||
.width('100%')
|
||||
.height('100%')
|
||||
}
|
||||
.backgroundColor(Color.White)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
import { TitleBar } from '../../../view/TitleBar'
|
||||
import { QrcodeLoginViewModel } from '../../../viewModel/QrcodeLoginViewModel'
|
||||
|
||||
@Entry
|
||||
@ComponentV2
|
||||
struct QrcodeLoginPage {
|
||||
viewModel: QrcodeLoginViewModel = new QrcodeLoginViewModel(this.getUIContext())
|
||||
|
||||
code: string = ''
|
||||
|
||||
@Monitor('viewModel.loginResult')
|
||||
onLogin() {
|
||||
this.getUIContext().getRouter().back()
|
||||
}
|
||||
|
||||
aboutToAppear(): void {
|
||||
this.initParams()
|
||||
}
|
||||
|
||||
initParams() {
|
||||
const params = this.getUIContext().getRouter().getParams() as Record<string, Object>;
|
||||
if (params) {
|
||||
this.code = params.code as string
|
||||
}
|
||||
}
|
||||
|
||||
onBackPress(): boolean | void {
|
||||
return true
|
||||
}
|
||||
|
||||
build() {
|
||||
Column() {
|
||||
TitleBar({ title: '登录确认', isDark: false})
|
||||
|
||||
Column() {
|
||||
Image($r('app.media.ic_qrcode_login_computer_black'))
|
||||
.width(110)
|
||||
.height(110)
|
||||
.margin({ top: 100 })
|
||||
|
||||
Text() {
|
||||
Span('登录 ')
|
||||
Span($r('app.string.app_name')).fontColor($r("app.color.color_466afd"))
|
||||
Span(' 网页端')
|
||||
}
|
||||
.fontSize(20)
|
||||
.fontColor($r('app.color.color_1a1a1a'))
|
||||
.fontWeight(FontWeight.Bold)
|
||||
.margin({ top: 20 })
|
||||
|
||||
Button('登录')
|
||||
.width(184)
|
||||
.height(48)
|
||||
.linearGradient({
|
||||
colors: [['#F62C6C', 0.0], ['#FC4F54', 1.0]],
|
||||
direction: GradientDirection.Right
|
||||
})
|
||||
.borderRadius(6)
|
||||
.margin({ top: 90 })
|
||||
.onClick(() => {
|
||||
this.viewModel.login(this.code)
|
||||
})
|
||||
|
||||
Text('取消登录').fontColor('#95979E')
|
||||
.fontSize(14)
|
||||
.margin({ top: 20 })
|
||||
.onClick(() => {
|
||||
this.getUIContext().getRouter().back()
|
||||
})
|
||||
}
|
||||
.width('90%')
|
||||
.layoutWeight(1)
|
||||
.margin(16)
|
||||
.borderRadius(16)
|
||||
.backgroundColor(Color.White)
|
||||
}
|
||||
.width('100%')
|
||||
.height('100%')
|
||||
.backgroundColor($r('app.color.color_ededed'))
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,177 @@
|
|||
import { router, window } from '@kit.ArkUI';
|
||||
import { HomePage } from './home/HomePage';
|
||||
import { MinePage } from './mine/MinePage';
|
||||
import { RecordPage } from './record/RecordPage';
|
||||
import systemDateTime from '@ohos.systemDateTime';
|
||||
import { ToastUtils } from '../../utils/ToastUtils';
|
||||
import { AppUtil, PasteboardUtil, StrUtil } from '@pura/harmony-utils';
|
||||
import { EventConstants } from '../../common/EventConstants';
|
||||
import { MainViewModel } from '../../viewModel/MainViewModel';
|
||||
import { UserEntity } from '../../entity/UserEntity';
|
||||
import { SimpleTipDialog } from '../../dialog/SimpleTipDialog';
|
||||
import { RouterUrls } from '../../common/RouterUrls';
|
||||
import { TipDialog } from '../../dialog/TipDialog';
|
||||
import { ConfigManager } from '../../manager/UserConfigManager';
|
||||
import { EventReportGlobalManager } from '../../manager/EventReportGlobalManager';
|
||||
import { PasteboardUtils } from '../../utils/PasteboardUtils';
|
||||
|
||||
@Entry
|
||||
@ComponentV2
|
||||
struct MainPage {
|
||||
windowStage: window.WindowStage = AppStorage.get("windowStage") as window.WindowStage;
|
||||
|
||||
viewModel: MainViewModel = new MainViewModel(this.getUIContext());
|
||||
|
||||
tabController: TabsController = new TabsController()
|
||||
|
||||
userinfo?: UserEntity;
|
||||
|
||||
titles = ['首页', '素材库', '工具', '我的'];
|
||||
|
||||
clickTime: number = 0;
|
||||
|
||||
@Local currentIndex: number = 0;
|
||||
@Provider() recordIndex: number = 0
|
||||
|
||||
@Monitor('viewModel.userEntity')
|
||||
onUserinfoChange(monitor: IMonitor) {
|
||||
this.userinfo = monitor.value()?.now as UserEntity;
|
||||
this.showLoginTip();
|
||||
}
|
||||
|
||||
aboutToAppear(): void {
|
||||
this.windowStage.getMainWindowSync().setWindowSystemBarProperties({
|
||||
statusBarColor: '#00000000',
|
||||
statusBarContentColor: '#000000'
|
||||
});
|
||||
this.initObserver();
|
||||
ConfigManager.userConfig()
|
||||
}
|
||||
|
||||
aboutToDisappear(): void {
|
||||
AppUtil.getContext().eventHub.off(EventConstants.LoginSuccessEvent);
|
||||
AppUtil.getContext().eventHub.off(EventConstants.JumpToRecordEvent);
|
||||
}
|
||||
|
||||
onPageShow(): void {
|
||||
this.viewModel.userinfo();
|
||||
if (this.currentIndex === 1) {
|
||||
AppUtil.getContext().eventHub.emit(EventConstants.RecordRefreshEvent);
|
||||
} else if (this.currentIndex === 2) {
|
||||
AppUtil.getContext().eventHub.emit(EventConstants.MineRefreshEvent);
|
||||
}
|
||||
this.checkPasteboard()
|
||||
}
|
||||
|
||||
initObserver() {
|
||||
AppUtil.getContext().eventHub.on(EventConstants.LoginSuccessEvent, () => {
|
||||
AppUtil.getContext().eventHub.emit(EventConstants.HomeRefreshEvent);
|
||||
AppUtil.getContext().eventHub.emit(EventConstants.MineRefreshEvent);
|
||||
})
|
||||
AppUtil.getContext().eventHub.on(EventConstants.JumpToRecordEvent, (index: number) => {
|
||||
this.tabController.changeIndex(1)
|
||||
this.currentIndex = 1
|
||||
})
|
||||
}
|
||||
|
||||
checkPasteboard() {
|
||||
PasteboardUtils.isNeedGetPermissionFromUser()
|
||||
.then((isNeed) => {
|
||||
if (isNeed) {
|
||||
PasteboardUtil.requestPermissions()
|
||||
.then((isGranted) => {
|
||||
if (isGranted) {
|
||||
let content = PasteboardUtil.getDataTextSync()
|
||||
if (StrUtil.isNotEmpty(content) && content !== PasteboardUtils.clipText && PasteboardUtils.isValidUrl(content)) {
|
||||
TipDialog.show(this.getUIContext(), {title: '您已复制链接,是否粘贴', content: content, leftText: '取消', rightText: '粘贴', callback: {
|
||||
confirm: () => {
|
||||
PasteboardUtils.clipText = content
|
||||
this.getUIContext().getRouter().pushUrl({url: RouterUrls.TAKE_MATERIAL_PAGE, params:{url: content}})
|
||||
},
|
||||
cancel: () => {
|
||||
PasteboardUtils.clipText = content
|
||||
}
|
||||
}})
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch(() => {})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
build() {
|
||||
Tabs({ controller: this.tabController, barPosition: BarPosition.End }) {
|
||||
TabContent() {
|
||||
HomePage()
|
||||
}
|
||||
.tabBar(this.tabBuilder(this.titles[0], 0, $r('app.media.ic_home_select'), $r('app.media.ic_home_default')))
|
||||
|
||||
TabContent() {
|
||||
|
||||
}
|
||||
.tabBar(this.tabBuilder(this.titles[1], 1, $r('app.media.ic_material_select'), $r('app.media.ic_material_default')))
|
||||
|
||||
TabContent() {
|
||||
|
||||
}
|
||||
.tabBar(this.tabBuilder(this.titles[2], 2, $r('app.media.ic_tool_select'), $r('app.media.ic_tool_default')))
|
||||
|
||||
TabContent() {
|
||||
MinePage()
|
||||
}
|
||||
.tabBar(this.tabBuilder(this.titles[3], 3, $r('app.media.ic_mine_select'), $r('app.media.ic_mine_default')))
|
||||
}
|
||||
.scrollable(false)
|
||||
.onSelected((index: number) => {
|
||||
this.currentIndex = index;
|
||||
if (index === 3) {
|
||||
AppUtil.getContext().eventHub.emit(EventConstants.MineRefreshEvent);
|
||||
}
|
||||
this.showLoginTip();
|
||||
EventReportGlobalManager.eventReport(EventConstants.HOME_BOTTOM_TAB_CHECK, this.titles[index], '')
|
||||
})
|
||||
.padding({ bottom: 20 })
|
||||
.backgroundColor(Color.White)
|
||||
}
|
||||
|
||||
@Builder
|
||||
tabBuilder(title: string, targetIndex: number, selectedImg: Resource, normalImg: Resource) {
|
||||
Column() {
|
||||
Image(this.currentIndex === targetIndex ? selectedImg : normalImg)
|
||||
.size({ width: 24, height: 24 })
|
||||
Text(title)
|
||||
.fontColor(this.currentIndex === targetIndex ? $r("app.color.color_466afd") : '#676E87')
|
||||
.fontSize(10)
|
||||
}
|
||||
.width('100%')
|
||||
.height(50)
|
||||
.justifyContent(FlexAlign.Center)
|
||||
}
|
||||
|
||||
showLoginTip() {
|
||||
if (this.userinfo && this.userinfo.temp && (this.userinfo.vip === 2 || this.userinfo.vip == 3)) {
|
||||
SimpleTipDialog.show(this.getUIContext(), {
|
||||
title: '郑重提示',
|
||||
content: '系统检测到您目前尚未登录,但您已成为我们尊贵的会员,为了防止您的会员账号丢失,建议您立即前往登录',
|
||||
buttonText: '立即登录',
|
||||
callback: {
|
||||
confirm: () => {
|
||||
this.getUIContext().getRouter().replaceUrl({ url: RouterUrls.LOGIN_PAGE }, router.RouterMode.Single)
|
||||
}
|
||||
}
|
||||
}, false)
|
||||
}
|
||||
}
|
||||
|
||||
onBackPress(): boolean | void {
|
||||
if (systemDateTime.getTime() - this.clickTime < 1500) {
|
||||
AppUtil.getContext().terminateSelf();
|
||||
} else {
|
||||
EventReportGlobalManager.eventReport(EventConstants.EXIT_APP, 'main')
|
||||
this.clickTime = systemDateTime.getTime();
|
||||
ToastUtils.show('双击退出应用');
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,457 @@
|
|||
import { borderRadiuses } from '@kit.ArkUI';
|
||||
import { HomeMenuEntity, homeMenuList } from '../../../entity/HomeMenuEntity';
|
||||
import { NoticeEntity } from '../../../entity/NoticeEntity';
|
||||
import { HomeViewModel } from '../../../viewModel/HomeViewModel';
|
||||
import { AppUtil, WantUtil } from '@pura/harmony-utils';
|
||||
import { EventConstants } from '../../../common/EventConstants';
|
||||
import { BannerEntity } from '../../../entity/BannerEntity';
|
||||
import { ConfigManager } from '../../../manager/UserConfigManager';
|
||||
import { LoginManager } from '../../../manager/LoginGlobalManager';
|
||||
import { RouterUrls } from '../../../common/RouterUrls';
|
||||
import { TipDialog } from '../../../dialog/TipDialog';
|
||||
import { EventReportGlobalManager } from '../../../manager/EventReportGlobalManager';
|
||||
import { Constants } from '../../../common/Constants';
|
||||
import { MaterialEntity } from '../../../entity/MaterialEntity';
|
||||
import { DownSamplingStrategy, ImageKnifeComponent, ImageKnifeOption } from '@ohos/imageknifepro';
|
||||
|
||||
@ComponentV2
|
||||
export struct HomePage {
|
||||
@Local notices?: Array<string> = [];
|
||||
@Local banners: Array<BannerEntity> = [];
|
||||
@Local materialList: Array<MaterialEntity> = []
|
||||
@Local isRefreshing: boolean = false
|
||||
@Local isLoading: boolean = false
|
||||
@Local canLoadMore: boolean = false
|
||||
|
||||
viewModel: HomeViewModel = new HomeViewModel(this.getUIContext());
|
||||
|
||||
noticeScroller: Scroller = new Scroller();
|
||||
|
||||
noticeTaskId: number = 0;
|
||||
bannerTaskId: number = 0;
|
||||
|
||||
private page: number = 1;
|
||||
|
||||
@Monitor('viewModel.noticeEntity')
|
||||
onNoticeChange(monitor: IMonitor) {
|
||||
const noticeEntity = monitor.value()?.now as NoticeEntity;
|
||||
this.notices = noticeEntity.notice;
|
||||
if (this.notices && this.notices.length >= 1) {
|
||||
this.startNoticeTask();
|
||||
} else {
|
||||
this.stopNoticeTask();
|
||||
}
|
||||
}
|
||||
|
||||
@Monitor('viewModel.materialList')
|
||||
onMaterialListChange(monitor: IMonitor) {
|
||||
const list = monitor.value()?.now as Array<MaterialEntity>
|
||||
if (this.page === 1) {
|
||||
this.materialList = list
|
||||
this.isRefreshing = false
|
||||
} else {
|
||||
this.materialList.push(...list)
|
||||
this.isLoading = false
|
||||
}
|
||||
this.canLoadMore = list.length === 20
|
||||
}
|
||||
|
||||
aboutToAppear(): void {
|
||||
this.initObserver();
|
||||
this.initBanner();
|
||||
this.viewModel.noticeList();
|
||||
this.viewModel.getMaterialList(this.page.toString())
|
||||
}
|
||||
|
||||
aboutToDisappear(): void {
|
||||
this.stopNoticeTask();
|
||||
}
|
||||
|
||||
initObserver() {
|
||||
AppUtil.getContext().eventHub.on(EventConstants.HomeRefreshEvent, () => {
|
||||
this.viewModel.noticeList();
|
||||
})
|
||||
}
|
||||
|
||||
initBanner() {
|
||||
if (this.banners.length > 0) {
|
||||
this.banners.splice(0, this.banners.length)
|
||||
}
|
||||
const list = ConfigManager.getHomeBanner();
|
||||
for (let i = 0; i < list.length; i++) {
|
||||
const item = list[i];
|
||||
if (item.page === 'check_Task') {
|
||||
continue
|
||||
} else if (item.page === 'recharge' && LoginManager.getUserInfo()?.vip === 3) {
|
||||
continue
|
||||
}
|
||||
this.banners.push(item);
|
||||
}
|
||||
}
|
||||
|
||||
startNoticeTask() {
|
||||
if (this.noticeTaskId === 0 && this.notices && this.notices.length >= 1) {
|
||||
this.noticeTaskId = setInterval(() => {
|
||||
this.noticeScroller.scrollBy(3, 0)
|
||||
if (this.noticeScroller.isAtEnd()) {
|
||||
this.notices = this.notices?.concat(this.notices);
|
||||
}
|
||||
}, 25)
|
||||
}
|
||||
}
|
||||
|
||||
stopNoticeTask() {
|
||||
if (this.noticeTaskId !== 0) {
|
||||
clearInterval(this.noticeTaskId);
|
||||
this.noticeTaskId = 0;
|
||||
}
|
||||
}
|
||||
|
||||
createImageOption(item: MaterialEntity): ImageKnifeOption {
|
||||
const option:ImageKnifeOption = {
|
||||
loadSrc: item.pic ? item.pic.url : '',
|
||||
placeholderSrc: $r('app.media.ic_placeholder'),
|
||||
thumbnailSrc: $r('app.media.ic_placeholder'),
|
||||
errorSrc: $r('app.media.ic_placeholder'),
|
||||
objectFit: ImageFit.Cover,
|
||||
border: {radius: 6},
|
||||
downSampling: DownSamplingStrategy.FIT_CENTER_QUALITY,
|
||||
onLoadListener:{
|
||||
onLoadSuccess: (imageInfo) => {
|
||||
item.pic_size = `${imageInfo.imageWidth}:${imageInfo.imageHeight}`
|
||||
}
|
||||
}
|
||||
}
|
||||
return option
|
||||
}
|
||||
|
||||
build() {
|
||||
Refresh({refreshing: this.isRefreshing}) {
|
||||
Scroll() {
|
||||
RelativeContainer() {
|
||||
Image($r('app.media.ic_home_top_bg')).width('100%').aspectRatio(1.973)
|
||||
|
||||
Swiper() {
|
||||
ForEach(this.banners, (item: BannerEntity) => {
|
||||
Image(item.image).width('100%').aspectRatio(2.5).margin({left: 12, right: 12})
|
||||
.onClick(() => {
|
||||
switch (item.page) {
|
||||
case 'vip': {
|
||||
if (LoginManager.getUserInfo()?.vip !== 3) {
|
||||
this.getUIContext().getRouter().pushUrl({url: RouterUrls.VIP_PAGE, params: {origin: 'banner'}})
|
||||
EventReportGlobalManager.eventReport(EventConstants.JUMP_TO_MEMBER_RECHARGE, 'banner')
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'check_Task': {
|
||||
|
||||
}
|
||||
case 'course': {
|
||||
this.getUIContext().getRouter().pushUrl({url: RouterUrls.COURSE_PAGE})
|
||||
}
|
||||
case 'web_link': {
|
||||
WantUtil.toWebBrowser(Constants.WEB_URL)
|
||||
}
|
||||
}
|
||||
})
|
||||
.borderRadius(10)
|
||||
})
|
||||
}
|
||||
.indicator(
|
||||
Indicator.dot()
|
||||
.itemWidth(4)
|
||||
.itemHeight(4)
|
||||
.selectedItemWidth(12)
|
||||
.selectedItemHeight(4)
|
||||
.color('#D6D6D6')
|
||||
.selectedColor(Color.White)
|
||||
)
|
||||
.loop(this.banners && this.banners.length > 1)
|
||||
.autoPlay(true)
|
||||
.interval(2000)
|
||||
.margin({ top: 70 })
|
||||
.visibility(this.banners && this.banners.length > 0 ? Visibility.Visible : Visibility.None)
|
||||
.id('swiper_banner')
|
||||
|
||||
RelativeContainer() {
|
||||
List({space: 100, scroller: this.noticeScroller}) {
|
||||
if (this.notices && this.notices.length >= 1) {
|
||||
ForEach(this.notices, (item: string) => {
|
||||
ListItem() {
|
||||
Text(item).height('100%').textAlign(TextAlign.Center).fontColor('#1876E2').fontSize(13)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
.listDirection(Axis.Horizontal)
|
||||
.backgroundColor('#E4EDFD')
|
||||
.borderRadius(borderRadiuses(6))
|
||||
.alignRules({
|
||||
top: { anchor: '__container__', align: VerticalAlign.Top },
|
||||
bottom: { anchor: '__container__', align: VerticalAlign.Bottom },
|
||||
left: { anchor: '__container__', align: HorizontalAlign.Start },
|
||||
right: { anchor: '__container__', align: HorizontalAlign.End }
|
||||
})
|
||||
.scrollBar(BarState.Off)
|
||||
.enableScrollInteraction(false)
|
||||
.margin({ left: 12, right: 12 })
|
||||
.padding({left: 45})
|
||||
.height(36)
|
||||
.id('li_notice')
|
||||
|
||||
Image($r('app.media.ic_notice'))
|
||||
.alignRules({
|
||||
top: { anchor: '__container__', align: VerticalAlign.Top },
|
||||
bottom: { anchor: '__container__', align: VerticalAlign.Bottom }
|
||||
})
|
||||
.margin({ left: 5, bottom: 2 })
|
||||
.width(54)
|
||||
.height(54)
|
||||
}
|
||||
.alignRules({
|
||||
top: { anchor: 'swiper_banner', align: VerticalAlign.Bottom }
|
||||
})
|
||||
.margin({top: 11})
|
||||
.width('100%')
|
||||
.height(54)
|
||||
.visibility(this.notices && this.notices?.length > 0 ? Visibility.Visible : Visibility.None)
|
||||
.id('layout_notice')
|
||||
|
||||
Row() {
|
||||
Column() {
|
||||
Row() {
|
||||
Text('链接提取').fontColor('#15005D').fontSize(17).fontFamily('almmsht')
|
||||
Image($r('app.media.ic_home_top_menu_arrow1')).width(12).height(12).margin({left: 2})
|
||||
}
|
||||
Text('涵盖大多数平台').fontColor($r('app.color.color_666666')).fontSize(11).margin({top: 4})
|
||||
Blank().layoutWeight(1)
|
||||
Text('1000+国内外视频平台').fontColor($r('app.color.color_999999')).fontSize(10)
|
||||
Row({space: 6}){
|
||||
Image($r('app.media.ic_home_link_support_icon1')).width(30).width(30)
|
||||
Image($r('app.media.ic_home_link_support_icon2')).width(30).width(30)
|
||||
Image($r('app.media.ic_home_link_support_icon3')).width(30).width(30)
|
||||
Text('更多').fontColor(Color.White).fontSize(10).width(30).height(30).textAlign(TextAlign.Center).backgroundColor('#825EFF').borderRadius(6)
|
||||
}
|
||||
.margin({top: 8})
|
||||
Row() {
|
||||
Image($r('app.media.yq_0')).width(14).height(14).borderRadius(7)
|
||||
Image($r('app.media.yq_1')).width(14).height(14).borderRadius(7).margin({left: -4})
|
||||
Image($r('app.media.yq_2')).width(14).height(14).borderRadius(7).margin({left: -4})
|
||||
Text('1000+用户体验中').fontColor($r('app.color.color_999999')).fontSize(10).margin({left: 6})
|
||||
}
|
||||
.margin({top: 12})
|
||||
}
|
||||
.width('52.7%')
|
||||
.aspectRatio(1.12)
|
||||
.backgroundImage($r('app.media.ic_home_top_menu_bg1'))
|
||||
.backgroundImageSize({width: '100%', height: '100%'})
|
||||
.padding({left: 10, top: 25, right: 10, bottom: 8})
|
||||
.alignItems(HorizontalAlign.Start)
|
||||
.id('layout_link')
|
||||
.onClick(() => {
|
||||
// let info = AppUtil.getSignatureInfoSync()
|
||||
this.getUIContext().getRouter().pushUrl({url: RouterUrls.TAKE_MATERIAL_PAGE})
|
||||
EventReportGlobalManager.eventReport(EventConstants.JUMP_TO_LINK_EXTRACT)
|
||||
})
|
||||
|
||||
Column() {
|
||||
Column() {
|
||||
Row() {
|
||||
Text('视频号').fontColor('#113100').fontSize(16).fontFamily('almmsht')
|
||||
Image($r('app.media.ic_home_top_menu_arrow2')).width(12).height(12).margin({left: 2})
|
||||
}
|
||||
Text('支持微信视频号').fontColor($r('app.color.color_666666')).fontSize(11)
|
||||
Blank().layoutWeight(1)
|
||||
Row() {
|
||||
Image($r('app.media.yq_3')).width(14).height(14).borderRadius(7)
|
||||
Image($r('app.media.yq_4')).width(14).height(14).borderRadius(7).margin({left: -4})
|
||||
Image($r('app.media.yq_5')).width(14).height(14).borderRadius(7).margin({left: -4})
|
||||
Text('1200+用户体验中').fontColor($r('app.color.color_999999')).fontSize(10).margin({left: 6})
|
||||
}
|
||||
}
|
||||
.width('48.7%')
|
||||
.aspectRatio(1.965)
|
||||
.backgroundImage($r('app.media.ic_home_top_menu_bg2'))
|
||||
.backgroundImageSize({width: '100%', height: '100%'})
|
||||
.padding({left: 10, top: 20, right: 10, bottom: 8})
|
||||
.margin({top: -5})
|
||||
.alignItems(HorizontalAlign.Start)
|
||||
.id('layout_wx_video')
|
||||
.onClick(() => {
|
||||
this.getUIContext().getRouter().pushUrl({url: RouterUrls.WX_VIDEO_PAGE, params: { isPlayback: false }})
|
||||
EventReportGlobalManager.eventReport(EventConstants.JUMP_TO_WECHAT_VIDEO)
|
||||
})
|
||||
|
||||
Column() {
|
||||
Row() {
|
||||
Text('直播回放').fontColor('#4A0006').fontSize(16).fontFamily('almmsht')
|
||||
Image($r('app.media.ic_home_top_menu_arrow3')).width(12).height(12).margin({left: 2})
|
||||
}
|
||||
Text('支持微信直播回放').fontColor($r('app.color.color_666666')).fontSize(11)
|
||||
Blank().layoutWeight(1)
|
||||
Row() {
|
||||
Image($r('app.media.yq_6')).width(14).height(14).borderRadius(7)
|
||||
Image($r('app.media.yq_7')).width(14).height(14).borderRadius(7).margin({left: -4})
|
||||
Image($r('app.media.yq_8')).width(14).height(14).borderRadius(7).margin({left: -4})
|
||||
Text('2000+用户体验中').fontColor($r('app.color.color_999999')).fontSize(10).margin({left: 6})
|
||||
}
|
||||
}
|
||||
.width('48.7%')
|
||||
.aspectRatio(2.28)
|
||||
.backgroundImage($r('app.media.ic_home_top_menu_bg3'))
|
||||
.backgroundImageSize({width: '100%', height: '100%'})
|
||||
.padding({left: 10, top: 9, right: 10, bottom: 8})
|
||||
.margin({top: 9})
|
||||
.alignItems(HorizontalAlign.Start)
|
||||
.id('layout_wx_playback')
|
||||
.onClick(() => {
|
||||
TipDialog.show(this.getUIContext(), {title: '提示', content: '仅限微信直播回放视频提取,是否前往?', callback: {
|
||||
confirm: () => {
|
||||
this.getUIContext().getRouter().pushUrl({url: RouterUrls.WX_VIDEO_PAGE, params: { isPlayback: true }})
|
||||
EventReportGlobalManager.eventReport(EventConstants.JUMP_TO_WECHAT_PLAYBACK)
|
||||
}
|
||||
}})
|
||||
})
|
||||
}
|
||||
}
|
||||
.alignRules({
|
||||
top: { anchor: 'layout_notice', align: VerticalAlign.Bottom }
|
||||
})
|
||||
.padding({left: 12, right: 12})
|
||||
.margin({ top: 10 })
|
||||
.height('auto')
|
||||
.id('layout_top_menu')
|
||||
|
||||
Grid() {
|
||||
ForEach(homeMenuList().convertToArray(), (item: HomeMenuEntity) => {
|
||||
GridItem() {
|
||||
Column() {
|
||||
Image(item.icon)
|
||||
.width(44)
|
||||
.height(44)
|
||||
Text(item.title)
|
||||
.fontColor($r('app.color.color_212226'))
|
||||
.fontSize(12)
|
||||
.margin({ top: 6 })
|
||||
}
|
||||
.alignItems(HorizontalAlign.Center)
|
||||
}
|
||||
.width('20%')
|
||||
.onClick(() => {
|
||||
switch (item.alias) {
|
||||
case 'videoToAudio': {
|
||||
this.getUIContext().getRouter().pushUrl({url: RouterUrls.TAKE_AUDIO_PAGE})
|
||||
break
|
||||
}
|
||||
case 'addWatermark': {
|
||||
this.getUIContext().getRouter().pushUrl({url: RouterUrls.ADD_WATER_MARKER_PAGE})
|
||||
break
|
||||
}
|
||||
case 'videoToText': {
|
||||
break
|
||||
}
|
||||
case 'longImageMerge': {
|
||||
break
|
||||
}
|
||||
case 'moreTools': {
|
||||
break
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
.maxCount(5)
|
||||
.layoutDirection(GridDirection.Row)
|
||||
.alignRules({
|
||||
top: { anchor: 'layout_top_menu', align: VerticalAlign.Bottom }
|
||||
})
|
||||
.margin({
|
||||
top: 20,
|
||||
left: 12,
|
||||
right: 12
|
||||
})
|
||||
.id('li_menu')
|
||||
|
||||
Column() {
|
||||
Stack() {
|
||||
Image($r('app.media.ic_tab_indicator')).width(27).height(11).margin({top: 13})
|
||||
Text('高清推荐素材').fontColor($r('app.color.color_212226')).fontSize(16).fontWeight(FontWeight.Medium)
|
||||
}
|
||||
.alignSelf(ItemAlign.Start)
|
||||
.margin({left: 12, top: 27})
|
||||
|
||||
WaterFlow({footer: this.itemFoot()}) {
|
||||
ForEach(this.materialList, (item: MaterialEntity, index: number) => {
|
||||
FlowItem() {
|
||||
ImageKnifeComponent({
|
||||
imageKnifeOption:this.createImageOption(item)
|
||||
})
|
||||
.width('100%')
|
||||
.height('100%')
|
||||
.borderRadius(6)
|
||||
.backgroundColor($r('app.color.color_ededed'))
|
||||
.onClick(() => {
|
||||
if (item.pic?.url) {
|
||||
this.getUIContext().getRouter().pushUrl({url: RouterUrls.MATERIAL_DETAIL_PAGE, params: {material: item}})
|
||||
}
|
||||
})
|
||||
}
|
||||
.width('100%')
|
||||
.height(500 / (index % 2 === 0 ? 2 : 3))
|
||||
})
|
||||
}
|
||||
.columnsTemplate('1fr 1fr')
|
||||
.columnsGap(7)
|
||||
.rowsGap(7)
|
||||
.width('100%')
|
||||
.height('100%')
|
||||
.padding({left: 12, right: 12})
|
||||
.margin({top: 14})
|
||||
.onReachEnd(() => {
|
||||
this.page++
|
||||
this.isLoading = true
|
||||
this.viewModel.getMaterialList(this.page.toString())
|
||||
})
|
||||
.nestedScroll({
|
||||
scrollForward: NestedScrollMode.PARENT_FIRST,
|
||||
scrollBackward: NestedScrollMode.SELF_FIRST
|
||||
})
|
||||
}
|
||||
.alignRules({
|
||||
top: {anchor: 'li_menu', align: VerticalAlign.Bottom}
|
||||
})
|
||||
.height('100%')
|
||||
}
|
||||
.height('auto')
|
||||
}
|
||||
.scrollBar(BarState.Off)
|
||||
}
|
||||
.backgroundColor(Color.White)
|
||||
.onRefreshing(() => {
|
||||
this.page = 1
|
||||
this.isRefreshing = true
|
||||
this.viewModel.getMaterialList(this.page.toString())
|
||||
})
|
||||
}
|
||||
|
||||
@Builder
|
||||
itemFoot() {
|
||||
// 注意:不要直接用IfElse节点作为footer的根节点
|
||||
// 必须在外面使用(Column/Row/Stack等)容器包裹,确保布局正确
|
||||
Column() {
|
||||
if (!this.canLoadMore) {
|
||||
Text('到底啦')
|
||||
.width('100%')
|
||||
.height(50)
|
||||
.textAlign(TextAlign.Center)
|
||||
} else if (this.isLoading) {
|
||||
Row() {
|
||||
LoadingProgress().height(32).width(48)
|
||||
Text("加载中")
|
||||
}.width("100%")
|
||||
.height(50)
|
||||
.justifyContent(FlexAlign.Center)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
import { TitleBar } from '../../../../view/TitleBar'
|
||||
|
||||
@Entry
|
||||
@ComponentV2
|
||||
struct CoursePage {
|
||||
build() {
|
||||
Column() {
|
||||
TitleBar({title: '指导教程'}).width('100%')
|
||||
Scroll() {
|
||||
Column() {
|
||||
Image($r('app.media.ic_course1'))
|
||||
Image($r('app.media.ic_course2'))
|
||||
Image($r('app.media.ic_course3'))
|
||||
}
|
||||
.height('auto')
|
||||
}
|
||||
.layoutWeight(1)
|
||||
.scrollBar(BarState.Off)
|
||||
}
|
||||
.backgroundColor($r('app.color.window_background'))
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,600 @@
|
|||
import { AppUtil, FileUtil, KeyboardUtil, ObjectUtil, PasteboardUtil, StrUtil } from '@pura/harmony-utils';
|
||||
import { RouterUrls } from '../../../../common/RouterUrls';
|
||||
import { MaterialLoadingDialog } from '../../../../dialog/MaterialLoadingDialog';
|
||||
import {
|
||||
AudioMaterial,
|
||||
ImageMaterial,
|
||||
MaterialDetailEntity,
|
||||
MaterialInfoEntity,
|
||||
MediaEntity,
|
||||
TextMaterial,
|
||||
VideoMaterial
|
||||
} from '../../../../entity/MaterialInfoEntity';
|
||||
import { VipPermissionEntity } from '../../../../entity/VipPermissionEntity';
|
||||
import { LoginManager } from '../../../../manager/LoginGlobalManager';
|
||||
import { ToastUtils } from '../../../../utils/ToastUtils';
|
||||
import { LinkRecognizeViewModel } from '../../../../viewModel/LinkRecognizeViewModel';
|
||||
import { AudioMaterialPage } from './material/AudioMaterialPage';
|
||||
import { ImageMaterialPage } from './material/ImageMaterialPage';
|
||||
import { TextMaterialPage } from './material/TextMaterialPage';
|
||||
import { VideoMaterialPage } from './material/VideoMaterialPage';
|
||||
import { router } from '@kit.ArkUI';
|
||||
import { MediaDownloader } from '../../../../net/MediaDownloader';
|
||||
import { ShareManager } from '../../../../manager/ShareManager';
|
||||
import { systemDateTime } from '@kit.BasicServicesKit';
|
||||
import { SaveUtils } from '../../../../utils/SaveUtils';
|
||||
import { DownloadDialog, DownloadStatus } from '../../../../dialog/DownloadDialog';
|
||||
import { EventConstants } from '../../../../common/EventConstants';
|
||||
import { SimpleTipDialog } from '../../../../dialog/SimpleTipDialog';
|
||||
import { EventReportGlobalManager } from '../../../../manager/EventReportGlobalManager';
|
||||
import { PasteboardUtils } from '../../../../utils/PasteboardUtils';
|
||||
import { TipDialog } from '../../../../dialog/TipDialog';
|
||||
import { PrefUtils } from '../../../../utils/PrefUtils';
|
||||
|
||||
@Entry
|
||||
@ComponentV2
|
||||
struct TakeMaterialPage {
|
||||
@Local inputText: string = '';
|
||||
@Local currentIndex: number = 0;
|
||||
|
||||
@Local materialInfo?: MaterialInfoEntity;
|
||||
|
||||
@Local videoList: Array<VideoMaterial> = [];
|
||||
@Local imageList: Array<ImageMaterial> = [];
|
||||
@Local audioList: Array<AudioMaterial> = [];
|
||||
@Local textList: Array<TextMaterial> = [];
|
||||
|
||||
@Local videoRowCount: number = 1;
|
||||
@Local imageRowCount: number = 1;
|
||||
|
||||
viewModel: LinkRecognizeViewModel = new LinkRecognizeViewModel(this.getUIContext());
|
||||
|
||||
tabController: TabsController = new TabsController();
|
||||
titles: Array<string> = ['视频', '图片', '音频', '文本'];
|
||||
logId?: string;
|
||||
type: number = 0
|
||||
originText: string = ''
|
||||
|
||||
mediaDownloader?: MediaDownloader | null
|
||||
selectedList: Array<MediaEntity> = []
|
||||
cacheFileUris: Array<string> = []
|
||||
downloadIndex: number = 0
|
||||
totalSize = 0
|
||||
downloadStatus = DownloadStatus.DOWNLOADING
|
||||
|
||||
@Monitor('viewModel.materialInfo')
|
||||
onMaterialInfoChange(monitor: IMonitor) {
|
||||
const info = monitor.value()?.now as MaterialInfoEntity
|
||||
this.logId = info.logid;
|
||||
MaterialLoadingDialog.show(this.getUIContext(), info.status_name)
|
||||
this.viewModel.analysisMaterial(info.logid, info.timeout);
|
||||
}
|
||||
|
||||
@Monitor('viewModel.analysisInfo')
|
||||
onAnalysisInfoInfoChange(monitor: IMonitor) {
|
||||
const info = monitor.value()?.now as MaterialInfoEntity
|
||||
if (info.material && info.material !== null) {
|
||||
this.materialInfo = info;
|
||||
this.originText = this.inputText
|
||||
this.materialInfo.logid = this.logId!!
|
||||
this.createVideoList(info.material);
|
||||
this.createImageList(info.material);
|
||||
this.createAudioList(info.material);
|
||||
this.createTextList(info.material);
|
||||
if (this.videoList.length > 0) {
|
||||
this.tabController.changeIndex(0);
|
||||
} else if (this.imageList.length > 0) {
|
||||
this.tabController.changeIndex(1);
|
||||
}
|
||||
MaterialLoadingDialog.dismiss();
|
||||
} else {
|
||||
if (info.status !== 1) {
|
||||
ToastUtils.show(info.status_name)
|
||||
MaterialLoadingDialog.dismiss()
|
||||
} else {
|
||||
MaterialLoadingDialog.update(info.status_name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Monitor('viewModel.permissionInfo')
|
||||
onPermissionInfoChange(monitor: IMonitor) {
|
||||
const info = monitor.value()?.now as VipPermissionEntity;
|
||||
if (info.auth) {
|
||||
if (!LoginManager.isLogin()) {
|
||||
this.getUIContext().getRouter().pushUrl({url: RouterUrls.LOGIN_PAGE, params: {from: 1}}, router.RouterMode.Single)
|
||||
return;
|
||||
}
|
||||
this.shareOrDownload()
|
||||
} else {
|
||||
if (!info.auth_ad) {
|
||||
this.getUIContext().getRouter().pushUrl({url: RouterUrls.VIP_PAGE, params: {origin: 'download_material'}})
|
||||
EventReportGlobalManager.eventReport(EventConstants.JUMP_TO_MEMBER_RECHARGE, 'download_material')
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Monitor('viewModel.errorCode')
|
||||
onErrorCodeChange(monitor: IMonitor) {
|
||||
const errorCode = monitor.value()?.now as number;
|
||||
if (errorCode === 12002 || errorCode === 12003 || errorCode === 12004) {
|
||||
this.getUIContext().getRouter().pushUrl({url: RouterUrls.RECHARGE_DIAMOND_PAGE});
|
||||
EventReportGlobalManager.eventReport(EventConstants.JUMP_TO_RECHARGE_DIAMOND, 'download_material')
|
||||
ToastUtils.show('钻石已用完')
|
||||
}
|
||||
}
|
||||
|
||||
aboutToAppear(): void {
|
||||
const params = this.getUIContext().getRouter().getParams() as Record<string, Object>
|
||||
if (params && params.url) {
|
||||
this.inputText = params.url as string
|
||||
this.parseUrl(this.inputText)
|
||||
}
|
||||
}
|
||||
|
||||
aboutToDisappear(): void {
|
||||
this.viewModel.cancelInterval()
|
||||
}
|
||||
|
||||
onPageShow(): void {
|
||||
this.checkPasteboard()
|
||||
}
|
||||
|
||||
checkPasteboard() {
|
||||
PasteboardUtils.isNeedGetPermissionFromUser()
|
||||
.then((isNeed) => {
|
||||
if (isNeed) {
|
||||
PasteboardUtil.requestPermissions()
|
||||
.then((isGranted) => {
|
||||
if (isGranted) {
|
||||
let content = PasteboardUtil.getDataTextSync()
|
||||
if (StrUtil.isNotEmpty(content) && content !== PasteboardUtils.clipText && PasteboardUtils.isValidUrl(content)) {
|
||||
TipDialog.show(this.getUIContext(), {title: '您已复制链接,是否粘贴', content: content, leftText: '取消', rightText: '粘贴', callback: {
|
||||
confirm: () => {
|
||||
PasteboardUtils.clipText = content
|
||||
this.inputText = content
|
||||
this.parseUrl(content)
|
||||
},
|
||||
cancel: () => {
|
||||
PasteboardUtils.clipText = content
|
||||
}
|
||||
}})
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch(() => {})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
showSaveTip(isAudio: boolean = false) {
|
||||
if (!isAudio) {
|
||||
if (PrefUtils.getBoolean('show_save_tip', true)) {
|
||||
SimpleTipDialog.show(this.getUIContext(), {title: '重要提示', content: '下载完成后需要您点击弹窗允许保存之后才能保存文件到相册', callback: {
|
||||
confirm: () => {
|
||||
this.viewModel.checkVip();
|
||||
PrefUtils.put('show_save_tip', false)
|
||||
}
|
||||
}})
|
||||
} else {
|
||||
this.viewModel.checkVip();
|
||||
}
|
||||
} else {
|
||||
this.viewModel.checkVip();
|
||||
}
|
||||
}
|
||||
|
||||
shareOrDownload() {
|
||||
this.cacheFileUris.length = 0
|
||||
if (this.type == 0) {
|
||||
if (this.selectedList.length > 0) {
|
||||
this.shareMedia(this.selectedList[0])
|
||||
}
|
||||
} else {
|
||||
if (this.selectedList.length > 0) {
|
||||
this.downloadIndex = 0
|
||||
this.downloadMedia(this.selectedList[this.downloadIndex])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
shareMedia(media: MediaEntity) {
|
||||
let filePath = FileUtil.getCacheDirPath() + FileUtil.separator + media.initFileName()
|
||||
if (FileUtil.accessSync(filePath) && FileUtil.isFile(filePath) && !(media.totalSize === 0 || media.currentLen !== media.totalSize)) {
|
||||
this.shareFile(media)
|
||||
} else {
|
||||
this.showDownloadDialog(media instanceof VideoMaterial && media.isMerge ? DownloadStatus.VIDEO_DOWNLOADING : DownloadStatus.DOWNLOADING)
|
||||
if (media.isMerge) {
|
||||
this.beforeDoMerge(media)
|
||||
}
|
||||
this.download(media, true)
|
||||
}
|
||||
}
|
||||
|
||||
async downloadMedia(media: MediaEntity) {
|
||||
let filePath = FileUtil.getCacheDirPath() + FileUtil.separator + media.initFileName()
|
||||
if (FileUtil.accessSync(filePath) && FileUtil.isFile(filePath) && !(media.totalSize === 0 || media.currentLen !== media.totalSize)) {
|
||||
this.cacheFileUris.push(FileUtil.getUriFromPath(filePath))
|
||||
if (this.downloadIndex < this.selectedList.length - 1) {
|
||||
this.downloadIndex++
|
||||
this.downloadMedia(this.selectedList[this.downloadIndex])
|
||||
} else {
|
||||
let saved = await this.saveFile(media)
|
||||
if (saved) {
|
||||
if (this.downloadIndex < this.selectedList.length - 1) {
|
||||
this.downloadIndex++
|
||||
this.downloadMedia(this.selectedList[this.downloadIndex])
|
||||
} else {
|
||||
this.updateDownloadDialog(DownloadStatus.COMPLETED, this.totalSize, this.totalSize, media instanceof AudioMaterial)
|
||||
}
|
||||
} else {
|
||||
ToastUtils.show('保存失败')
|
||||
this.dismissDownloadDialog()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.showDownloadDialog(media instanceof VideoMaterial && media.isMerge ? DownloadStatus.VIDEO_DOWNLOADING : DownloadStatus.DOWNLOADING)
|
||||
if (media.isMerge) {
|
||||
this.beforeDoMerge(media)
|
||||
}
|
||||
this.download(media)
|
||||
}
|
||||
}
|
||||
|
||||
beforeDoMerge(media: MediaEntity) {
|
||||
let video = media as VideoMaterial
|
||||
let audio = video.audio
|
||||
let name = systemDateTime.getTime()
|
||||
if (StrUtil.isEmpty(video.cacheName)) video.cacheName = `merge_${name}.mp4`
|
||||
if (audio && StrUtil.isEmpty(audio?.cacheName)) audio.cacheName = `merge_${name}.mp3`
|
||||
}
|
||||
|
||||
async download(media: MediaEntity, isShare: boolean = false) {
|
||||
this.viewModel.reportStatus(this.materialInfo!!.logid, '1')
|
||||
media.initFileName()
|
||||
media.origin = this.originText
|
||||
this.mediaDownloader = MediaDownloader.getInstance()
|
||||
this.mediaDownloader.setProxyList(this.materialInfo?.material?.proxyUrlList)
|
||||
.callback({
|
||||
onSuccess: async (path) => {
|
||||
if (isShare) {
|
||||
this.shareFile(media)
|
||||
} else {
|
||||
this.cacheFileUris.push(FileUtil.getUriFromPath(path))
|
||||
if (this.downloadIndex < this.selectedList.length - 1) {
|
||||
this.downloadIndex++
|
||||
this.downloadMedia(this.selectedList[this.downloadIndex])
|
||||
} else {
|
||||
let saved = await this.saveFile(media)
|
||||
if (saved) {
|
||||
if (this.downloadIndex < this.selectedList.length - 1) {
|
||||
this.downloadIndex++
|
||||
this.downloadMedia(this.selectedList[this.downloadIndex])
|
||||
} else {
|
||||
this.updateDownloadDialog(DownloadStatus.COMPLETED, this.totalSize, this.totalSize, media instanceof AudioMaterial)
|
||||
}
|
||||
} else {
|
||||
ToastUtils.show('保存失败')
|
||||
this.dismissDownloadDialog()
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
onGetTotal: (total) => {
|
||||
this.totalSize = total
|
||||
this.updateDownloadDialog(this.downloadStatus, total)
|
||||
},
|
||||
onProgress: (progress) => {
|
||||
this.updateDownloadDialog(this.downloadStatus, this.totalSize, progress)
|
||||
},
|
||||
onMerge: (step) => {
|
||||
if (step === 4) {
|
||||
this.updateDownloadDialog(DownloadStatus.AUDIO_DOWNLOADING)
|
||||
} else {
|
||||
this.updateDownloadDialog(DownloadStatus.PROCESSING)
|
||||
}
|
||||
},
|
||||
onPause:() => {
|
||||
this.dismissDownloadDialog()
|
||||
},
|
||||
onCancel: () => {
|
||||
this.dismissDownloadDialog()
|
||||
},
|
||||
onFailed: (msg) => {
|
||||
ToastUtils.show('下载失败:' + msg)
|
||||
this.dismissDownloadDialog()
|
||||
this.viewModel.reportStatus(this.materialInfo!!.logid, '-1', `${media.totalSize}`, msg)
|
||||
this.reportErrorEvent(media, msg)
|
||||
}
|
||||
})
|
||||
.down(media);
|
||||
}
|
||||
|
||||
shareFile(media: MediaEntity) {
|
||||
ShareManager.shareFile(FileUtil.getCacheDirPath() + FileUtil.separator + media.initFileName())
|
||||
this.viewModel.reportStatus(this.materialInfo!!.logid, '2', `${media.totalSize}`)
|
||||
this.dismissDownloadDialog()
|
||||
}
|
||||
|
||||
async saveFile(media: MediaEntity): Promise<boolean> {
|
||||
let saved = false
|
||||
if (media instanceof VideoMaterial) {
|
||||
saved = await SaveUtils.saveImageVideoToAlbumDialog(this.cacheFileUris)
|
||||
} else if (media instanceof ImageMaterial) {
|
||||
saved = await SaveUtils.saveImageVideoToAlbumDialog(this.cacheFileUris)
|
||||
} else if (media instanceof AudioMaterial) {
|
||||
saved = await SaveUtils.saveAudioToMusic(this.cacheFileUris)
|
||||
}
|
||||
if (saved) {
|
||||
let totalSize = 0
|
||||
this.cacheFileUris.forEach((uri) => {
|
||||
let stat = FileUtil.statSync(FileUtil.getFilePath(uri))
|
||||
totalSize += stat.size
|
||||
})
|
||||
this.viewModel.reportStatus(this.materialInfo!!.logid, '2', `${totalSize}`)
|
||||
} else {
|
||||
this.viewModel.reportStatus(this.materialInfo!!.logid, '-1', `保存失败`)
|
||||
}
|
||||
return Promise.resolve(saved)
|
||||
}
|
||||
|
||||
showDownloadDialog(status: DownloadStatus = DownloadStatus.DOWNLOADING) {
|
||||
this.downloadStatus = status
|
||||
DownloadDialog.show(this.getUIContext(), { status: status, totalSize: 0, progress: 0, totalCount: this.selectedList.length, index: this.downloadIndex, callback: {
|
||||
confirm: () => {
|
||||
if (this.downloadStatus === DownloadStatus.COMPLETED) {
|
||||
EventReportGlobalManager.eventReport(EventConstants.DIALOG_GO_TO_VIEW, this.titles[this.currentIndex])
|
||||
AppUtil.getContext().eventHub.emit(EventConstants.JumpToRecordEvent, this.currentIndex)
|
||||
this.getUIContext().getRouter().back()
|
||||
} else {
|
||||
//todo 后台下载
|
||||
}
|
||||
},
|
||||
cancel: () => {
|
||||
if (this.downloadStatus !== DownloadStatus.COMPLETED) {
|
||||
if (this.mediaDownloader) {
|
||||
this.mediaDownloader.cancel()
|
||||
EventReportGlobalManager.eventReport(EventConstants.CANCEL_DOWNLOAD_VIDEO, this.selectedList[this.downloadIndex].url)
|
||||
}
|
||||
} else {
|
||||
EventReportGlobalManager.eventReport(EventConstants.DIALOG_CONFIRM_SAVE_FILE, this.titles[this.currentIndex])
|
||||
}
|
||||
}
|
||||
} })
|
||||
}
|
||||
|
||||
updateDownloadDialog(status: DownloadStatus = DownloadStatus.DOWNLOADING, totalSize: number = 0, progress: number = 0, isAudio: boolean = false) {
|
||||
this.downloadStatus = status
|
||||
DownloadDialog.update({ status: status, totalSize: totalSize, progress: progress, totalCount: this.selectedList.length, index: this.downloadIndex, isAudio: isAudio })
|
||||
}
|
||||
|
||||
dismissDownloadDialog() {
|
||||
this.downloadStatus = DownloadStatus.DOWNLOADING
|
||||
this.totalSize = 0
|
||||
this.downloadIndex = 0
|
||||
this.mediaDownloader = null
|
||||
DownloadDialog.dismiss()
|
||||
}
|
||||
|
||||
parseUrl(url: string) {
|
||||
if (StrUtil.isNotEmpty(this.inputText)) {
|
||||
this.viewModel.getMaterialInfo(url);
|
||||
}
|
||||
}
|
||||
|
||||
createVideoList(material?: MaterialDetailEntity) {
|
||||
const list = new Array<VideoMaterial>();
|
||||
material?.video?.forEach((item, index) => {
|
||||
item.isThreading = material?.threading!!;
|
||||
if (material?.merge && material.audio && material.audio.length > index) {
|
||||
item.audio = material.audio[index];
|
||||
item.isMerge = true;
|
||||
}
|
||||
if (material?.image && material.image.length > index) {
|
||||
item.thumb = material.image[index].url;
|
||||
}
|
||||
list.push(item);
|
||||
})
|
||||
this.videoList = list.map(item => ObjectUtil.assign(new VideoMaterial(), item) as VideoMaterial);
|
||||
if (this.videoList.length > 0) {
|
||||
this.videoList[0].isChecked = true
|
||||
}
|
||||
this.videoRowCount = this.computeRowCount(this.videoList);
|
||||
}
|
||||
|
||||
createImageList(material: MaterialDetailEntity) {
|
||||
if (material.image) {
|
||||
this.imageList = material.image.map(item => ObjectUtil.assign(new ImageMaterial(), item) as ImageMaterial);
|
||||
if (this.imageList.length > 0) {
|
||||
this.imageList[0].isChecked = true
|
||||
}
|
||||
this.imageRowCount = this.computeRowCount(this.imageList);
|
||||
}
|
||||
}
|
||||
|
||||
createAudioList(material: MaterialDetailEntity) {
|
||||
if (material.audio) {
|
||||
this.audioList = material.audio.map(item => ObjectUtil.assign(new AudioMaterial(), item) as AudioMaterial);
|
||||
if (this.audioList.length > 0) {
|
||||
this.audioList[0].isChecked = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
createTextList(material: MaterialDetailEntity) {
|
||||
const list = new Array<TextMaterial>();
|
||||
if (material.desc) {
|
||||
const text = new TextMaterial()
|
||||
text.title = material.title;
|
||||
text.desc = material.desc;
|
||||
list.push(text);
|
||||
}
|
||||
this.textList = list;
|
||||
if (this.textList.length > 0) {
|
||||
this.textList[0].isChecked = true
|
||||
}
|
||||
}
|
||||
|
||||
computeRowCount(list: Array<MediaEntity>): number {
|
||||
if (list.length > 8) {
|
||||
return 3;
|
||||
} else if (list.length >= 3 && list.length <= 8) {
|
||||
return 2;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
reportErrorEvent(media: MediaEntity, message: string) {
|
||||
if (media instanceof VideoMaterial) {
|
||||
EventReportGlobalManager.eventReport(EventConstants.ERROR_CLIENT_DOWNLOAD_VIDEO, media.url, message)
|
||||
} else if (media instanceof ImageMaterial) {
|
||||
EventReportGlobalManager.eventReport(EventConstants.ERROR_CLIENT_DOWNLOAD_IMG, media.url, message)
|
||||
} else if (media instanceof AudioMaterial) {
|
||||
EventReportGlobalManager.eventReport(EventConstants.ERROR_CLIENT_DOWNLOAD_AUDIO, media.url, message)
|
||||
}
|
||||
}
|
||||
|
||||
build() {
|
||||
Column() {
|
||||
Row() {
|
||||
Button({ type: ButtonType.Circle, stateEffect: true }) {
|
||||
Image($r('app.media.ic_back')).width(24).height(24)
|
||||
}
|
||||
.width(40)
|
||||
.height(40)
|
||||
.margin({ left: 10 })
|
||||
.onClick(() => {
|
||||
this.getUIContext().getRouter().back()
|
||||
})
|
||||
.backgroundColor(Color.Transparent)
|
||||
|
||||
Row() {
|
||||
Image($r('app.media.ic_link')).width(18).height(18)
|
||||
TextInput({ placeholder: '请输入链接地址', text: this.inputText })
|
||||
.layoutWeight(1)
|
||||
.fontColor('#D6D6D6')
|
||||
.fontSize(14)
|
||||
.placeholderColor($r('app.color.color_30ffffff'))
|
||||
.placeholderFont({ size: 14 })
|
||||
.onChange((value: string) => {
|
||||
this.inputText = value;
|
||||
})
|
||||
Image($r('app.media.ic_clear_text'))
|
||||
.width(18)
|
||||
.height(18)
|
||||
.padding(2)
|
||||
.visibility(StrUtil.isNotEmpty(this.inputText) ? Visibility.Visible : Visibility.None)
|
||||
.onClick(() => {
|
||||
this.inputText = '';
|
||||
})
|
||||
Divider()
|
||||
.vertical(true)
|
||||
.strokeWidth(1)
|
||||
.height(14)
|
||||
.color($r('app.color.color_10ffffff'))
|
||||
.margin({ left: 12, right: 12 })
|
||||
Text('获取').fontColor($r('app.color.color_80ffffff')).fontSize(14)
|
||||
.onClick(() => {
|
||||
if (StrUtil.isNotEmpty(this.inputText)) {
|
||||
KeyboardUtil.hide()
|
||||
this.parseUrl(this.inputText)
|
||||
EventReportGlobalManager.eventReport(EventConstants.GET_MATERIAL, "material-button", this.inputText)
|
||||
} else {
|
||||
ToastUtils.show('请输入链接地址')
|
||||
}
|
||||
})
|
||||
}
|
||||
.layoutWeight(1)
|
||||
.height(34)
|
||||
.borderRadius(20)
|
||||
.backgroundColor($r('app.color.color_333333'))
|
||||
.margin({ left: 20, right: 16 })
|
||||
.padding({ left: 10, right: 10 })
|
||||
}.height(100).padding({ top: 50 })
|
||||
|
||||
Tabs({ barPosition: BarPosition.Start, controller: this.tabController }) {
|
||||
TabContent() {
|
||||
VideoMaterialPage({
|
||||
mediaList: this.videoList, rowCount: this.videoRowCount,
|
||||
onShare:(video) => {
|
||||
this.type = 0
|
||||
this.selectedList.length = 0
|
||||
this.selectedList.push(video)
|
||||
this.viewModel.checkVip();
|
||||
},
|
||||
onSave: (list) => {
|
||||
this.type = 1
|
||||
this.selectedList = list
|
||||
this.showSaveTip();
|
||||
} })
|
||||
}
|
||||
.tabBar(this.tabBuilder(this.titles[0], 0))
|
||||
|
||||
TabContent() {
|
||||
ImageMaterialPage({
|
||||
mediaList: this.imageList, rowCount: this.imageRowCount,
|
||||
onShare:(image) => {
|
||||
this.type = 0
|
||||
this.selectedList.length = 0
|
||||
this.selectedList.push(image)
|
||||
this.viewModel.checkVip();
|
||||
},
|
||||
onSave: (list) => {
|
||||
this.type = 1
|
||||
this.selectedList = list
|
||||
this.showSaveTip();
|
||||
} })
|
||||
}
|
||||
.tabBar(this.tabBuilder(this.titles[1], 1))
|
||||
|
||||
TabContent() {
|
||||
AudioMaterialPage({
|
||||
mediaList: this.audioList,
|
||||
onShare:(audio) => {
|
||||
this.type = 0
|
||||
this.selectedList.length = 0
|
||||
this.selectedList.push(audio)
|
||||
this.viewModel.checkVip();
|
||||
},
|
||||
onSave: (list) => {
|
||||
this.type = 1
|
||||
this.selectedList = list
|
||||
this.showSaveTip(true);
|
||||
} })
|
||||
}
|
||||
.tabBar(this.tabBuilder(this.titles[2], 2))
|
||||
|
||||
TabContent() {
|
||||
TextMaterialPage({ mediaList: this.textList })
|
||||
}
|
||||
.tabBar(this.tabBuilder(this.titles[3], 3))
|
||||
}
|
||||
.scrollable(false)
|
||||
.onTabBarClick((index) => {
|
||||
this.currentIndex = index;
|
||||
})
|
||||
/*.onSelected((index: number) => {
|
||||
this.currentIndex = index;
|
||||
})*/
|
||||
.layoutWeight(1)
|
||||
}
|
||||
.width('100%')
|
||||
.height('100%')
|
||||
.backgroundColor($r('app.color.window_background'))
|
||||
}
|
||||
|
||||
@Builder
|
||||
tabBuilder(title: string, targetIndex: number) {
|
||||
Column() {
|
||||
Text(title)
|
||||
.fontColor(this.currentIndex === targetIndex ? $r("app.color.color_466afd") : $r('app.color.color_50ffffff'))
|
||||
.fontSize(this.currentIndex === targetIndex ? 17 : 14)
|
||||
.fontWeight(this.currentIndex === targetIndex ? FontWeight.Medium : FontWeight.Regular)
|
||||
}
|
||||
.width('100%')
|
||||
.height(50)
|
||||
.justifyContent(FlexAlign.Center)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,114 @@
|
|||
import { AudioMaterial } from '../../../../../entity/MaterialInfoEntity';
|
||||
import { ToastUtils } from '../../../../../utils/ToastUtils';
|
||||
import { EmptyView, PageStatus } from '../../../../../view/EmptyView';
|
||||
import { AudioMaterialItemView } from '../../../../../view/MaterialItemView';
|
||||
|
||||
@ComponentV2
|
||||
export struct AudioMaterialPage {
|
||||
@Param mediaList: Array<AudioMaterial> = [];
|
||||
@Param onShare?: (audio: AudioMaterial) => void = undefined
|
||||
@Param onSave?: (list: Array<AudioMaterial>) => void = undefined
|
||||
|
||||
@Local isCheckAll: boolean = false
|
||||
|
||||
selectedItems(): Array<AudioMaterial> {
|
||||
const list = new Array<AudioMaterial>();
|
||||
this.mediaList.forEach((item) => {
|
||||
if (item.isChecked) {
|
||||
list.push(item);
|
||||
}
|
||||
})
|
||||
return list;
|
||||
}
|
||||
|
||||
build() {
|
||||
Stack() {
|
||||
Column() {
|
||||
List({ space: 10 }) {
|
||||
ForEach(this.mediaList, (item: AudioMaterial, index) => {
|
||||
ListItem() {
|
||||
AudioMaterialItemView({ media: item })
|
||||
}
|
||||
.onClick(() => {
|
||||
item.isChecked = !item.isChecked;
|
||||
this.isCheckAll = this.mediaList.every(item => item.isChecked)
|
||||
})
|
||||
})
|
||||
}
|
||||
.width('auto')
|
||||
.layoutWeight(1)
|
||||
.scrollBar(BarState.Off)
|
||||
.margin({ left: 16, right: 16, bottom: 15 })
|
||||
|
||||
Row() {
|
||||
Row() {
|
||||
Image(this.mediaList.every(item => item.isChecked) ? $r('app.media.ic_check_true') : $r('app.media.ic_check_false')).width(18).height(18)
|
||||
Text('全选').fontColor($r('app.color.color_90ffffff')).fontSize(16).margin({ left: 7 })
|
||||
}
|
||||
.onClick(() => {
|
||||
this.isCheckAll = !this.isCheckAll;
|
||||
this.mediaList.forEach((item) => {
|
||||
item.isChecked = this.isCheckAll;
|
||||
})
|
||||
})
|
||||
|
||||
Blank().layoutWeight(1)
|
||||
|
||||
Button('转发', { type: ButtonType.Capsule, stateEffect: true })
|
||||
.width(122)
|
||||
.height(40)
|
||||
.backgroundColor($r('app.color.color_333333'))
|
||||
.fontColor($r('app.color.color_50ffffff'))
|
||||
.fontSize(15)
|
||||
.onClick(() => {
|
||||
if (this.onShare) {
|
||||
const list = this.selectedItems();
|
||||
if (list.length === 0) {
|
||||
ToastUtils.show('请选择要转发的音频');
|
||||
} else if (list.length > 1) {
|
||||
ToastUtils.show('一次只能转发一个音频');
|
||||
} else {
|
||||
this.onShare(list[0]);
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
Button('保存', { type: ButtonType.Capsule, stateEffect: true })
|
||||
.width(122)
|
||||
.height(40)
|
||||
.linearGradient({
|
||||
colors: [['#F62C6C', 0.0], ['#FC4F54', 1.0]],
|
||||
direction: GradientDirection.Right
|
||||
})
|
||||
.fontColor($r('app.color.color_90ffffff'))
|
||||
.fontSize(15)
|
||||
.margin({ left: 12 })
|
||||
.onClick(() => {
|
||||
if (this.onSave) {
|
||||
const list = this.selectedItems();
|
||||
if (list.length === 0) {
|
||||
ToastUtils.show('请选择要保存的音频');
|
||||
} else {
|
||||
this.onSave(list);
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
.backgroundColor($r('app.color.color_222222'))
|
||||
.padding({
|
||||
left: 16,
|
||||
top: 10,
|
||||
right: 16,
|
||||
bottom: 30
|
||||
})
|
||||
.visibility(this.mediaList.length > 0 ? Visibility.Visible : Visibility.None)
|
||||
}
|
||||
|
||||
EmptyView({
|
||||
status: this.mediaList.length > 0 ? PageStatus.GONE : PageStatus.NO_DATA,
|
||||
noDataImage: $r('app.media.ic_empty_audio'),
|
||||
noDataText: '暂无音频'
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,117 @@
|
|||
import { ImageMaterial } from '../../../../../entity/MaterialInfoEntity';
|
||||
import { ToastUtils } from '../../../../../utils/ToastUtils';
|
||||
import { EmptyView, PageStatus } from '../../../../../view/EmptyView';
|
||||
import { ImageMaterialItemView } from '../../../../../view/MaterialItemView';
|
||||
|
||||
@ComponentV2
|
||||
export struct ImageMaterialPage {
|
||||
@Param mediaList: Array<ImageMaterial> = [];
|
||||
@Param rowCount: number = 1;
|
||||
@Param onShare?: (image: ImageMaterial) => void = undefined
|
||||
@Param onSave?: (list: Array<ImageMaterial>) => void = undefined
|
||||
|
||||
@Local isCheckAll: boolean = false
|
||||
|
||||
selectedItems(): Array<ImageMaterial> {
|
||||
const list = new Array<ImageMaterial>();
|
||||
this.mediaList.forEach((item) => {
|
||||
if (item.isChecked) {
|
||||
list.push(item);
|
||||
}
|
||||
})
|
||||
return list;
|
||||
}
|
||||
|
||||
build() {
|
||||
Stack() {
|
||||
Column() {
|
||||
Grid() {
|
||||
ForEach(this.mediaList, (item: ImageMaterial, index) => {
|
||||
GridItem() {
|
||||
ImageMaterialItemView({ media: item, rowCount: this.rowCount })
|
||||
}
|
||||
.onClick(() => {
|
||||
item.isChecked = !item.isChecked;
|
||||
this.isCheckAll = this.mediaList.every(item => item.isChecked)
|
||||
})
|
||||
})
|
||||
}
|
||||
.scrollBar(BarState.Off)
|
||||
.columnsTemplate(this.rowCount === 1 ? '1fr' : this.rowCount === 2 ? '1fr 1fr' : '1fr 1fr 1fr')
|
||||
.rowsGap(10)
|
||||
.columnsGap(10)
|
||||
.margin({ left: 16, right: 16, bottom: 15 })
|
||||
.layoutWeight(1)
|
||||
|
||||
Row() {
|
||||
Row() {
|
||||
Image(this.mediaList.every(item => item.isChecked) ? $r('app.media.ic_check_true') : $r('app.media.ic_check_false')).width(18).height(18)
|
||||
Text('全选').fontColor($r('app.color.color_90ffffff')).fontSize(16).margin({ left: 7 })
|
||||
}
|
||||
.onClick(() => {
|
||||
this.isCheckAll = !this.isCheckAll;
|
||||
this.mediaList.forEach((item) => {
|
||||
item.isChecked = this.isCheckAll;
|
||||
})
|
||||
})
|
||||
|
||||
Blank().layoutWeight(1)
|
||||
|
||||
Button('转发', { type: ButtonType.Capsule, stateEffect: true })
|
||||
.width(122)
|
||||
.height(40)
|
||||
.backgroundColor($r('app.color.color_333333'))
|
||||
.fontColor($r('app.color.color_50ffffff'))
|
||||
.fontSize(15)
|
||||
.onClick(() => {
|
||||
if (this.onShare) {
|
||||
const list = this.selectedItems();
|
||||
if (list.length === 0) {
|
||||
ToastUtils.show('请选择要转发的图片');
|
||||
} else if (list.length > 1) {
|
||||
ToastUtils.show('一次只能转发一张图片');
|
||||
} else {
|
||||
this.onShare(list[0]);
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
Button('保存', { type: ButtonType.Capsule, stateEffect: true })
|
||||
.width(122)
|
||||
.height(40)
|
||||
.linearGradient({
|
||||
colors: [['#F62C6C', 0.0], ['#FC4F54', 1.0]],
|
||||
direction: GradientDirection.Right
|
||||
})
|
||||
.fontColor($r('app.color.color_90ffffff'))
|
||||
.fontSize(15)
|
||||
.margin({ left: 12 })
|
||||
.onClick(() => {
|
||||
if (this.onSave) {
|
||||
const list = this.selectedItems();
|
||||
if (list.length === 0) {
|
||||
ToastUtils.show('请选择要保存的图片');
|
||||
} else {
|
||||
this.onSave(list);
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
.backgroundColor($r('app.color.color_222222'))
|
||||
.padding({
|
||||
left: 16,
|
||||
top: 10,
|
||||
right: 16,
|
||||
bottom: 30
|
||||
})
|
||||
.visibility(this.mediaList.length > 0 ? Visibility.Visible : Visibility.None)
|
||||
}
|
||||
|
||||
EmptyView({
|
||||
status: this.mediaList.length > 0 ? PageStatus.GONE : PageStatus.NO_DATA,
|
||||
noDataImage: $r('app.media.ic_empty_image'),
|
||||
noDataText: '暂无图片'
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
import { PasteboardUtil } from '@pura/harmony-utils';
|
||||
import { TextMaterial } from '../../../../../entity/MaterialInfoEntity';
|
||||
import { ToastUtils } from '../../../../../utils/ToastUtils';
|
||||
import { EmptyView, PageStatus } from '../../../../../view/EmptyView';
|
||||
import { TextMaterialItemView } from '../../../../../view/MaterialItemView';
|
||||
|
||||
@ComponentV2
|
||||
export struct TextMaterialPage {
|
||||
@Param mediaList: Array<TextMaterial> = [];
|
||||
|
||||
@Local isCheckAll: boolean = false
|
||||
|
||||
selectedItems(): Array<TextMaterial> {
|
||||
const list = new Array<TextMaterial>();
|
||||
this.mediaList.forEach((item) => {
|
||||
if (item.isChecked) {
|
||||
list.push(item);
|
||||
}
|
||||
})
|
||||
return list;
|
||||
}
|
||||
|
||||
build() {
|
||||
Stack() {
|
||||
Column() {
|
||||
List({ space: 10 }) {
|
||||
ForEach(this.mediaList, (item: TextMaterial, index) => {
|
||||
ListItem() {
|
||||
TextMaterialItemView({ media: item })
|
||||
}
|
||||
.onClick(() => {
|
||||
item.isChecked = !item.isChecked;
|
||||
this.isCheckAll = this.mediaList.every(item => item.isChecked)
|
||||
})
|
||||
})
|
||||
}
|
||||
.width('auto')
|
||||
.layoutWeight(1)
|
||||
.scrollBar(BarState.Off)
|
||||
.margin({ left: 16, right: 16, bottom: 15 })
|
||||
|
||||
Row() {
|
||||
Row() {
|
||||
Image(this.mediaList.every(item => item.isChecked) ? $r('app.media.ic_check_true') : $r('app.media.ic_check_false')).width(18).height(18)
|
||||
Text('全选').fontColor($r('app.color.color_90ffffff')).fontSize(16).margin({ left: 7 })
|
||||
}
|
||||
.onClick(() => {
|
||||
this.isCheckAll = !this.isCheckAll;
|
||||
this.mediaList.forEach((item) => {
|
||||
item.isChecked = this.isCheckAll;
|
||||
})
|
||||
})
|
||||
|
||||
Button('复制文本', { type: ButtonType.Capsule, stateEffect: true })
|
||||
.layoutWeight(1)
|
||||
.height(40)
|
||||
.linearGradient({
|
||||
colors: [['#F62C6C', 0.0], ['#FC4F54', 1.0]],
|
||||
direction: GradientDirection.Right
|
||||
})
|
||||
.fontColor($r('app.color.color_90ffffff'))
|
||||
.fontSize(15)
|
||||
.margin({ left: 27 })
|
||||
.onClick(() => {
|
||||
const list = this.selectedItems();
|
||||
if (list.length === 0) {
|
||||
ToastUtils.show('请选择要复制的文本');
|
||||
} else {
|
||||
list.forEach((item) => {
|
||||
PasteboardUtil.setDataTextSync(item.title);
|
||||
})
|
||||
ToastUtils.show('已复制');
|
||||
}
|
||||
})
|
||||
}
|
||||
.backgroundColor($r('app.color.color_222222'))
|
||||
.padding({
|
||||
left: 16,
|
||||
top: 10,
|
||||
right: 16,
|
||||
bottom: 30
|
||||
})
|
||||
.visibility(this.mediaList.length > 0 ? Visibility.Visible : Visibility.None)
|
||||
}
|
||||
|
||||
EmptyView({
|
||||
status: this.mediaList.length > 0 ? PageStatus.GONE : PageStatus.NO_DATA,
|
||||
noDataImage: $r('app.media.ic_empty_text'),
|
||||
noDataText: '暂无文本'
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,117 @@
|
|||
import { VideoMaterial } from '../../../../../entity/MaterialInfoEntity';
|
||||
import { ToastUtils } from '../../../../../utils/ToastUtils';
|
||||
import { EmptyView, PageStatus } from '../../../../../view/EmptyView';
|
||||
import { VideoMaterialItemView } from '../../../../../view/MaterialItemView';
|
||||
|
||||
@ComponentV2
|
||||
export struct VideoMaterialPage {
|
||||
@Param mediaList: Array<VideoMaterial> = [];
|
||||
@Param rowCount: number = 1;
|
||||
@Param onShare?: (video: VideoMaterial) => void = undefined
|
||||
@Param onSave?: (list: Array<VideoMaterial>) => void = undefined
|
||||
|
||||
@Local isCheckAll: boolean = false
|
||||
|
||||
selectedItems(): Array<VideoMaterial> {
|
||||
const list = new Array<VideoMaterial>();
|
||||
this.mediaList.forEach((item) => {
|
||||
if (item.isChecked) {
|
||||
list.push(item);
|
||||
}
|
||||
})
|
||||
return list;
|
||||
}
|
||||
|
||||
build() {
|
||||
Stack() {
|
||||
Column() {
|
||||
Grid() {
|
||||
ForEach(this.mediaList, (item: VideoMaterial, index) => {
|
||||
GridItem() {
|
||||
VideoMaterialItemView({ media: item, rowCount: this.rowCount })
|
||||
}
|
||||
.onClick(() => {
|
||||
item.isChecked = !item.isChecked;
|
||||
this.isCheckAll = this.mediaList.every(item => item.isChecked)
|
||||
})
|
||||
})
|
||||
}
|
||||
.scrollBar(BarState.Off)
|
||||
.columnsTemplate(this.rowCount === 1 ? '1fr' : this.rowCount === 2 ? '1fr 1fr' : '1fr 1fr 1fr')
|
||||
.rowsGap(10)
|
||||
.columnsGap(10)
|
||||
.margin({ left: 16, right: 16, bottom: 15 })
|
||||
.layoutWeight(1)
|
||||
|
||||
Row() {
|
||||
Row() {
|
||||
Image(this.mediaList.every(item => item.isChecked) ? $r('app.media.ic_check_true') : $r('app.media.ic_check_false')).width(18).height(18)
|
||||
Text('全选').fontColor($r('app.color.color_90ffffff')).fontSize(16).margin({ left: 7 })
|
||||
}
|
||||
.onClick(() => {
|
||||
this.isCheckAll = !this.isCheckAll;
|
||||
this.mediaList.forEach((item) => {
|
||||
item.isChecked = this.isCheckAll;
|
||||
})
|
||||
})
|
||||
|
||||
Blank().layoutWeight(1)
|
||||
|
||||
Button('转发', { type: ButtonType.Capsule, stateEffect: true })
|
||||
.width(122)
|
||||
.height(40)
|
||||
.backgroundColor($r('app.color.color_333333'))
|
||||
.fontColor($r('app.color.color_50ffffff'))
|
||||
.fontSize(15)
|
||||
.onClick(() => {
|
||||
if (this.onShare) {
|
||||
const list = this.selectedItems();
|
||||
if (list.length === 0) {
|
||||
ToastUtils.show('请选择要转发的视频');
|
||||
} else if (list.length > 1) {
|
||||
ToastUtils.show('一次只能转发一个视频');
|
||||
} else {
|
||||
this.onShare(list[0]);
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
Button('保存', { type: ButtonType.Capsule, stateEffect: true })
|
||||
.width(122)
|
||||
.height(40)
|
||||
.linearGradient({
|
||||
colors: [['#F62C6C', 0.0], ['#FC4F54', 1.0]],
|
||||
direction: GradientDirection.Right
|
||||
})
|
||||
.fontColor($r('app.color.color_90ffffff'))
|
||||
.fontSize(15)
|
||||
.margin({ left: 12 })
|
||||
.onClick(() => {
|
||||
if (this.onSave) {
|
||||
const list = this.selectedItems();
|
||||
if (list.length === 0) {
|
||||
ToastUtils.show('请选择要保存的视频');
|
||||
} else {
|
||||
this.onSave(list);
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
.backgroundColor($r('app.color.color_222222'))
|
||||
.padding({
|
||||
left: 16,
|
||||
top: 10,
|
||||
right: 16,
|
||||
bottom: 30
|
||||
})
|
||||
.visibility(this.mediaList.length > 0 ? Visibility.Visible : Visibility.None)
|
||||
}
|
||||
|
||||
EmptyView({
|
||||
status: this.mediaList.length > 0 ? PageStatus.GONE : PageStatus.NO_DATA,
|
||||
noDataImage: $r('app.media.ic_empty_video'),
|
||||
noDataText: '暂无视频'
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,228 @@
|
|||
import { MaterialEntity } from '../../../../entity/MaterialEntity';
|
||||
import { TitleBar } from '../../../../view/TitleBar';
|
||||
import { router, window } from '@kit.ArkUI';
|
||||
import { ImagePreview } from '@rv/image-preview';
|
||||
import { AppUtil, DisplayUtil, FileUtil, NumberUtil } from '@pura/harmony-utils';
|
||||
import { media } from '@kit.MediaKit';
|
||||
import { BusinessError, request, systemDateTime } from '@kit.BasicServicesKit';
|
||||
import { ToastUtils } from '../../../../utils/ToastUtils';
|
||||
import { SaveUtils } from '../../../../utils/SaveUtils';
|
||||
import { AuthViewModel } from '../../../../viewModel/AuthViewModel';
|
||||
import { VipPermissionEntity } from '../../../../entity/VipPermissionEntity';
|
||||
import { LoginManager } from '../../../../manager/LoginGlobalManager';
|
||||
import { RouterUrls } from '../../../../common/RouterUrls';
|
||||
import { EventReportGlobalManager } from '../../../../manager/EventReportGlobalManager';
|
||||
import { EventConstants } from '../../../../common/EventConstants';
|
||||
import { LoadingDialog } from '../../../../dialog/LoadingDialog';
|
||||
import { DownloadDialog, DownloadStatus } from '../../../../dialog/DownloadDialog';
|
||||
|
||||
@Entry
|
||||
@ComponentV2
|
||||
struct MaterialDetailPage {
|
||||
windowStage: window.WindowStage = AppStorage.get("windowStage") as window.WindowStage;
|
||||
|
||||
@Local material?: MaterialEntity;
|
||||
@Local tagArray: Array<string> = []
|
||||
|
||||
private viewModel: AuthViewModel = new AuthViewModel(this.getUIContext())
|
||||
private imageSize: media.PixelMapParams = {}
|
||||
|
||||
@Monitor('viewModel.permissionInfo')
|
||||
onPermissionInfoChange(monitor: IMonitor) {
|
||||
const info = monitor.value()?.now as VipPermissionEntity;
|
||||
if (info.auth) {
|
||||
if (!LoginManager.isLogin()) {
|
||||
this.getUIContext().getRouter().pushUrl({url: RouterUrls.LOGIN_PAGE, params: {from: 1}}, router.RouterMode.Single)
|
||||
return;
|
||||
}
|
||||
this.download()
|
||||
} else {
|
||||
if (!info.auth_ad) {
|
||||
this.getUIContext().getRouter().pushUrl({url: RouterUrls.VIP_PAGE, params: {origin: 'download_material'}})
|
||||
EventReportGlobalManager.eventReport(EventConstants.JUMP_TO_MEMBER_RECHARGE, 'download_material')
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Monitor('viewModel.errorCode')
|
||||
onErrorCodeChange(monitor: IMonitor) {
|
||||
const errorCode = monitor.value()?.now as number;
|
||||
if (errorCode === 12002 || errorCode === 12003 || errorCode === 12004) {
|
||||
this.getUIContext().getRouter().pushUrl({url: RouterUrls.RECHARGE_DIAMOND_PAGE});
|
||||
EventReportGlobalManager.eventReport(EventConstants.JUMP_TO_RECHARGE_DIAMOND, 'download_material')
|
||||
ToastUtils.show('M币已用完')
|
||||
}
|
||||
}
|
||||
|
||||
aboutToAppear(): void {
|
||||
this.windowStage.getMainWindowSync().setWindowSystemBarProperties({
|
||||
statusBarColor: '#00000000',
|
||||
statusBarContentColor: '#FFFFFF'
|
||||
});
|
||||
this.initParams()
|
||||
}
|
||||
|
||||
aboutToDisappear(): void {
|
||||
this.windowStage.getMainWindowSync().setWindowSystemBarProperties({
|
||||
statusBarColor: '#00000000',
|
||||
statusBarContentColor: '#000000'
|
||||
});
|
||||
}
|
||||
|
||||
initParams() {
|
||||
const params = this.getUIContext().getRouter().getParams() as Record<string, Object>;
|
||||
if (params) {
|
||||
this.material = params.material as MaterialEntity
|
||||
if (this.material.pic_size) {
|
||||
const size = this.material.pic_size.split(':')
|
||||
if (size.length === 2) {
|
||||
this.imageSize.width = NumberUtil.toNumber(size[0])
|
||||
this.imageSize.height = NumberUtil.toNumber(size[1])
|
||||
}
|
||||
}
|
||||
this.tagArray = this.material.tags
|
||||
}
|
||||
}
|
||||
|
||||
download() {
|
||||
LoadingDialog.show(this.getUIContext())
|
||||
let outputPath = FileUtil.getCacheDirPath() + FileUtil.separator + `kcsp_${systemDateTime.getTime()}.jpeg`
|
||||
let config: request.agent.Config = {
|
||||
action: request.agent.Action.DOWNLOAD,
|
||||
url: this.material!!.pic!!.url,
|
||||
overwrite: true,
|
||||
saveas: outputPath,
|
||||
gauge: true,
|
||||
priority:0
|
||||
}
|
||||
request.agent.create(AppUtil.getApplicationContext(), config)
|
||||
.then((task: request.agent.Task) => {
|
||||
task.start((err: BusinessError) => {
|
||||
if (err) {
|
||||
console.error(`下载失败: ${err.message}`);
|
||||
ToastUtils.show(err.message);
|
||||
return;
|
||||
}
|
||||
LoadingDialog.dismiss()
|
||||
});
|
||||
task.on('completed',() => {
|
||||
LoadingDialog.dismiss()
|
||||
if (FileUtil.accessSync(outputPath)) {
|
||||
SaveUtils.saveImageVideoToAlbumDialog([outputPath])
|
||||
.then((saved) => {
|
||||
if (saved) {
|
||||
this.showDownloadDialog()
|
||||
} else {
|
||||
ToastUtils.show('保存失败')
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
ToastUtils.show('保存失败')
|
||||
})
|
||||
} else {
|
||||
ToastUtils.show('下载失败: 文件不存在');
|
||||
}
|
||||
request.agent.remove(task.tid);
|
||||
})
|
||||
task.on('failed', () => {
|
||||
LoadingDialog.dismiss()
|
||||
ToastUtils.show('下载失败,请检查网络后重试');
|
||||
request.agent.remove(task.tid);
|
||||
});
|
||||
})
|
||||
.catch((err: BusinessError) => {
|
||||
if (err) {
|
||||
console.error(`下载失败: ${err.message}`);
|
||||
ToastUtils.show(err.message);
|
||||
}
|
||||
LoadingDialog.dismiss()
|
||||
})
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
build() {
|
||||
Column() {
|
||||
TitleBar({title: this.material?.title, isDark: true})
|
||||
|
||||
Stack() {
|
||||
ImagePreview() {
|
||||
RelativeContainer() {
|
||||
Image(this.material?.pic?.url)
|
||||
.width("100%")
|
||||
.height(px2vp(Math.round(this.imageSize.height!! * DisplayUtil.getWidth() / this.imageSize.width!!)))
|
||||
.sourceSize({
|
||||
width: px2vp(DisplayUtil.getWidth()),
|
||||
height: px2vp(Math.round(this.imageSize.height!! * DisplayUtil.getWidth() / this.imageSize.width!!))
|
||||
})
|
||||
.alignRules({
|
||||
top: {anchor: '__container__', align: VerticalAlign.Top},
|
||||
bottom: {anchor: '__container__', align: VerticalAlign.Bottom}
|
||||
})
|
||||
.draggable(false)
|
||||
.id('image')
|
||||
|
||||
List({space: 4}){
|
||||
ForEach(this.tagArray, (item: string) => {
|
||||
ListItem() {
|
||||
Text(item).fontColor(Color.White).fontSize(10)
|
||||
.borderRadius(2)
|
||||
.backgroundColor('#80000000')
|
||||
.padding({left: 4, top: 1, right: 4, bottom: 1})
|
||||
}
|
||||
})
|
||||
}
|
||||
.listDirection(Axis.Horizontal)
|
||||
.alignRules({
|
||||
top: {anchor: 'image', align: VerticalAlign.Top},
|
||||
right: {anchor: 'image', align: HorizontalAlign.End}
|
||||
})
|
||||
.margin({top: 12, right: 12})
|
||||
}
|
||||
.height('auto')
|
||||
}
|
||||
}
|
||||
.width('100%')
|
||||
.layoutWeight(1)
|
||||
|
||||
Stack() {
|
||||
Button({ type: ButtonType.Capsule, stateEffect: true }) {
|
||||
Row() {
|
||||
Image($r('app.media.ic_download1')).width(22).height(22)
|
||||
Text('下载').fontColor(Color.White).fontSize(15).fontWeight(FontWeight.Medium)
|
||||
}
|
||||
}
|
||||
.width('100%')
|
||||
.height(46)
|
||||
.backgroundColor($r('app.color.color_466afd'))
|
||||
.onClick(() => {
|
||||
if (this.material?.pic?.url) {
|
||||
this.viewModel.checkVip()
|
||||
} else {
|
||||
ToastUtils.show('链接不存在')
|
||||
}
|
||||
})
|
||||
}
|
||||
.backgroundColor($r('app.color.color_1b1b1b'))
|
||||
.padding({left: 16, top: 9, right: 16, bottom: 30})
|
||||
}
|
||||
.width('100%')
|
||||
.height('100%')
|
||||
.backgroundColor('#0F0E13')
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,329 @@
|
|||
import { PhotoHelper, PickerUtil } 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, picker } 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 { TipDialog } from '../../../../dialog/TipDialog'
|
||||
import { avSessionManager } from '../../../../manager/AVSessionManager'
|
||||
|
||||
@Entry
|
||||
@ComponentV2
|
||||
struct AddAudioPage {
|
||||
private controller: VideoController = new VideoController()
|
||||
@Local videoUri?: string
|
||||
@Local audioUri?: string
|
||||
@Local currentTime: number = 0
|
||||
@Local durationTime: number = 0
|
||||
@Local isPlaying: boolean = false
|
||||
@Local isSuccess: boolean = false
|
||||
|
||||
mirrorVideo() {
|
||||
LoadingDialog.show(this.getUIContext())
|
||||
this.isSuccess = false
|
||||
let cacheVideoPath = FileUtil.getCacheDirPath() + FileUtil.separator + `cache_${systemDateTime.getTime()}.mp4`
|
||||
if (FileUtil.accessSync(cacheVideoPath)) {
|
||||
FileUtil.unlinkSync(cacheVideoPath)
|
||||
}
|
||||
let videoFile = FileUtil.openSync(this.videoUri!!, fileIo.OpenMode.READ_ONLY)
|
||||
// 复制视频文件到缓存目录下
|
||||
FileUtil.copyFileSync(videoFile.fd, cacheVideoPath)
|
||||
|
||||
let cacheAudioPath = FileUtil.getCacheDirPath() + FileUtil.separator + `cache_${systemDateTime.getTime()}.mp3`
|
||||
if (FileUtil.accessSync(cacheAudioPath)) {
|
||||
FileUtil.unlinkSync(cacheAudioPath)
|
||||
}
|
||||
let audioFile = FileUtil.openSync(this.audioUri!!, fileIo.OpenMode.READ_ONLY)
|
||||
// 复制音频文件到缓存目录下
|
||||
FileUtil.copyFileSync(audioFile.fd, cacheAudioPath)
|
||||
|
||||
let outputPath = FileUtil.getCacheDirPath() + FileUtil.separator + `kcsp_${systemDateTime.getTime()}.mp4`
|
||||
let cmd = `ffmpeg -i ${cacheVideoPath} -stream_loop -1 -i ${cacheAudioPath} -c:v copy -c:a aac -shortest -map 0:v -map 1:a ${outputPath}`
|
||||
MP4Parser.ffmpegCmd(cmd, {
|
||||
callBackResult: (code: number) => {
|
||||
if (code === 0) {
|
||||
this.videoUri = 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.videoUri = uris[0]
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
selectAudio() {
|
||||
/*PickerUtil.selectAudio({maxSelectNumber: 1})
|
||||
.then((uris) => {
|
||||
if (uris.length != 0) {
|
||||
this.audioUri = uris[0]
|
||||
}
|
||||
})*/
|
||||
PickerUtil.selectDocument({maxSelectNumber: 1, fileSuffixFilters: ['.mp3']})
|
||||
.then((uris) => {
|
||||
if (uris.length != 0) {
|
||||
this.audioUri = uris[0]
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
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: '加音乐' })
|
||||
|
||||
Column() {
|
||||
Row() {
|
||||
Text('上传视频').fontColor($r('app.color.color_90ffffff')).fontSize(16).fontWeight(FontWeight.Medium)
|
||||
Text('(仅支持mp4格式)').fontColor($r('app.color.color_50ffffff')).fontSize(12)
|
||||
}.alignSelf(ItemAlign.Start)
|
||||
|
||||
RelativeContainer() {
|
||||
Stack() {
|
||||
Image($r('app.media.ic_add_video')).width(44).height(44)
|
||||
}
|
||||
.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)
|
||||
.margin({ top: 12 })
|
||||
.borderRadius(8)
|
||||
.backgroundColor($r('app.color.color_222222'))
|
||||
}.margin({ left: 16, top: 16, right: 16 })
|
||||
.visibility(this.videoUri ? Visibility.None : Visibility.Visible)
|
||||
|
||||
Column() {
|
||||
RelativeContainer() {
|
||||
Video({
|
||||
src: this.videoUri, // 设置视频源
|
||||
controller: this.controller, //设置视频控制器,可以控制视频的播放状态
|
||||
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) => {
|
||||
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: 30, right: 30 })
|
||||
.alignRules({
|
||||
bottom: { anchor: '__container__', align: VerticalAlign.Bottom }
|
||||
})
|
||||
}
|
||||
.layoutWeight(1)
|
||||
|
||||
Image($r('app.media.ic_add_audio')).width(50).height(50).margin({top: 20})
|
||||
.onClick(() => {
|
||||
this.selectAudio()
|
||||
})
|
||||
Text('音频').fontColor($r('app.color.color_90ffffff')).fontSize(14).margin({top: 10})
|
||||
|
||||
Row() {
|
||||
Text(this.isSuccess ? '重新上传' : '取消').fontColor($r('app.color.color_90ffffff')).fontSize(17).margin({ left: 16 })
|
||||
.onClick(() => {
|
||||
this.controller.stop()
|
||||
if (this.isSuccess) {
|
||||
this.selectVideo()
|
||||
} else {
|
||||
this.getUIContext().getRouter().back()
|
||||
}
|
||||
})
|
||||
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.videoUri!!])
|
||||
.then((saved) => {
|
||||
if (saved) {
|
||||
this.videoUri = undefined
|
||||
this.showDownloadDialog()
|
||||
} else {
|
||||
ToastUtils.show('保存失败')
|
||||
}
|
||||
})
|
||||
.catch((e: BusinessError) => {
|
||||
ToastUtils.show('保存失败:' + e.message)
|
||||
})
|
||||
|
||||
} else {
|
||||
if (this.audioUri) {
|
||||
this.mirrorVideo()
|
||||
} else {
|
||||
ToastUtils.show('请上传音频')
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
.margin({ top: 50, bottom: 30 })
|
||||
}
|
||||
.layoutWeight(1)
|
||||
.visibility(this.videoUri ? Visibility.Visible : Visibility.None)
|
||||
}
|
||||
.width('100%')
|
||||
.height('100%')
|
||||
.backgroundColor($r('app.color.window_background'))
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,425 @@
|
|||
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'
|
||||
|
||||
@Entry
|
||||
@ComponentV2
|
||||
struct AddWaterMarkerPage {
|
||||
@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 showWaterMaker: boolean = false
|
||||
@Local textContent: string = ''
|
||||
@Local imagePath: string = ''
|
||||
|
||||
private controller: VideoController = new VideoController()
|
||||
private videoSize: media.PixelMapParams = { width: 0, height: 0 }
|
||||
private rect: RectPosition = { x: 0, y: 0, width: 0, height: 0 }
|
||||
|
||||
addWaterMarker() {
|
||||
LoadingDialog.show(this.getUIContext())
|
||||
this.isSuccess = false
|
||||
let cacheVideoPath = FileUtil.getCacheDirPath() + FileUtil.separator + `kcsp_${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 imageX = (vp2px(this.rect.x) * this.videoSize.width!!) / this.playerSize.width!!
|
||||
let imageY = (vp2px(this.rect.y) * this.videoSize.height!!) / this.playerSize.height!!
|
||||
|
||||
let imageWidth = (vp2px(this.rect.width * this.videoSize.width!!) / this.playerSize.width!!)
|
||||
let imageHeight = (vp2px(this.rect.height * this.videoSize.height!!) / this.playerSize.height!!)
|
||||
|
||||
this.getUIContext().getComponentSnapshot().get(StrUtil.isNotEmpty(this.textContent) ? 'textWaterMarker' : 'imageWaterMarker')
|
||||
.then(async (image: image.PixelMap) => {
|
||||
let imagePath = await ImageUtil.savePixelMap(image, FileUtil.getCacheDirPath(), `cache_${systemDateTime.getTime()}.png`)
|
||||
let outputPath = FileUtil.getCacheDirPath() + FileUtil.separator + `kcsp_${systemDateTime.getTime()}.mp4`
|
||||
let cmd = `ffmpeg -i ${cacheVideoPath} -i ${imagePath} -filter_complex [1:v]scale=${Math.round(imageWidth)}:${Math.round(imageHeight)}[wm];[0:v][wm]overlay=${imageX}:${imageY} -c:v h264 -pix_fmt yuv420p -y ${outputPath}`
|
||||
MP4Parser.ffmpegCmd(cmd, {
|
||||
callBackResult: (code: number) => {
|
||||
if (code === 0) {
|
||||
this.uri = FileUtil.getUriFromPath(outputPath)
|
||||
this.isSuccess = true
|
||||
this.isPlaying = false
|
||||
ToastUtils.show('处理成功')
|
||||
} else {
|
||||
ToastUtils.show('处理失败')
|
||||
}
|
||||
LoadingDialog.dismiss()
|
||||
}
|
||||
})
|
||||
})
|
||||
.catch((error: BusinessError) => {
|
||||
ToastUtils.show('处理失败:' + error.message)
|
||||
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.showWaterMaker = false
|
||||
this.textContent = ''
|
||||
this.imagePath = ''
|
||||
|
||||
MediaUtils.getVideoSize(this.uri)
|
||||
.then((size) => {
|
||||
this.videoSize = size
|
||||
if (size.width && size.height) {
|
||||
const ratio = (DisplayUtil.getWidth() - 180) / 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: '加水印' })
|
||||
|
||||
Column() {
|
||||
Row() {
|
||||
Text('上传视频').fontColor($r('app.color.color_90ffffff')).fontSize(16).fontWeight(FontWeight.Medium)
|
||||
Text('(仅支持mp4格式)').fontColor($r('app.color.color_50ffffff')).fontSize(12)
|
||||
}.alignSelf(ItemAlign.Start)
|
||||
|
||||
RelativeContainer() {
|
||||
Stack() {
|
||||
Image($r('app.media.ic_add_video')).width(44).height(44)
|
||||
}
|
||||
.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)
|
||||
.margin({ top: 12 })
|
||||
.borderRadius(8)
|
||||
.backgroundColor($r('app.color.color_222222'))
|
||||
}.margin({ left: 16, top: 16, right: 16 })
|
||||
.visibility(this.uri ? Visibility.None : Visibility.Visible)
|
||||
|
||||
Column() {
|
||||
RelativeContainer() {
|
||||
Video({
|
||||
src: this.uri, // 设置视频源
|
||||
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.showWaterMaker && this.uri && !this.isSuccess) {
|
||||
WaterMarkerView({
|
||||
content: this.textContent,
|
||||
imagePath: this.imagePath,
|
||||
onRectChange: (rect) => {
|
||||
this.rect = rect
|
||||
},
|
||||
onClose: () => {
|
||||
this.showWaterMaker = false
|
||||
this.textContent = ''
|
||||
this.imagePath = ''
|
||||
}
|
||||
})
|
||||
.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)
|
||||
|
||||
Row() {
|
||||
Column(){
|
||||
Image($r('app.media.ic_text_water_marker')).width(50).height(50)
|
||||
Text('文字').fontColor($r('app.color.color_90ffffff')).fontSize(14).margin({ top: 8 })
|
||||
}
|
||||
.onClick(() => {
|
||||
if (!this.showWaterMaker) {
|
||||
this.controller.stop()
|
||||
EditTextDialog.show(this.getUIContext(), {title: '添加水印', hintText: '请输入文字', confirm: (text) => {
|
||||
this.textContent = text
|
||||
this.showWaterMaker = true
|
||||
}})
|
||||
}
|
||||
})
|
||||
Column(){
|
||||
Image($r('app.media.ic_image_water_marker')).width(50).height(50)
|
||||
Text('图片').fontColor($r('app.color.color_90ffffff')).fontSize(14).margin({ top: 8 })
|
||||
}
|
||||
.margin({ left: 50 })
|
||||
.onClick(() => {
|
||||
if (!this.showWaterMaker) {
|
||||
this.controller.stop()
|
||||
PhotoHelper.selectEasy({
|
||||
MIMEType: photoAccessHelper.PhotoViewMIMETypes.IMAGE_TYPE,
|
||||
maxSelectNumber: 1,
|
||||
isPhotoTakingSupported: false,
|
||||
isEditSupported: false,
|
||||
isOriginalSupported: false
|
||||
})
|
||||
.then((uris) => {
|
||||
if (uris.length != 0) {
|
||||
this.isSuccess = false
|
||||
this.imagePath = uris[0]
|
||||
this.showWaterMaker = true
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
.margin({ top: 20 })
|
||||
|
||||
Row() {
|
||||
Text(this.isSuccess ? '重新上传' : '取消').fontColor($r('app.color.color_90ffffff'))
|
||||
.fontSize(17)
|
||||
.margin({ left: 16 })
|
||||
.onClick(() => {
|
||||
this.controller.stop()
|
||||
if (this.isSuccess) {
|
||||
this.selectVideo()
|
||||
} else {
|
||||
this.getUIContext().getRouter().back()
|
||||
}
|
||||
})
|
||||
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)
|
||||
.visibility(this.uri ? Visibility.Visible : Visibility.None)
|
||||
}
|
||||
.width('100%')
|
||||
.height('100%')
|
||||
.backgroundColor($r('app.color.window_background'))
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,467 @@
|
|||
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 } 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 { RectCropView, 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 { avSessionManager } from '../../../../manager/AVSessionManager'
|
||||
|
||||
@Entry
|
||||
@ComponentV2
|
||||
struct ClipVideoPage {
|
||||
@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 currentIndex: number = 0
|
||||
|
||||
private controller: VideoController = new VideoController()
|
||||
private rectArray : Array<string> = ['自由', '1:1', '4:3', '3:4', '16:9', '9:16']
|
||||
private videoSize: media.PixelMapParams = { width: 0, height: 0 }
|
||||
private rect: RectPosition = { x: 0, y: 0, width: 0, height: 0 }
|
||||
|
||||
clipVideo() {
|
||||
LoadingDialog.show(this.getUIContext())
|
||||
this.isSuccess = false
|
||||
let cacheVideoPath = FileUtil.getCacheDirPath() + FileUtil.separator + `kcsp_${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 clipWidth: number = 0
|
||||
let clipHeight: number = 0
|
||||
if (this.currentIndex === 0) {
|
||||
clipWidth = (vp2px(this.rect.width * this.videoSize.width!!) / this.playerSize.width!!)
|
||||
clipHeight = (vp2px(this.rect.height * this.videoSize.height!!) / this.playerSize.height!!)
|
||||
} else {
|
||||
const ratio = (DisplayUtil.getWidth() - 180) / this.videoSize.width!!
|
||||
let originPlayerSize: media.PixelMapParams = {width: Math.ceil(this.videoSize.width!! * ratio), height: Math.ceil(this.videoSize.height!! * ratio)}
|
||||
clipWidth = (this.playerSize.width!! * this.videoSize.width!!) / originPlayerSize.width!!
|
||||
clipHeight = (this.playerSize.height!! * this.videoSize.height!!) / originPlayerSize.height!!
|
||||
}
|
||||
|
||||
let clipX: number = 0
|
||||
let clipY: number = 0
|
||||
if (this.currentIndex === 0) {
|
||||
clipX = (vp2px(this.rect.x) * this.videoSize.width!!) / this.playerSize.width!!
|
||||
clipY = (vp2px(this.rect.y) * this.videoSize.width!!) / this.playerSize.height!!
|
||||
} else {
|
||||
const ratio = (DisplayUtil.getWidth() - 180) / this.videoSize.width!!
|
||||
let originPlayerSize: media.PixelMapParams = {width: Math.ceil(this.videoSize.width!! * ratio), height: Math.ceil(this.videoSize.height!! * ratio)}
|
||||
clipX = clipWidth === originPlayerSize.width ? 0 : (originPlayerSize.width!! - this.playerSize.width!!) / 2 * (this.videoSize.width!!) / originPlayerSize.width!!
|
||||
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 cmd = `ffmpeg -i ${cacheVideoPath} -vf \"crop=${Math.ceil(clipWidth)}:${Math.ceil(clipHeight)}:${Math.ceil(clipX)}:${Math.ceil(clipY)}\" -c:v h264 -pix_fmt yuv420p -y ${outputPath}`
|
||||
MP4Parser.ffmpegCmd(cmd, {
|
||||
callBackResult: (code: number) => {
|
||||
if (code === 0) {
|
||||
this.uri = FileUtil.getUriFromPath(outputPath)
|
||||
MediaUtils.getVideoSize(this.uri)
|
||||
.then((size) => {
|
||||
this.videoSize = size
|
||||
if (size.width && size.height) {
|
||||
const ratio = (DisplayUtil.getWidth() - 180) / size.width
|
||||
this.playerSize = {width: Math.ceil(size.width * ratio), height: Math.ceil(size.height * ratio)}
|
||||
}
|
||||
})
|
||||
this.isSuccess = true
|
||||
this.isPlaying = false
|
||||
ToastUtils.show('处理成功')
|
||||
} else {
|
||||
ToastUtils.show('处理失败')
|
||||
}
|
||||
LoadingDialog.dismiss()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
setVideoRatio() {
|
||||
if (this.videoSize.width && this.videoSize.height) {
|
||||
const ratio = (DisplayUtil.getWidth() - 180) / this.videoSize.width
|
||||
let originPlayerSize: media.PixelMapParams = {width: Math.ceil(this.videoSize.width * ratio), height: Math.ceil(this.videoSize.height * ratio)}
|
||||
|
||||
if (originPlayerSize.width && originPlayerSize.height) {
|
||||
switch (this.currentIndex) {
|
||||
case 0: {
|
||||
this.playerSize = originPlayerSize
|
||||
break
|
||||
}
|
||||
|
||||
case 1: {
|
||||
if (originPlayerSize.width >= originPlayerSize.height) {
|
||||
this.playerSize = {width: originPlayerSize.height, height: originPlayerSize.height}
|
||||
} else {
|
||||
this.playerSize = {width: originPlayerSize.width, height: originPlayerSize.width}
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
case 2: {
|
||||
if (originPlayerSize.width / originPlayerSize.height >= 4 / 3) {
|
||||
this.playerSize = {width: Math.ceil((originPlayerSize.height!!) / 3 * 4), height: originPlayerSize.height}
|
||||
} else {
|
||||
this.playerSize = {width: originPlayerSize.width, height: Math.ceil((originPlayerSize.width!!) / 4 * 3)}
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
case 3: {
|
||||
if (originPlayerSize.width / originPlayerSize.height <= 3 / 4) {
|
||||
this.playerSize = {width: originPlayerSize.width, height: Math.ceil((originPlayerSize.width!!) / 3 * 4)}
|
||||
} else {
|
||||
this.playerSize = {width: Math.ceil((originPlayerSize.height!!) / 4 * 3), height: originPlayerSize.height}
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
case 4: {
|
||||
if (originPlayerSize.width / originPlayerSize.height >= 16 / 9) {
|
||||
this.playerSize = {width: Math.ceil((originPlayerSize.height!!) / 9 * 16), height: originPlayerSize.height}
|
||||
} else {
|
||||
this.playerSize = {width: originPlayerSize.width, height: Math.ceil((originPlayerSize.width!!) / 16 * 9)}
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
case 5: {
|
||||
if (originPlayerSize.width / originPlayerSize.height <= 9 / 16) {
|
||||
this.playerSize = {width: originPlayerSize.width, height: Math.ceil((originPlayerSize.width!!) / 9 * 16)}
|
||||
} else {
|
||||
this.playerSize = {width: Math.ceil((originPlayerSize.height!!) / 16 * 9), height: originPlayerSize.height}
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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.currentIndex = 0
|
||||
|
||||
MediaUtils.getVideoSize(this.uri)
|
||||
.then((size) => {
|
||||
this.videoSize = size
|
||||
if (size.width && size.height) {
|
||||
const ratio = (DisplayUtil.getWidth() - 180) / 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: '视频裁剪' })
|
||||
|
||||
Column() {
|
||||
Row() {
|
||||
Text('上传视频').fontColor($r('app.color.color_90ffffff')).fontSize(16).fontWeight(FontWeight.Medium)
|
||||
Text('(仅支持mp4格式)').fontColor($r('app.color.color_50ffffff')).fontSize(12)
|
||||
}.alignSelf(ItemAlign.Start)
|
||||
|
||||
RelativeContainer() {
|
||||
Stack() {
|
||||
Image($r('app.media.ic_add_video')).width(44).height(44)
|
||||
}
|
||||
.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)
|
||||
.margin({ top: 12 })
|
||||
.borderRadius(8)
|
||||
.backgroundColor($r('app.color.color_222222'))
|
||||
}.margin({ left: 16, top: 16, right: 16 })
|
||||
.visibility(this.uri ? Visibility.None : Visibility.Visible)
|
||||
|
||||
Column() {
|
||||
RelativeContainer() {
|
||||
Video({
|
||||
src: this.uri, // 设置视频源
|
||||
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 }
|
||||
})
|
||||
|
||||
RectCropView({
|
||||
onRectChange: (rect) => {
|
||||
this.rect = rect
|
||||
}
|
||||
})
|
||||
.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 }
|
||||
})
|
||||
.visibility(this.uri && this.currentIndex === 0 && !this.isSuccess ? Visibility.Visible : Visibility.None)
|
||||
}
|
||||
.layoutWeight(1)
|
||||
|
||||
Grid() {
|
||||
ForEach(this.rectArray, (item: string, index) => {
|
||||
GridItem() {
|
||||
Text(item).width(50).height(50)
|
||||
.textAlign(TextAlign.Center)
|
||||
.fontColor(Color.White)
|
||||
.borderRadius(4)
|
||||
.borderWidth(1.5)
|
||||
.borderColor(this.currentIndex === index ? '#D33952' : Color.Transparent)
|
||||
.backgroundColor('#282828')
|
||||
.onClick(() => {
|
||||
this.currentIndex = index
|
||||
this.controller.stop()
|
||||
this.setVideoRatio()
|
||||
})
|
||||
}
|
||||
.width('100%')
|
||||
})
|
||||
}
|
||||
.height(50)
|
||||
.columnsTemplate('1fr 1fr 1fr 1fr 1fr 1fr')
|
||||
.layoutDirection(GridDirection.Row)
|
||||
.visibility(this.uri && !this.isSuccess ? Visibility.Visible : Visibility.None)
|
||||
|
||||
Row() {
|
||||
Text(this.isSuccess ? '重新上传' : '取消').fontColor($r('app.color.color_90ffffff'))
|
||||
.fontSize(17)
|
||||
.margin({ left: 16 })
|
||||
.onClick(() => {
|
||||
this.controller.stop()
|
||||
if (this.isSuccess) {
|
||||
this.selectVideo()
|
||||
} else {
|
||||
this.getUIContext().getRouter().back()
|
||||
}
|
||||
})
|
||||
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 {
|
||||
this.clipVideo()
|
||||
}
|
||||
})
|
||||
}
|
||||
.margin({ top: 20, bottom: 30 })
|
||||
}
|
||||
.layoutWeight(1)
|
||||
.visibility(this.uri ? Visibility.Visible : Visibility.None)
|
||||
}
|
||||
.width('100%')
|
||||
.height('100%')
|
||||
.backgroundColor($r('app.color.window_background'))
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,289 @@
|
|||
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 MD5ResetPage {
|
||||
private controller: VideoController = new VideoController()
|
||||
@Local uri?: string
|
||||
@Local currentTime: number = 0
|
||||
@Local durationTime: number = 0
|
||||
@Local isPlaying: boolean = false
|
||||
@Local isSuccess: boolean = false
|
||||
|
||||
modifyMD5() {
|
||||
LoadingDialog.show(this.getUIContext())
|
||||
this.isSuccess = false
|
||||
let outputPath = FileUtil.getCacheDirPath() + FileUtil.separator + `kcsp_${systemDateTime.getTime()}.mp4`
|
||||
if (FileUtil.accessSync(outputPath)) {
|
||||
FileUtil.unlinkSync(outputPath)
|
||||
}
|
||||
|
||||
let file = FileUtil.openSync(this.uri!!, fileIo.OpenMode.READ_ONLY)
|
||||
// 复制文件到缓存目录下
|
||||
FileUtil.copyFileSync(file.fd, outputPath)
|
||||
|
||||
if (FileUtil.accessSync(outputPath)) {
|
||||
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]
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
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: 'MD5去重' })
|
||||
|
||||
Column() {
|
||||
Row() {
|
||||
Text('上传视频').fontColor($r('app.color.color_90ffffff')).fontSize(16).fontWeight(FontWeight.Medium)
|
||||
Text('(仅支持mp4格式)').fontColor($r('app.color.color_50ffffff')).fontSize(12)
|
||||
}.alignSelf(ItemAlign.Start)
|
||||
|
||||
RelativeContainer() {
|
||||
Stack() {
|
||||
Image($r('app.media.ic_add_video')).width(44).height(44)
|
||||
}
|
||||
.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)
|
||||
.margin({ top: 12 })
|
||||
.borderRadius(8)
|
||||
.backgroundColor($r('app.color.color_222222'))
|
||||
}.margin({ left: 16, top: 16, right: 16 })
|
||||
.visibility(this.uri ? Visibility.None : Visibility.Visible)
|
||||
|
||||
Column() {
|
||||
RelativeContainer() {
|
||||
Video({
|
||||
src: this.uri, // 设置视频源
|
||||
controller: this.controller, //设置视频控制器,可以控制视频的播放状态
|
||||
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) => {
|
||||
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: 30, right: 30 })
|
||||
.alignRules({
|
||||
bottom: { anchor: '__container__', align: VerticalAlign.Bottom }
|
||||
})
|
||||
}
|
||||
.layoutWeight(1)
|
||||
|
||||
Row() {
|
||||
Text(this.isSuccess ? '重新上传' : '取消').fontColor($r('app.color.color_90ffffff')).fontSize(17).margin({ left: 16 })
|
||||
.onClick(() => {
|
||||
this.controller.stop()
|
||||
if (this.isSuccess) {
|
||||
this.selectVideo()
|
||||
} else {
|
||||
this.getUIContext().getRouter().back()
|
||||
}
|
||||
})
|
||||
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 {
|
||||
this.modifyMD5()
|
||||
}
|
||||
})
|
||||
}
|
||||
.margin({ top: 140, bottom: 30 })
|
||||
}
|
||||
.layoutWeight(1)
|
||||
.visibility(this.uri ? Visibility.Visible : Visibility.None)
|
||||
}
|
||||
.width('100%')
|
||||
.height('100%')
|
||||
.backgroundColor($r('app.color.window_background'))
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,295 @@
|
|||
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 { TipDialog } from '../../../../dialog/TipDialog'
|
||||
import { avSessionManager } from '../../../../manager/AVSessionManager'
|
||||
|
||||
@Entry
|
||||
@ComponentV2
|
||||
struct RemoveAudioPage {
|
||||
private controller: VideoController = new VideoController()
|
||||
@Local uri?: string
|
||||
@Local currentTime: number = 0
|
||||
@Local durationTime: number = 0
|
||||
@Local isPlaying: boolean = false
|
||||
@Local isSuccess: boolean = false
|
||||
|
||||
mirrorVideo() {
|
||||
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()}.mp4`
|
||||
let cmd = `ffmpeg -i ${cachePath} -an -c:v copy ${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]
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
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: '去音乐' })
|
||||
|
||||
Column() {
|
||||
Row() {
|
||||
Text('上传视频').fontColor($r('app.color.color_90ffffff')).fontSize(16).fontWeight(FontWeight.Medium)
|
||||
Text('(仅支持mp4格式)').fontColor($r('app.color.color_50ffffff')).fontSize(12)
|
||||
}.alignSelf(ItemAlign.Start)
|
||||
|
||||
RelativeContainer() {
|
||||
Stack() {
|
||||
Image($r('app.media.ic_add_video')).width(44).height(44)
|
||||
}
|
||||
.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)
|
||||
.margin({ top: 12 })
|
||||
.borderRadius(8)
|
||||
.backgroundColor($r('app.color.color_222222'))
|
||||
}.margin({ left: 16, top: 16, right: 16 })
|
||||
.visibility(this.uri ? Visibility.None : Visibility.Visible)
|
||||
|
||||
Column() {
|
||||
RelativeContainer() {
|
||||
Video({
|
||||
src: this.uri, // 设置视频源
|
||||
controller: this.controller, //设置视频控制器,可以控制视频的播放状态
|
||||
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) => {
|
||||
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: 30, right: 30 })
|
||||
.alignRules({
|
||||
bottom: { anchor: '__container__', align: VerticalAlign.Bottom }
|
||||
})
|
||||
}
|
||||
.layoutWeight(1)
|
||||
|
||||
Row() {
|
||||
Text(this.isSuccess ? '重新上传' : '取消').fontColor($r('app.color.color_90ffffff')).fontSize(17).margin({ left: 16 })
|
||||
.onClick(() => {
|
||||
this.controller.stop()
|
||||
if (this.isSuccess) {
|
||||
this.selectVideo()
|
||||
} else {
|
||||
this.getUIContext().getRouter().back()
|
||||
}
|
||||
})
|
||||
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 {
|
||||
this.mirrorVideo()
|
||||
}
|
||||
})
|
||||
}
|
||||
.margin({ top: 140, bottom: 30 })
|
||||
}
|
||||
.layoutWeight(1)
|
||||
.visibility(this.uri ? Visibility.Visible : Visibility.None)
|
||||
}
|
||||
.width('100%')
|
||||
.height('100%')
|
||||
.backgroundColor($r('app.color.window_background'))
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,287 @@
|
|||
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'))
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,321 @@
|
|||
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 { MP4Parser } from '@ohos/mp4parser'
|
||||
import { TipDialog } from '../../../../dialog/TipDialog'
|
||||
import { avSessionManager } from '../../../../manager/AVSessionManager'
|
||||
|
||||
@Entry
|
||||
@ComponentV2
|
||||
struct VideoMirrorPage {
|
||||
private controller: VideoController = new VideoController()
|
||||
@Local uri?: string
|
||||
@Local currentTime: number = 0
|
||||
@Local durationTime: number = 0
|
||||
@Local isPlaying: boolean = false
|
||||
@Local isSuccess: boolean = false
|
||||
|
||||
private orientation: number = 0
|
||||
|
||||
mirrorVideo() {
|
||||
LoadingDialog.show(this.getUIContext())
|
||||
this.isSuccess = false
|
||||
let cacheVideoPath = FileUtil.getCacheDirPath() + FileUtil.separator + `kcsp_${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 outputPath = FileUtil.getCacheDirPath() + FileUtil.separator + `kcsp_${systemDateTime.getTime()}.mp4`
|
||||
let cmd = `ffmpeg -i ${cacheVideoPath} -vf ${this.orientation === 1 ? "hflip" : "vflip"} -c:v h264 -pix_fmt yuv420p -y ${outputPath}`
|
||||
MP4Parser.ffmpegCmd(cmd, {
|
||||
callBackResult: (code: number) => {
|
||||
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]
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
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: '视频镜像' })
|
||||
|
||||
Column() {
|
||||
Row() {
|
||||
Text('上传视频').fontColor($r('app.color.color_90ffffff')).fontSize(16).fontWeight(FontWeight.Medium)
|
||||
Text('(仅支持mp4格式)').fontColor($r('app.color.color_50ffffff')).fontSize(12)
|
||||
}.alignSelf(ItemAlign.Start)
|
||||
|
||||
RelativeContainer() {
|
||||
Stack() {
|
||||
Image($r('app.media.ic_add_video')).width(44).height(44)
|
||||
}
|
||||
.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)
|
||||
.margin({ top: 12 })
|
||||
.borderRadius(8)
|
||||
.backgroundColor($r('app.color.color_222222'))
|
||||
}.margin({ left: 16, top: 16, right: 16 })
|
||||
.visibility(this.uri ? Visibility.None : Visibility.Visible)
|
||||
|
||||
Column() {
|
||||
RelativeContainer() {
|
||||
Video({
|
||||
src: this.uri, // 设置视频源
|
||||
controller: this.controller, //设置视频控制器,可以控制视频的播放状态
|
||||
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) => {
|
||||
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: 30, right: 30 })
|
||||
.alignRules({
|
||||
bottom: { anchor: '__container__', align: VerticalAlign.Bottom }
|
||||
})
|
||||
}
|
||||
.layoutWeight(1)
|
||||
|
||||
Row() {
|
||||
Column(){
|
||||
Image($r('app.media.ic_mirror_h')).width(50).height(50)
|
||||
Text('水平').fontColor($r('app.color.color_90ffffff')).fontSize(14).margin({ top: 8 })
|
||||
}
|
||||
.onClick(() => {
|
||||
this.orientation = 1
|
||||
this.controller.stop()
|
||||
this.mirrorVideo()
|
||||
})
|
||||
Column(){
|
||||
Image($r('app.media.ic_mirror_v')).width(50).height(50)
|
||||
Text('垂直').fontColor($r('app.color.color_90ffffff')).fontSize(14).margin({ top: 8 })
|
||||
}
|
||||
.margin({ left: 50 })
|
||||
.onClick(() => {
|
||||
this.orientation = 2
|
||||
this.controller.stop()
|
||||
this.mirrorVideo()
|
||||
})
|
||||
.visibility(Visibility.None)
|
||||
}
|
||||
.margin({ top: 20 })
|
||||
|
||||
Row() {
|
||||
Text(this.isSuccess ? '重新上传' : '取消').fontColor($r('app.color.color_90ffffff')).fontSize(17).margin({ left: 16 })
|
||||
.onClick(() => {
|
||||
this.controller.stop()
|
||||
if (this.isSuccess) {
|
||||
this.selectVideo()
|
||||
} else {
|
||||
this.getUIContext().getRouter().back()
|
||||
}
|
||||
})
|
||||
Blank().layoutWeight(1)
|
||||
Text('保存').fontColor($r("app.color.color_466afd")).fontSize(17).margin({ right: 16 })
|
||||
.onClick(() => {
|
||||
this.controller.stop()
|
||||
if (this.orientation !== 0) {
|
||||
SaveUtils.saveImageVideoToAlbumDialog([this.uri!!])
|
||||
.then((saved) => {
|
||||
if (saved) {
|
||||
this.uri = undefined
|
||||
this.showDownloadDialog()
|
||||
} else {
|
||||
ToastUtils.show('保存失败')
|
||||
}
|
||||
})
|
||||
.catch((e: BusinessError) => {
|
||||
ToastUtils.show('保存失败:' + e.message)
|
||||
})
|
||||
} else {
|
||||
ToastUtils.show('请选择镜像方向')
|
||||
}
|
||||
})
|
||||
}
|
||||
.margin({ top: 20, bottom: 30 })
|
||||
}
|
||||
.layoutWeight(1)
|
||||
.visibility(this.uri ? Visibility.Visible : Visibility.None)
|
||||
}
|
||||
.width('100%')
|
||||
.height('100%')
|
||||
.backgroundColor($r('app.color.window_background'))
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,296 @@
|
|||
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 { MP4Parser } from '@ohos/mp4parser'
|
||||
import { TipDialog } from '../../../../dialog/TipDialog'
|
||||
import { avSessionManager } from '../../../../manager/AVSessionManager'
|
||||
|
||||
@Entry
|
||||
@ComponentV2
|
||||
struct VideoReversePage {
|
||||
private controller: VideoController = new VideoController()
|
||||
@Local uri?: string
|
||||
@Local currentTime: number = 0
|
||||
@Local durationTime: number = 0
|
||||
@Local isPlaying: boolean = false
|
||||
@Local isSuccess: boolean = false
|
||||
|
||||
videoReverse() {
|
||||
LoadingDialog.show(this.getUIContext())
|
||||
this.isSuccess = false
|
||||
let cacheVideoPath = FileUtil.getCacheDirPath() + FileUtil.separator + `kcsp_${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 outputPath = FileUtil.getCacheDirPath() + FileUtil.separator + `kcsp_${systemDateTime.getTime()}.mp4`
|
||||
let cmd = `ffmpeg -i ${cacheVideoPath} -vf reverse -af areverse -c:v h264 -pix_fmt yuv420p -y ${outputPath}`
|
||||
MP4Parser.ffmpegCmd(cmd, {
|
||||
callBackResult: (code: number) => {
|
||||
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]
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
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: '视频倒放' })
|
||||
|
||||
Column() {
|
||||
Row() {
|
||||
Text('上传视频').fontColor($r('app.color.color_90ffffff')).fontSize(16).fontWeight(FontWeight.Medium)
|
||||
Text('(仅支持mp4格式)').fontColor($r('app.color.color_50ffffff')).fontSize(12)
|
||||
}.alignSelf(ItemAlign.Start)
|
||||
|
||||
RelativeContainer() {
|
||||
Stack() {
|
||||
Image($r('app.media.ic_add_video')).width(44).height(44)
|
||||
}
|
||||
.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)
|
||||
.margin({ top: 12 })
|
||||
.borderRadius(8)
|
||||
.backgroundColor($r('app.color.color_222222'))
|
||||
}.margin({ left: 16, top: 16, right: 16 })
|
||||
.visibility(this.uri ? Visibility.None : Visibility.Visible)
|
||||
|
||||
Column() {
|
||||
RelativeContainer() {
|
||||
Video({
|
||||
src: this.uri, // 设置视频源
|
||||
controller: this.controller, //设置视频控制器,可以控制视频的播放状态
|
||||
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) => {
|
||||
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: 30, right: 30 })
|
||||
.alignRules({
|
||||
bottom: { anchor: '__container__', align: VerticalAlign.Bottom }
|
||||
})
|
||||
}
|
||||
.layoutWeight(1)
|
||||
|
||||
Row() {
|
||||
Text(this.isSuccess ? '重新上传' : '取消').fontColor($r('app.color.color_90ffffff')).fontSize(17).margin({ left: 16 })
|
||||
.onClick(() => {
|
||||
this.controller.stop()
|
||||
if (this.isSuccess) {
|
||||
this.selectVideo()
|
||||
} else {
|
||||
this.getUIContext().getRouter().back()
|
||||
}
|
||||
})
|
||||
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 {
|
||||
this.videoReverse()
|
||||
}
|
||||
})
|
||||
}
|
||||
.margin({ top: 140, bottom: 30 })
|
||||
}
|
||||
.layoutWeight(1)
|
||||
.visibility(this.uri ? Visibility.Visible : Visibility.None)
|
||||
}
|
||||
.width('100%')
|
||||
.height('100%')
|
||||
.backgroundColor($r('app.color.window_background'))
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,633 @@
|
|||
import { AppUtil, FileUtil, ObjectUtil,
|
||||
PasteboardUtil,
|
||||
PermissionUtil, RandomUtil, StrUtil } from '@pura/harmony-utils';
|
||||
import { EventConstants } from '../../../../common/EventConstants';
|
||||
import { RouterUrls } from '../../../../common/RouterUrls';
|
||||
import { DownloadDialog, DownloadStatus } from '../../../../dialog/DownloadDialog';
|
||||
import { ImageMaterial, MaterialInfoEntity, MediaEntity, VideoMaterial } from '../../../../entity/MaterialInfoEntity';
|
||||
import { VipPermissionEntity } from '../../../../entity/VipPermissionEntity';
|
||||
import { LoginManager } from '../../../../manager/LoginGlobalManager';
|
||||
import { ShareManager } from '../../../../manager/ShareManager';
|
||||
import { ConfigManager } from '../../../../manager/UserConfigManager';
|
||||
import { MediaDownloader } from '../../../../net/MediaDownloader';
|
||||
import { SaveUtils } from '../../../../utils/SaveUtils';
|
||||
import { ToastUtils } from '../../../../utils/ToastUtils';
|
||||
import { TitleBar } from '../../../../view/TitleBar';
|
||||
import { WxVideoViewModel } from '../../../../viewModel/WxVideoViewModel';
|
||||
import { WxVideoMaterialPage } from './material/WxVideoMaterialPage';
|
||||
import { LevelMode, router } from '@kit.ArkUI';
|
||||
import { WxVideoEntity } from '../../../../entity/WxVideoEntity';
|
||||
import { WxImageMaterialPage } from './material/WxImageMaterialPage';
|
||||
import { OnWXResp, WXApi, WXEventHandler } from '../../../../utils/wechat/WXApiEventHandlerImpl';
|
||||
import * as WxOpenSdk from '@tencent/wechat_open_sdk';
|
||||
import { ErrCode, SendAuthResp } from '@tencent/wechat_open_sdk';
|
||||
import { LoadingDialog } from '../../../../dialog/LoadingDialog';
|
||||
import BuildProfile from 'BuildProfile';
|
||||
import { WxServiceEntity } from '../../../../entity/WxServiceEntity';
|
||||
import { Constants } from '../../../../common/Constants';
|
||||
import { EventReportGlobalManager } from '../../../../manager/EventReportGlobalManager';
|
||||
import { TipDialog } from '../../../../dialog/TipDialog';
|
||||
import { SimpleTipDialog } from '../../../../dialog/SimpleTipDialog';
|
||||
import { JoinWxGroupCourseDialog } from '../../../../dialog/JoinWxGroupCourseDialog';
|
||||
import { PrefUtils } from '../../../../utils/PrefUtils';
|
||||
|
||||
@Entry
|
||||
@ComponentV2
|
||||
struct WxVideoPage {
|
||||
@Local isPlayback: boolean = false
|
||||
@Local currentIndex: number = 0;
|
||||
@Local isRefreshing: boolean = false;
|
||||
|
||||
@Local videoList: Array<VideoMaterial> = [];
|
||||
@Local imageList: Array<ImageMaterial> = [];
|
||||
|
||||
@Local videoRowCount: number = 1;
|
||||
@Local imageRowCount: number = 1;
|
||||
|
||||
viewModel: WxVideoViewModel = new WxVideoViewModel(this.getUIContext());
|
||||
tabController: TabsController = new TabsController();
|
||||
titles: Array<string> = ['视频', '图片'];
|
||||
type: number = 0
|
||||
|
||||
mediaDownloader?: MediaDownloader | null
|
||||
selectedList: Array<MediaEntity> = []
|
||||
cacheFileUris: Array<string> = []
|
||||
downloadIndex: number = 0
|
||||
totalSize = 0
|
||||
downloadStatus = DownloadStatus.DOWNLOADING
|
||||
|
||||
joinGroupDialogController?: CustomDialogController | null;
|
||||
|
||||
//从微信返回的回调
|
||||
onWXResp: OnWXResp = (resp) => {
|
||||
//微信返回的数据
|
||||
if (resp instanceof SendAuthResp && resp.state?.endsWith('video')) {
|
||||
const authResult = JSON.stringify(resp ?? {}, null , 2);
|
||||
const errCode = JSON.parse(authResult).errCode as number;
|
||||
if (errCode === ErrCode.ERR_OK) {
|
||||
const authCode = JSON.parse(authResult).code as string;
|
||||
if (ConfigManager.getPlaybackJoinType() === "img") {
|
||||
this.showJoinGroupCourseDialog()
|
||||
} else {
|
||||
this.viewModel.bindWxUserinfo(authCode)
|
||||
}
|
||||
} else {
|
||||
ToastUtils.show(JSON.parse(authResult).errStr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Monitor('viewModel.wxVideo')
|
||||
onMaterialInfoChange(monitor: IMonitor) {
|
||||
const entity = monitor.value()?.now as WxVideoEntity
|
||||
this.createVideoList(entity.items);
|
||||
this.createImageList(entity.items);
|
||||
if (this.videoList.length > 0) {
|
||||
this.tabController.changeIndex(0);
|
||||
this.currentIndex = 0
|
||||
} else if (this.imageList.length > 0) {
|
||||
this.tabController.changeIndex(1);
|
||||
this.currentIndex = 1
|
||||
}
|
||||
this.isRefreshing = false
|
||||
}
|
||||
|
||||
@Monitor('viewModel.permissionInfo')
|
||||
onPermissionInfoChange(monitor: IMonitor) {
|
||||
const info = monitor.value()?.now as VipPermissionEntity;
|
||||
if (info.auth) {
|
||||
if (!LoginManager.isLogin()) {
|
||||
this.getUIContext().getRouter().pushUrl({url: RouterUrls.LOGIN_PAGE, params: {from: 1}}, router.RouterMode.Single)
|
||||
return;
|
||||
}
|
||||
this.shareOrDownload()
|
||||
} else {
|
||||
if (!info.auth_ad) {
|
||||
this.getUIContext().getRouter().pushUrl({url: RouterUrls.VIP_PAGE, params: {origin: 'download_wechat_video'}})
|
||||
EventReportGlobalManager.eventReport(EventConstants.JUMP_TO_MEMBER_RECHARGE, 'download_wechat_video')
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Monitor('viewModel.errorCode')
|
||||
onErrorCodeChange(monitor: IMonitor) {
|
||||
const errorCode = monitor.value()?.now as number;
|
||||
if (errorCode === 12002 || errorCode === 12003 || errorCode === 12004) {
|
||||
this.getUIContext().getRouter().pushUrl({url: RouterUrls.RECHARGE_DIAMOND_PAGE});
|
||||
EventReportGlobalManager.eventReport(EventConstants.JUMP_TO_RECHARGE_DIAMOND, 'download_wechat_video')
|
||||
ToastUtils.show('钻石已用完')
|
||||
}
|
||||
}
|
||||
|
||||
@Monitor('viewModel.deleteVideo')
|
||||
onDeleteVideo(monitor: IMonitor) {
|
||||
this.isRefreshing = true
|
||||
ToastUtils.show('删除成功')
|
||||
}
|
||||
|
||||
@Monitor('viewModel.wxService')
|
||||
onWxServiceChange(monitor: IMonitor) {
|
||||
const info = monitor.value()?.now as WxServiceEntity;
|
||||
if (StrUtil.isEmpty(info.corpid) || StrUtil.isEmpty(info.address)) {
|
||||
ToastUtils.show('获取客服信息错误')
|
||||
} else {
|
||||
ConfigManager.saveBindWxVideoHelper(true)
|
||||
this.contactWxService(info)
|
||||
}
|
||||
}
|
||||
|
||||
@Monitor('viewModel.wxUserinfo')
|
||||
onWxUserinfoChange(monitor: IMonitor) {
|
||||
if (this.isPlayback) {
|
||||
ConfigManager.saveBindWxPlaybackHelper(true)
|
||||
} else {
|
||||
ConfigManager.saveBindWxVideoHelper(true)
|
||||
}
|
||||
this.jumpToMiniProgram()
|
||||
}
|
||||
|
||||
aboutToAppear(): void {
|
||||
WXEventHandler.registerOnWXRespCallback(this.onWXResp)
|
||||
this.initParams()
|
||||
this.checkBindStatus()
|
||||
}
|
||||
|
||||
aboutToDisappear() {
|
||||
WXEventHandler.unregisterOnWXRespCallback(this.onWXResp)
|
||||
}
|
||||
|
||||
onPageShow(): void {
|
||||
this.isRefreshing = true
|
||||
}
|
||||
|
||||
initParams() {
|
||||
const params = this.getUIContext().getRouter().getParams() as Record<string, Object>;
|
||||
if (params) {
|
||||
this.isPlayback = params.isPlayback as boolean
|
||||
}
|
||||
}
|
||||
|
||||
showSaveTip() {
|
||||
if (PrefUtils.getBoolean('show_save_tip', true)) {
|
||||
SimpleTipDialog.show(this.getUIContext(), {title: '重要提示', content: '下载完成后需要您点击弹窗允许保存之后才能保存文件到相册', callback: {
|
||||
confirm: () => {
|
||||
this.viewModel.checkVip();
|
||||
PrefUtils.put('show_save_tip', false)
|
||||
}
|
||||
}})
|
||||
} else {
|
||||
this.viewModel.checkVip()
|
||||
}
|
||||
}
|
||||
|
||||
shareOrDownload() {
|
||||
this.cacheFileUris.length = 0
|
||||
if (this.type == 0) {
|
||||
if (this.selectedList.length > 0) {
|
||||
this.shareMedia(this.selectedList[0])
|
||||
}
|
||||
} else {
|
||||
if (this.selectedList.length > 0) {
|
||||
this.downloadIndex = 0
|
||||
this.downloadMedia(this.selectedList[this.downloadIndex])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
shareMedia(media: MediaEntity) {
|
||||
let filePath = FileUtil.getCacheDirPath() + FileUtil.separator + media.initFileName()
|
||||
if (FileUtil.accessSync(filePath) && FileUtil.isFile(filePath) && !(media.totalSize === 0 || media.currentLen !== media.totalSize)) {
|
||||
this.shareFile(media)
|
||||
} else {
|
||||
this.showDownloadDialog(media instanceof VideoMaterial && media.isMerge ? DownloadStatus.VIDEO_DOWNLOADING : DownloadStatus.DOWNLOADING)
|
||||
this.download(media, true)
|
||||
}
|
||||
}
|
||||
|
||||
async downloadMedia(media: MediaEntity) {
|
||||
let filePath = FileUtil.getCacheDirPath() + FileUtil.separator + media.initFileName()
|
||||
if (FileUtil.accessSync(filePath) && FileUtil.isFile(filePath) && !(media.totalSize === 0 || media.currentLen !== media.totalSize)) {
|
||||
this.cacheFileUris.push(FileUtil.getUriFromPath(filePath))
|
||||
if (this.downloadIndex < this.selectedList.length - 1) {
|
||||
this.downloadIndex++
|
||||
this.downloadMedia(this.selectedList[this.downloadIndex])
|
||||
} else {
|
||||
let saved = await this.saveFile()
|
||||
if (saved) {
|
||||
if (this.downloadIndex < this.selectedList.length - 1) {
|
||||
this.downloadIndex++
|
||||
this.downloadMedia(this.selectedList[this.downloadIndex])
|
||||
} else {
|
||||
this.updateDownloadDialog(DownloadStatus.COMPLETED, this.totalSize, this.totalSize)
|
||||
}
|
||||
} else {
|
||||
ToastUtils.show('保存失败')
|
||||
this.dismissDownloadDialog()
|
||||
}
|
||||
this.isRefreshing = true
|
||||
}
|
||||
} else {
|
||||
this.showDownloadDialog(media instanceof VideoMaterial && media.isMerge ? DownloadStatus.VIDEO_DOWNLOADING : DownloadStatus.DOWNLOADING)
|
||||
this.download(media)
|
||||
}
|
||||
}
|
||||
|
||||
async download(media: MediaEntity, isShare: boolean = false) {
|
||||
this.viewModel.reportStatus(media.logid, '1')
|
||||
media.initFileName()
|
||||
this.mediaDownloader = MediaDownloader.getInstance()
|
||||
this.mediaDownloader
|
||||
.callback({
|
||||
onSuccess: async (path) => {
|
||||
if (isShare) {
|
||||
this.shareFile(media)
|
||||
} else {
|
||||
this.cacheFileUris.push(FileUtil.getUriFromPath(path))
|
||||
if (this.downloadIndex < this.selectedList.length - 1) {
|
||||
this.downloadIndex++
|
||||
this.downloadMedia(this.selectedList[this.downloadIndex])
|
||||
} else {
|
||||
let saved = await this.saveFile()
|
||||
if (saved) {
|
||||
if (this.downloadIndex < this.selectedList.length - 1) {
|
||||
this.downloadIndex++
|
||||
this.downloadMedia(this.selectedList[this.downloadIndex])
|
||||
} else {
|
||||
this.updateDownloadDialog(DownloadStatus.COMPLETED, this.totalSize, this.totalSize)
|
||||
}
|
||||
} else {
|
||||
ToastUtils.show('保存失败')
|
||||
this.dismissDownloadDialog()
|
||||
}
|
||||
this.isRefreshing = true
|
||||
}
|
||||
}
|
||||
},
|
||||
onGetTotal: (total) => {
|
||||
this.totalSize = total
|
||||
this.updateDownloadDialog(this.downloadStatus, total)
|
||||
},
|
||||
onProgress: (progress) => {
|
||||
this.updateDownloadDialog(this.downloadStatus, this.totalSize, progress)
|
||||
},
|
||||
onMerge: (step) => {
|
||||
if (step === 4) {
|
||||
this.updateDownloadDialog(DownloadStatus.AUDIO_DOWNLOADING)
|
||||
} else {
|
||||
this.updateDownloadDialog(DownloadStatus.PROCESSING)
|
||||
}
|
||||
},
|
||||
onPause:() => {
|
||||
this.dismissDownloadDialog()
|
||||
},
|
||||
onCancel: () => {
|
||||
this.dismissDownloadDialog()
|
||||
},
|
||||
onFailed: (msg) => {
|
||||
ToastUtils.show('下载失败:' + msg)
|
||||
this.dismissDownloadDialog()
|
||||
this.viewModel.reportStatus(media.logid, '-1', `${media.totalSize}`, msg)
|
||||
this.reportErrorEvent(media, msg)
|
||||
}
|
||||
})
|
||||
.down(media);
|
||||
}
|
||||
|
||||
shareFile(media: MediaEntity) {
|
||||
ShareManager.shareFile(FileUtil.getCacheDirPath() + FileUtil.separator + media.initFileName())
|
||||
this.viewModel.reportStatus(media.logid, '2', `${media.totalSize}`)
|
||||
this.dismissDownloadDialog()
|
||||
}
|
||||
|
||||
async saveFile(): Promise<boolean> {
|
||||
let saved = await SaveUtils.saveImageVideoToAlbumDialog(this.cacheFileUris)
|
||||
if (saved) {
|
||||
this.cacheFileUris.forEach((uri, index) => {
|
||||
let stat = FileUtil.statSync(FileUtil.getFilePath(uri))
|
||||
this.viewModel.reportStatus(this.selectedList[index].logid, '2', `${stat.size}`)
|
||||
})
|
||||
}
|
||||
return Promise.resolve(saved)
|
||||
}
|
||||
|
||||
showDownloadDialog(status: DownloadStatus = DownloadStatus.DOWNLOADING) {
|
||||
this.downloadStatus = status
|
||||
DownloadDialog.show(this.getUIContext(), { status: status, totalSize: 0, progress: 0, totalCount: this.selectedList.length, index: this.downloadIndex, callback: {
|
||||
confirm: () => {
|
||||
if (this.downloadStatus === DownloadStatus.COMPLETED) {
|
||||
EventReportGlobalManager.eventReport(EventConstants.DIALOG_GO_TO_VIEW, this.titles[this.currentIndex])
|
||||
AppUtil.getContext().eventHub.emit(EventConstants.JumpToRecordEvent, this.currentIndex)
|
||||
this.getUIContext().getRouter().back()
|
||||
} else {
|
||||
//todo 后台下载
|
||||
}
|
||||
},
|
||||
cancel: () => {
|
||||
if (this.downloadStatus !== DownloadStatus.COMPLETED) {
|
||||
if (this.mediaDownloader) {
|
||||
this.mediaDownloader.cancel()
|
||||
EventReportGlobalManager.eventReport(EventConstants.CANCEL_DOWNLOAD_VIDEO, this.selectedList[this.downloadIndex].url)
|
||||
}
|
||||
} else {
|
||||
EventReportGlobalManager.eventReport(EventConstants.DIALOG_CONFIRM_SAVE_FILE, this.titles[this.currentIndex])
|
||||
}
|
||||
}
|
||||
} })
|
||||
}
|
||||
|
||||
updateDownloadDialog(status: DownloadStatus = DownloadStatus.DOWNLOADING, totalSize: number = 0, progress: number = 0, isAudio: boolean = false) {
|
||||
this.downloadStatus = status
|
||||
DownloadDialog.update({ status: status, totalSize: totalSize, progress: progress, totalCount: this.selectedList.length, index: this.downloadIndex, isAudio: isAudio })
|
||||
}
|
||||
|
||||
dismissDownloadDialog() {
|
||||
this.downloadStatus = DownloadStatus.DOWNLOADING
|
||||
this.totalSize = 0
|
||||
this.downloadIndex = 0
|
||||
this.mediaDownloader = null
|
||||
DownloadDialog.dismiss()
|
||||
}
|
||||
|
||||
createVideoList(materials?: Array<MaterialInfoEntity>) {
|
||||
const list = new Array<VideoMaterial>();
|
||||
materials?.forEach((info) => {
|
||||
info.material?.video?.forEach((video, index) => {
|
||||
video.logid = info.logid
|
||||
video.isThreading = info.material!!.threading
|
||||
if (info.material?.image && info.material.image.length > index) {
|
||||
video.thumb = info.material.image[index].url
|
||||
}
|
||||
video.flag = RandomUtil.getRandomNumber(0, 1000)
|
||||
list.push(video)
|
||||
})
|
||||
})
|
||||
this.videoList = list.map(item => ObjectUtil.assign(new VideoMaterial(), item) as VideoMaterial);
|
||||
if (this.videoList.length > 0) {
|
||||
this.videoList[0].isChecked = true
|
||||
}
|
||||
this.videoRowCount = this.computeRowCount(this.videoList);
|
||||
}
|
||||
|
||||
createImageList(materials?: Array<MaterialInfoEntity>) {
|
||||
const list = new Array<ImageMaterial>();
|
||||
materials?.forEach((info) => {
|
||||
info.material?.image?.forEach((image) => {
|
||||
image.logid = info.logid
|
||||
image.flag = RandomUtil.getRandomNumber(0, 1000)
|
||||
list.push(image)
|
||||
})
|
||||
})
|
||||
this.imageList = list.map(item => ObjectUtil.assign(new ImageMaterial(), item) as ImageMaterial);
|
||||
if (this.imageList.length > 0) {
|
||||
this.imageList[0].isChecked = true
|
||||
}
|
||||
this.imageRowCount = this.computeRowCount(this.imageList);
|
||||
}
|
||||
|
||||
computeRowCount(list: Array<MediaEntity>): number {
|
||||
if (list.length > 8) {
|
||||
return 3;
|
||||
} else if (list.length >= 3 && list.length <= 8) {
|
||||
return 2;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
checkBindStatus() {
|
||||
if (this.isPlayback && !ConfigManager.isBindWxPlaybackHelper() || !this.isPlayback && !ConfigManager.isBindWxVideoHelper()) {
|
||||
if (LoginManager.getLastUserInfo()?.user_id !== LoginManager.getUserInfo()?.user_id) {
|
||||
TipDialog.show(this.getUIContext(), {title: '提示', content: '系统检测到您更换了账号,请重新添加助手', callback: {
|
||||
confirm: () => {
|
||||
if (this.isPlayback || !ConfigManager.isWxVideoServiceEnable()) {
|
||||
if (ConfigManager.getPlaybackJoinType() === "img") {
|
||||
this.showJoinGroupCourseDialog()
|
||||
} else {
|
||||
this.wxAuth()
|
||||
}
|
||||
} else {
|
||||
this.getWxServiceInfo()
|
||||
}
|
||||
}
|
||||
}})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
showJoinGroupCourseDialog() {
|
||||
this.joinGroupDialogController = new CustomDialogController({
|
||||
builder: JoinWxGroupCourseDialog({ isPlayback: this.isPlayback }),
|
||||
width: '100%',
|
||||
cornerRadius: 20,
|
||||
autoCancel: true,
|
||||
maskColor: '#CC000000',
|
||||
levelMode: LevelMode.EMBEDDED,
|
||||
backgroundBlurStyle: BlurStyle.NONE,
|
||||
alignment: DialogAlignment.Bottom
|
||||
})
|
||||
this.joinGroupDialogController.open();
|
||||
}
|
||||
|
||||
async wxAuth() {
|
||||
if (!WXApi.isWXAppInstalled()) {
|
||||
ToastUtils.show('未安装微信客户端,请先下载安装微信客户端');
|
||||
return;
|
||||
}
|
||||
LoadingDialog.show(this.getUIContext());
|
||||
let req = new WxOpenSdk.SendAuthReq;
|
||||
req.isOption1 = false;
|
||||
req.nonAutomatic = true;
|
||||
req.scope = 'snsapi_userinfo';
|
||||
req.state = BuildProfile.BUNDLE_NAME + RandomUtil.getRandomInt(0, 1000) + '_video';
|
||||
req.transaction ='';
|
||||
|
||||
await WXApi.sendReq(AppUtil.getContext(), req)
|
||||
EventReportGlobalManager.eventReport(EventConstants.JUMP_TO_SHARE_WX_PLAYBACK, '前往微信分享直播回放')
|
||||
LoadingDialog.dismiss();
|
||||
}
|
||||
|
||||
async jumpToMiniProgram() {
|
||||
//保存成功跳转直播回放加群小程序
|
||||
try {
|
||||
let wxVideoConfig = ConfigManager.getWxVideoConfig()
|
||||
if (wxVideoConfig != null && LoginManager.getUserInfo()) {
|
||||
PasteboardUtil.setDataText(LoginManager.getUserInfo()!!.user_id)
|
||||
|
||||
wxVideoConfig.id = LoginManager.getUserInfo()!!.user_id
|
||||
let params = encodeURI(JSON.stringify(wxVideoConfig)).replace('+', '%20')
|
||||
let launchMiniProgramReq = new WxOpenSdk.LaunchMiniProgramReq()
|
||||
launchMiniProgramReq.userName = Constants.MINI_PROGRAM_APP_ID //拉起的小程序的原始id
|
||||
launchMiniProgramReq.path = `pages/index/index?path=share¶m=${params}`
|
||||
launchMiniProgramReq.miniprogramType = 0 //拉起小程序的类型 0-正式版 1-开发版 2-体验版
|
||||
await WXApi.sendReq(AppUtil.getContext(), launchMiniProgramReq)
|
||||
} else {
|
||||
ToastUtils.show('获取配置失败,请联系客服')
|
||||
}
|
||||
} catch (e) {
|
||||
ToastUtils.show('跳转失败,请联系客服')
|
||||
}
|
||||
}
|
||||
|
||||
getWxServiceInfo() {
|
||||
if (!WXApi.isWXAppInstalled()) {
|
||||
ToastUtils.show('未安装微信客户端,请先下载安装微信客户端');
|
||||
return;
|
||||
}
|
||||
this.viewModel.wxServiceInfo()
|
||||
EventReportGlobalManager.eventReport(EventConstants.JUMP_TO_SHARE_WX_VIDEO, "前往微信分享视频号", '')
|
||||
}
|
||||
|
||||
/**
|
||||
* 跳转客服
|
||||
* @param service
|
||||
*/
|
||||
contactWxService(service: WxServiceEntity) {
|
||||
let req = new WxOpenSdk.OpenCustomerServiceChatReq()
|
||||
req.corpId = service.corpid; // 企业ID
|
||||
req.url = service.address; // 客服URL
|
||||
WXApi.sendReq(AppUtil.getContext(), req)
|
||||
}
|
||||
|
||||
reportErrorEvent(media: MediaEntity, message: string) {
|
||||
if (media instanceof VideoMaterial) {
|
||||
EventReportGlobalManager.eventReport(EventConstants.ERROR_CLIENT_DOWNLOAD_VIDEO, media.url, message)
|
||||
} else if (media instanceof ImageMaterial) {
|
||||
EventReportGlobalManager.eventReport(EventConstants.ERROR_CLIENT_DOWNLOAD_IMG, media.url, message)
|
||||
}
|
||||
}
|
||||
|
||||
build() {
|
||||
RelativeContainer() {
|
||||
Column() {
|
||||
TitleBar({ title: this.isPlayback ? '直播回放' : '视频号' })
|
||||
|
||||
Stack({ alignContent: Alignment.TopStart }) {
|
||||
Refresh({refreshing: this.isRefreshing}) {
|
||||
Tabs({ barPosition: BarPosition.Start, controller: this.tabController }) {
|
||||
TabContent() {
|
||||
WxVideoMaterialPage({mediaList: this.videoList, rowCount: this.videoRowCount, isPlayback: this.isPlayback,
|
||||
onShare:(video) => {
|
||||
this.type = 0
|
||||
this.selectedList.length = 0
|
||||
this.selectedList.push(video)
|
||||
this.viewModel.checkVip();
|
||||
},
|
||||
onSave: (list) => {
|
||||
this.type = 1
|
||||
this.selectedList = list
|
||||
this.showSaveTip();
|
||||
},
|
||||
onItemDelete: (video) => {
|
||||
TipDialog.show(this.getUIContext(), {title: '提示', content: this.isPlayback ? '确定删除该直播回放?' : '确定删除该视频号?', callback: {
|
||||
confirm: () => {
|
||||
this.viewModel.deleteWxVideo(video.logid)
|
||||
}
|
||||
}})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
TabContent() {
|
||||
WxImageMaterialPage({mediaList: this.imageList, rowCount: this.imageRowCount, isPlayback: this.isPlayback,
|
||||
onShare:(image) => {
|
||||
this.type = 0
|
||||
this.selectedList.length = 0
|
||||
this.selectedList.push(image)
|
||||
this.viewModel.checkVip();
|
||||
},
|
||||
onSave: (list) => {
|
||||
this.type = 1
|
||||
this.selectedList = list
|
||||
this.showSaveTip();
|
||||
},
|
||||
onItemDelete: (image) => {
|
||||
TipDialog.show(this.getUIContext(), {title: '提示', content: this.isPlayback ? '确定删除该直播回放?' : '确定删除该视频号?', callback: {
|
||||
confirm: () => {
|
||||
this.viewModel.deleteWxVideo(image.logid)
|
||||
}
|
||||
}})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
.scrollable(false)
|
||||
/*.onSelected((index: number) => {
|
||||
this.currentIndex = index;
|
||||
})*/
|
||||
}
|
||||
.onRefreshing(() => {
|
||||
this.isRefreshing = true
|
||||
this.viewModel.videoList(this.isPlayback ? 'playback' : 'wechatvideo')
|
||||
})
|
||||
.refreshOffset(50)
|
||||
.pullToRefresh(true)
|
||||
|
||||
Row({ space: 40 }) {
|
||||
ForEach(this.titles, (title: string, index) => {
|
||||
this.tab(title, index);
|
||||
})
|
||||
Blank().layoutWeight(1)
|
||||
Row() {
|
||||
Image($r('app.media.ic_wx_video_course')).width(16).height(16)
|
||||
Text('视频教程').fontColor($r('app.color.color_80ffffff')).fontSize(12).margin({ left: 4 })
|
||||
}
|
||||
.onClick(() => {
|
||||
if (this.isPlayback) {
|
||||
this.getUIContext().getRouter().pushUrl({url: RouterUrls.VIDEO_PLAYER_PAGE, params: {uri: ConfigManager.getPlaybackCourse(), title: '视频教程'}})
|
||||
} else {
|
||||
this.getUIContext().getRouter().pushUrl({url: RouterUrls.VIDEO_PLAYER_PAGE, params: {uri: ConfigManager.getWxVideoCourse(), title: '视频教程'}})
|
||||
}
|
||||
})
|
||||
}.padding({ left: 16, right: 16 })
|
||||
.margin({ top: 10 })
|
||||
}.layoutWeight(1)
|
||||
}
|
||||
|
||||
Row() {
|
||||
Image(this.isPlayback ? $r('app.media.ic_playback_helper') : $r('app.media.ic_video_helper')).width(26).height(26)
|
||||
Text(this.isPlayback ? '添加直播\n回放助手' : '添加助手').margin({left: 6}).fontColor(Color.White).fontSize(12)
|
||||
Image($r('app.media.ic_arrow_dp16')).width(16).height(16).margin({left: 2})
|
||||
}
|
||||
.padding(8)
|
||||
.backgroundColor($r('app.color.color_333333'))
|
||||
.borderRadius({topLeft: 10, bottomLeft: 10})
|
||||
.alignRules({
|
||||
right: {anchor:'__container__', align: HorizontalAlign.End},
|
||||
bottom: {anchor:'__container__', align: VerticalAlign.Bottom},
|
||||
})
|
||||
.margin({bottom: 100})
|
||||
.onClick(() => {
|
||||
if (this.isPlayback || !ConfigManager.isWxVideoServiceEnable()) {
|
||||
if (ConfigManager.getPlaybackJoinType() === "img") {
|
||||
this.showJoinGroupCourseDialog()
|
||||
} else {
|
||||
this.wxAuth()
|
||||
}
|
||||
} else {
|
||||
this.getWxServiceInfo()
|
||||
}
|
||||
})
|
||||
}
|
||||
.width('100%')
|
||||
.height('100%')
|
||||
.backgroundColor($r('app.color.window_background'))
|
||||
}
|
||||
|
||||
@Builder
|
||||
tab(tabName: string, tabIndex: number) {
|
||||
Row() {
|
||||
Text(tabName)
|
||||
.fontSize(this.currentIndex === tabIndex ? 17 : 14)
|
||||
.fontWeight(this.currentIndex === tabIndex ? FontWeight.Medium : FontWeight.Regular)
|
||||
.lineHeight(24)
|
||||
.fontColor(tabIndex === this.currentIndex ? $r("app.color.color_466afd") : $r('app.color.color_50ffffff'))
|
||||
}
|
||||
.width('auto')
|
||||
.height('auto')
|
||||
.onClick(() => {
|
||||
this.tabController.changeIndex(tabIndex);
|
||||
this.currentIndex = tabIndex;
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,146 @@
|
|||
import { RouterUrls } from '../../../../../common/RouterUrls';
|
||||
import { ImageMaterial } from '../../../../../entity/MaterialInfoEntity';
|
||||
import { ConfigManager } from '../../../../../manager/UserConfigManager';
|
||||
import { ToastUtils } from '../../../../../utils/ToastUtils';
|
||||
import { ImageMaterialItemView } from '../../../../../view/MaterialItemView';
|
||||
|
||||
@ComponentV2
|
||||
export struct WxImageMaterialPage {
|
||||
@Param isPlayback: boolean = false
|
||||
@Param mediaList: Array<ImageMaterial> = [];
|
||||
@Param rowCount: number = 1;
|
||||
@Param onShare?: (video: ImageMaterial) => void = undefined
|
||||
@Param onSave?: (list: Array<ImageMaterial>) => void = undefined
|
||||
@Param onItemDelete?: (video: ImageMaterial) => void = undefined
|
||||
@Local isCheckAll: boolean = false
|
||||
|
||||
selectedItems(): Array<ImageMaterial> {
|
||||
const list = new Array<ImageMaterial>();
|
||||
this.mediaList.forEach((item) => {
|
||||
if (item.isChecked) {
|
||||
list.push(item);
|
||||
}
|
||||
})
|
||||
return list;
|
||||
}
|
||||
|
||||
build() {
|
||||
Stack() {
|
||||
Column() {
|
||||
Grid() {
|
||||
ForEach(this.mediaList, (item: ImageMaterial, index) => {
|
||||
GridItem() {
|
||||
ImageMaterialItemView({ media: item, rowCount: this.rowCount, isWxVideo: true,
|
||||
onDelete: (image) => {
|
||||
if (this.onItemDelete) {
|
||||
this.onItemDelete(image)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
.onClick(() => {
|
||||
item.isChecked = !item.isChecked;
|
||||
this.isCheckAll = this.mediaList.every(item => item.isChecked)
|
||||
})
|
||||
})
|
||||
}
|
||||
.scrollBar(BarState.Off)
|
||||
.columnsTemplate(this.rowCount === 1 ? '1fr' : this.rowCount === 2 ? '1fr 1fr' : '1fr 1fr 1fr')
|
||||
.rowsGap(10)
|
||||
.columnsGap(10)
|
||||
.margin({ left: 16, right: 16, bottom: 15 })
|
||||
.layoutWeight(1)
|
||||
|
||||
Row() {
|
||||
Row() {
|
||||
Image(this.mediaList.every(item => item.isChecked) ? $r('app.media.ic_check_true') :
|
||||
$r('app.media.ic_check_false')).width(18).height(18)
|
||||
Text('全选').fontColor($r('app.color.color_90ffffff')).fontSize(16).margin({ left: 7 })
|
||||
}
|
||||
.onClick(() => {
|
||||
this.isCheckAll = !this.isCheckAll;
|
||||
this.mediaList.forEach((item) => {
|
||||
item.isChecked = this.isCheckAll;
|
||||
})
|
||||
})
|
||||
|
||||
Blank().layoutWeight(1)
|
||||
|
||||
Button('转发', { type: ButtonType.Capsule, stateEffect: true })
|
||||
.width(122)
|
||||
.height(40)
|
||||
.backgroundColor($r('app.color.color_333333'))
|
||||
.fontColor($r('app.color.color_50ffffff'))
|
||||
.fontSize(15)
|
||||
.onClick(() => {
|
||||
if (this.onShare) {
|
||||
const list = this.selectedItems();
|
||||
if (list.length === 0) {
|
||||
ToastUtils.show('请选择要转发的图片');
|
||||
} else if (list.length > 1) {
|
||||
ToastUtils.show('一次只能转发一张图片');
|
||||
} else {
|
||||
this.onShare(list[0]);
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
Button('保存', { type: ButtonType.Capsule, stateEffect: true })
|
||||
.width(122)
|
||||
.height(40)
|
||||
.linearGradient({
|
||||
colors: [['#F62C6C', 0.0], ['#FC4F54', 1.0]],
|
||||
direction: GradientDirection.Right
|
||||
})
|
||||
.fontColor($r('app.color.color_90ffffff'))
|
||||
.fontSize(15)
|
||||
.margin({ left: 12 })
|
||||
.onClick(() => {
|
||||
if (this.onSave) {
|
||||
const list = this.selectedItems();
|
||||
if (list.length === 0) {
|
||||
ToastUtils.show('请选择要保存的图片');
|
||||
} else {
|
||||
this.onSave(list);
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
.backgroundColor($r('app.color.color_222222'))
|
||||
.padding({
|
||||
left: 16,
|
||||
top: 10,
|
||||
right: 16,
|
||||
bottom: 30
|
||||
})
|
||||
.visibility(this.mediaList.length > 0 ? Visibility.Visible : Visibility.None)
|
||||
}
|
||||
|
||||
Column() {
|
||||
Stack() {
|
||||
Image($r('app.media.ic_course_thumb')).width(240).height(240)
|
||||
Image($r('app.media.ic_play_video')).width(50).height(50)
|
||||
}.width('100%').height(290).backgroundColor(Color.Black)
|
||||
.onClick(() => {
|
||||
if (this.isPlayback) {
|
||||
this.getUIContext().getRouter().pushUrl({url: RouterUrls.VIDEO_PLAYER_PAGE, params: {uri: ConfigManager.getPlaybackCourse(), title: '视频教程'}})
|
||||
} else {
|
||||
this.getUIContext().getRouter().pushUrl({url: RouterUrls.VIDEO_PLAYER_PAGE, params: {uri: ConfigManager.getWxVideoCourse(), title: '视频教程'}})
|
||||
}
|
||||
})
|
||||
|
||||
Column() {
|
||||
Text('操作步骤:').fontColor($r('app.color.color_90ffffff')).fontSize(14)
|
||||
Text(this.isPlayback ? $r('app.string.wx_playback_course') : $r('app.string.wx_video_course'))
|
||||
.fontColor($r('app.color.color_50ffffff'))
|
||||
.fontSize(12)
|
||||
.lineHeight(20)
|
||||
.margin({ top: 9 })
|
||||
}.alignItems(HorizontalAlign.Start).width(245).layoutWeight(1).margin({ top: 37 })
|
||||
}
|
||||
.visibility(this.mediaList.length > 0 ? Visibility.None : Visibility.Visible)
|
||||
}
|
||||
.width('100%')
|
||||
.height('100%')
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,145 @@
|
|||
import { RouterUrls } from '../../../../../common/RouterUrls';
|
||||
import { VideoMaterial } from '../../../../../entity/MaterialInfoEntity';
|
||||
import { ConfigManager } from '../../../../../manager/UserConfigManager';
|
||||
import { ToastUtils } from '../../../../../utils/ToastUtils';
|
||||
import { VideoMaterialItemView } from '../../../../../view/MaterialItemView';
|
||||
|
||||
@ComponentV2
|
||||
export struct WxVideoMaterialPage {
|
||||
@Param isPlayback: boolean = false
|
||||
@Param mediaList: Array<VideoMaterial> = [];
|
||||
@Param rowCount: number = 1;
|
||||
@Param onShare?: (video: VideoMaterial) => void = undefined
|
||||
@Param onSave?: (list: Array<VideoMaterial>) => void = undefined
|
||||
@Param onItemDelete?: (video: VideoMaterial) => void = undefined
|
||||
@Local isCheckAll: boolean = false
|
||||
|
||||
selectedItems(): Array<VideoMaterial> {
|
||||
const list = new Array<VideoMaterial>();
|
||||
this.mediaList.forEach((item) => {
|
||||
if (item.isChecked) {
|
||||
list.push(item);
|
||||
}
|
||||
})
|
||||
return list;
|
||||
}
|
||||
|
||||
build() {
|
||||
Stack() {
|
||||
Column() {
|
||||
Grid() {
|
||||
ForEach(this.mediaList, (item: VideoMaterial, index) => {
|
||||
GridItem() {
|
||||
VideoMaterialItemView({ media: item, rowCount: this.rowCount, isWxVideo: true, onDelete:(video) => {
|
||||
if (this.onItemDelete) {
|
||||
this.onItemDelete(video)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
.onClick(() => {
|
||||
item.isChecked = !item.isChecked;
|
||||
this.isCheckAll = this.mediaList.every(item => item.isChecked)
|
||||
})
|
||||
})
|
||||
}
|
||||
.scrollBar(BarState.Off)
|
||||
.columnsTemplate(this.rowCount === 1 ? '1fr' : this.rowCount === 2 ? '1fr 1fr' : '1fr 1fr 1fr')
|
||||
.rowsGap(10)
|
||||
.columnsGap(10)
|
||||
.margin({ left: 16, right: 16, bottom: 15 })
|
||||
.layoutWeight(1)
|
||||
|
||||
Row() {
|
||||
Row() {
|
||||
Image(this.mediaList.every(item => item.isChecked) ? $r('app.media.ic_check_true') :
|
||||
$r('app.media.ic_check_false')).width(18).height(18)
|
||||
Text('全选').fontColor($r('app.color.color_90ffffff')).fontSize(16).margin({ left: 7 })
|
||||
}
|
||||
.onClick(() => {
|
||||
this.isCheckAll = !this.isCheckAll;
|
||||
this.mediaList.forEach((item) => {
|
||||
item.isChecked = this.isCheckAll;
|
||||
})
|
||||
})
|
||||
|
||||
Blank().layoutWeight(1)
|
||||
|
||||
Button('转发', { type: ButtonType.Capsule, stateEffect: true })
|
||||
.width(122)
|
||||
.height(40)
|
||||
.backgroundColor($r('app.color.color_333333'))
|
||||
.fontColor($r('app.color.color_50ffffff'))
|
||||
.fontSize(15)
|
||||
.onClick(() => {
|
||||
if (this.onShare) {
|
||||
const list = this.selectedItems();
|
||||
if (list.length === 0) {
|
||||
ToastUtils.show('请选择要转发的视频');
|
||||
} else if (list.length > 1) {
|
||||
ToastUtils.show('一次只能转发一个视频');
|
||||
} else {
|
||||
this.onShare(list[0]);
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
Button('保存', { type: ButtonType.Capsule, stateEffect: true })
|
||||
.width(122)
|
||||
.height(40)
|
||||
.linearGradient({
|
||||
colors: [['#F62C6C', 0.0], ['#FC4F54', 1.0]],
|
||||
direction: GradientDirection.Right
|
||||
})
|
||||
.fontColor($r('app.color.color_90ffffff'))
|
||||
.fontSize(15)
|
||||
.margin({ left: 12 })
|
||||
.onClick(() => {
|
||||
if (this.onSave) {
|
||||
const list = this.selectedItems();
|
||||
if (list.length === 0) {
|
||||
ToastUtils.show('请选择要保存的视频');
|
||||
} else {
|
||||
this.onSave(list);
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
.backgroundColor($r('app.color.color_222222'))
|
||||
.padding({
|
||||
left: 16,
|
||||
top: 10,
|
||||
right: 16,
|
||||
bottom: 30
|
||||
})
|
||||
.visibility(this.mediaList.length > 0 ? Visibility.Visible : Visibility.None)
|
||||
}
|
||||
|
||||
Column() {
|
||||
Stack() {
|
||||
Image($r('app.media.ic_course_thumb')).width(240).height(240)
|
||||
Image($r('app.media.ic_play_video')).width(50).height(50)
|
||||
}.width('100%').height(290).backgroundColor(Color.Black)
|
||||
.onClick(() => {
|
||||
if (this.isPlayback) {
|
||||
this.getUIContext().getRouter().pushUrl({url: RouterUrls.VIDEO_PLAYER_PAGE, params: {uri: ConfigManager.getPlaybackCourse(), title: '视频教程'}})
|
||||
} else {
|
||||
this.getUIContext().getRouter().pushUrl({url: RouterUrls.VIDEO_PLAYER_PAGE, params: {uri: ConfigManager.getWxVideoCourse(), title: '视频教程'}})
|
||||
}
|
||||
})
|
||||
|
||||
Column() {
|
||||
Text('操作步骤:').fontColor($r('app.color.color_90ffffff')).fontSize(14)
|
||||
Text(this.isPlayback ? $r('app.string.wx_playback_course') : $r('app.string.wx_video_course'))
|
||||
.fontColor($r('app.color.color_50ffffff'))
|
||||
.fontSize(12)
|
||||
.lineHeight(20)
|
||||
.margin({ top: 9 })
|
||||
}.alignItems(HorizontalAlign.Start).width(245).layoutWeight(1).margin({ top: 37 })
|
||||
}
|
||||
.visibility(this.mediaList.length > 0 ? Visibility.None : Visibility.Visible)
|
||||
}
|
||||
.width('100%')
|
||||
.height('100%')
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,436 @@
|
|||
import { AppUtil, FileUtil, FormatUtil, NumberUtil, PasteboardUtil, StrUtil } from '@pura/harmony-utils';
|
||||
import { EventConstants } from '../../../common/EventConstants';
|
||||
import { RouterUrls } from '../../../common/RouterUrls';
|
||||
import { UserEntity } from '../../../entity/UserEntity';
|
||||
import { LoginManager } from '../../../manager/LoginGlobalManager';
|
||||
import { ToastUtils } from '../../../utils/ToastUtils';
|
||||
import { TextItemView } from '../../../view/TextItemView';
|
||||
import MineViewModel from '../../../viewModel/MineViewModel';
|
||||
import { router } from '@kit.ArkUI';
|
||||
import { TipDialog } from '../../../dialog/TipDialog';
|
||||
import { fileIo, storageStatistics } from '@kit.CoreFileKit';
|
||||
import { BusinessError } from '@kit.BasicServicesKit';
|
||||
import { LoadingDialog } from '../../../dialog/LoadingDialog';
|
||||
import { DiamondDetailEntity } from '../../../entity/DiamondDetailEntity';
|
||||
import { EventReportGlobalManager } from '../../../manager/EventReportGlobalManager';
|
||||
import { WxServiceEntity } from '../../../entity/WxServiceEntity';
|
||||
import { WXApi } from '../../../utils/wechat/WXApiEventHandlerImpl';
|
||||
import * as WxOpenSdk from '@tencent/wechat_open_sdk';
|
||||
import { ScanUtil } from '@pura/picker_utils';
|
||||
import { scanCore } from '@kit.ScanKit';
|
||||
|
||||
@ComponentV2
|
||||
export struct MinePage {
|
||||
@Local showChallenge: boolean = false;
|
||||
@Local showShare: boolean = false;
|
||||
@Local isLogin: boolean = LoginManager.isLogin();
|
||||
@Local userinfo?: UserEntity;
|
||||
@Local diamondInfo?: DiamondDetailEntity
|
||||
@Local cacheSize: number = 0
|
||||
|
||||
scroller: Scroller = new Scroller();
|
||||
|
||||
viewModel: MineViewModel = new MineViewModel(this.getUIContext());
|
||||
|
||||
|
||||
@Monitor('viewModel.userEntity')
|
||||
onUserinfoChange(monitor: IMonitor) {
|
||||
this.userinfo = monitor.value()?.now as UserEntity;
|
||||
}
|
||||
|
||||
@Monitor('viewModel.wxService')
|
||||
onWxServiceChange(monitor: IMonitor) {
|
||||
const info = monitor.value()?.now as WxServiceEntity
|
||||
if (StrUtil.isEmpty(info.corpid) || StrUtil.isEmpty(info.address)) {
|
||||
ToastUtils.show('获取客服信息错误')
|
||||
} else {
|
||||
this.contactWxService(info)
|
||||
}
|
||||
}
|
||||
|
||||
@Monitor('viewModel.diamondInfo')
|
||||
onDiamondInfoChange(monitor: IMonitor) {
|
||||
this.diamondInfo = monitor.value()?.now as DiamondDetailEntity;
|
||||
}
|
||||
|
||||
aboutToAppear(): void {
|
||||
this.initObserver();
|
||||
this.getCache()
|
||||
this.viewModel.userinfo();
|
||||
this.viewModel.getDiamondInfo()
|
||||
}
|
||||
|
||||
initObserver() {
|
||||
AppUtil.getContext().eventHub.on(EventConstants.MineRefreshEvent, () => {
|
||||
this.isLogin = LoginManager.isLogin();
|
||||
this.viewModel.userinfo();
|
||||
this.getCache();
|
||||
});
|
||||
}
|
||||
|
||||
getCache() {
|
||||
storageStatistics.getCurrentBundleStats((error: BusinessError, bundleStats: storageStatistics.BundleStats) => {
|
||||
if (error) {
|
||||
console.error('getCurrentBundleStats failed with error:' + JSON.stringify(error));
|
||||
} else {
|
||||
console.info('getCurrentBundleStats successfully:' + JSON.stringify(bundleStats));
|
||||
this.cacheSize = bundleStats.cacheSize
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Clear cache
|
||||
clearCache() {
|
||||
LoadingDialog.show(this.getUIContext())
|
||||
let cacheDir = AppUtil.getContext().cacheDir;
|
||||
fileIo.listFile(cacheDir).then((filenames) => {
|
||||
for (let i = 0; i < filenames.length; i++) {
|
||||
let dirPath = cacheDir + '/' + filenames[i];
|
||||
let isDirectory: boolean = false;
|
||||
try {
|
||||
isDirectory = fileIo.statSync(dirPath).isDirectory();
|
||||
} catch (e) {
|
||||
console.error(JSON.stringify(e));
|
||||
}
|
||||
if (isDirectory) {
|
||||
fileIo.rmdirSync(dirPath);
|
||||
} else {
|
||||
fileIo.unlinkSync(dirPath);
|
||||
}
|
||||
}
|
||||
})
|
||||
setTimeout(() => { this.getCache() }, 200)
|
||||
LoadingDialog.dismiss()
|
||||
}
|
||||
|
||||
/**
|
||||
* 跳转客服
|
||||
* @param service
|
||||
*/
|
||||
contactWxService(service: WxServiceEntity) {
|
||||
let req = new WxOpenSdk.OpenCustomerServiceChatReq()
|
||||
req.corpId = service.corpid; // 企业ID
|
||||
req.url = service.address; // 客服URL
|
||||
WXApi.sendReq(AppUtil.getContext(), req)
|
||||
}
|
||||
|
||||
build() {
|
||||
Scroll(this.scroller) {
|
||||
Stack() {
|
||||
Image($r('app.media.ic_mine_top_bg'))
|
||||
.width('100%')
|
||||
.aspectRatio(0.8)
|
||||
.id('iv_top_bg')
|
||||
|
||||
Image(this.userinfo?.vip === 3 ? $r('app.media.ic_vip_bg2') : $r('app.media.ic_vip_bg1'))
|
||||
.width('100%')
|
||||
.aspectRatio(1.4)
|
||||
.visibility(this.userinfo?.vip !== 1 ? Visibility.Visible : Visibility.Hidden)
|
||||
.id('iv_vip_bg')
|
||||
|
||||
Column() {
|
||||
RelativeContainer() {
|
||||
Image(StrUtil.isNotEmpty(this.userinfo?.avater) ? this.userinfo?.avater : $r('app.media.ic_default_avatar'))
|
||||
.alignRules({
|
||||
left: { anchor: '__container__', align: HorizontalAlign.Start },
|
||||
right: { anchor: '__container__', align: HorizontalAlign.End }
|
||||
})
|
||||
.margin({ top: 20 })
|
||||
.padding(1)
|
||||
.borderRadius(45)
|
||||
.width(90)
|
||||
.height(90)
|
||||
.backgroundColor(Color.White)
|
||||
.id('iv_avatar')
|
||||
.onClick(() => {
|
||||
if (!LoginManager.isLogin()) {
|
||||
this.getUIContext().getRouter().pushUrl({ url: RouterUrls.LOGIN_PAGE, params: { from : 1 }}, router.RouterMode.Single)
|
||||
EventReportGlobalManager.eventReport(EventConstants.JUMP_TO_LOGIN, 'center')
|
||||
} else {
|
||||
this.getUIContext().getRouter().pushUrl({ url: RouterUrls.USER_SETTINGS_PAGE })
|
||||
}
|
||||
})
|
||||
|
||||
Text('Hi! 快登录')
|
||||
.fontColor(Color.White)
|
||||
.fontSize(12)
|
||||
.textAlign(TextAlign.Center)
|
||||
.alignRules({
|
||||
top: { anchor: '__container__', align: VerticalAlign.Top },
|
||||
left: { anchor: 'iv_avatar', align: HorizontalAlign.End }
|
||||
})
|
||||
.padding({
|
||||
left: 6,
|
||||
right: 6,
|
||||
})
|
||||
.margin({ left: -25 })
|
||||
.linearGradient({
|
||||
colors: [['#F62C6C', 0.0], ['#FC4F54', 1.0]],
|
||||
direction: GradientDirection.Right
|
||||
})
|
||||
.borderRadius({ topLeft: 6, topRight: 6, bottomRight: 6 })
|
||||
.width('auto')
|
||||
.height(24)
|
||||
.visibility(this.isLogin ? Visibility.None : Visibility.Visible)
|
||||
.id('tv_nologin_tip')
|
||||
|
||||
Text(this.userinfo?.ip_area)
|
||||
.fontColor(Color.White)
|
||||
.fontSize(12)
|
||||
.alignRules({
|
||||
top: { anchor: '__container__', align: VerticalAlign.Top },
|
||||
left: { anchor: 'iv_avatar', align: HorizontalAlign.End }
|
||||
})
|
||||
.padding({
|
||||
left: 6,
|
||||
right: 6,
|
||||
bottom: 4
|
||||
})
|
||||
.margin({ left: -25 })
|
||||
.width('auto')
|
||||
.height(21)
|
||||
.backgroundImage($r('app.media.ic_area_bg'))
|
||||
.backgroundImageSize({width: 'auto', height:21})
|
||||
.visibility(StrUtil.isNotEmpty(this.userinfo?.ip_area) && this.userinfo?.ip_area !== 'CN' && LoginManager.isLogin() ? Visibility.Visible : Visibility.None)
|
||||
.id('tv_area')
|
||||
|
||||
Text(StrUtil.isNotEmpty(this.userinfo?.name) ? this.userinfo?.name : '游客')
|
||||
.fontColor($r('app.color.color_90ffffff'))
|
||||
.fontSize(18)
|
||||
.fontWeight(FontWeight.Medium)
|
||||
.margin({ top: 12 })
|
||||
.alignRules({
|
||||
top: { anchor: 'iv_avatar', align: VerticalAlign.Bottom },
|
||||
left: { anchor: 'iv_avatar', align: HorizontalAlign.Start },
|
||||
right: { anchor: 'iv_avatar', align: HorizontalAlign.End }
|
||||
})
|
||||
.width('auto')
|
||||
.height('auto')
|
||||
.id('tv_username')
|
||||
|
||||
Row() {
|
||||
Text('ID:' + this.userinfo?.user_id)
|
||||
.fontColor($r('app.color.color_999999'))
|
||||
.fontSize(14)
|
||||
.id('tv_user_id')
|
||||
Image($r('app.media.ic_copy_id'))
|
||||
.margin({ left: 4 })
|
||||
.width(14)
|
||||
.height(14)
|
||||
}
|
||||
.alignRules({
|
||||
top: { anchor: 'tv_username', align: VerticalAlign.Bottom },
|
||||
left: { anchor: 'tv_username', align: HorizontalAlign.Start },
|
||||
right: { anchor: 'tv_username', align: HorizontalAlign.End }
|
||||
})
|
||||
.margin({ top: 4 })
|
||||
.width('auto')
|
||||
.id('layout_copy_id')
|
||||
.onClick(() => {
|
||||
if (StrUtil.isNotEmpty(this.userinfo?.user_id)) {
|
||||
PasteboardUtil.setDataTextSync(this.userinfo?.user_id!!)
|
||||
ToastUtils.show('复制成功')
|
||||
}
|
||||
})
|
||||
|
||||
Image($r('app.media.ic_scan')).width(24).height(24)
|
||||
.alignRules({
|
||||
top: {anchor: '__container__', align: VerticalAlign.Top},
|
||||
right: {anchor: '__container__', align: HorizontalAlign.End}
|
||||
})
|
||||
.margin({ right: 20 })
|
||||
.onClick(() => {
|
||||
try {
|
||||
ScanUtil.startScanForResult({ scanTypes: [scanCore.ScanType.QR_CODE], enableMultiMode: true, enableAlbum: true})
|
||||
.then((result) => {
|
||||
const code = result.originalValue
|
||||
const array = code.split('-')
|
||||
if (code.length === 36 && array.length === 5) {
|
||||
this.getUIContext().getRouter().pushUrl({ url: RouterUrls.QRCODE_LOGIN_PAGE, params: { code: code }})
|
||||
} else {
|
||||
ToastUtils.show('无效二维码')
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
ToastUtils.show('此设备不支持二维码扫描')
|
||||
})
|
||||
} catch (e) {
|
||||
ToastUtils.show('此设备不支持二维码扫描')
|
||||
}
|
||||
})
|
||||
}
|
||||
.margin({ top: 70 })
|
||||
.width('100%')
|
||||
.height(180)
|
||||
.id('layout_userinfo')
|
||||
|
||||
Row() {
|
||||
Column() {
|
||||
Text(FormatUtil.getFormatFileSize(NumberUtil.toNumber(this.userinfo?.month_download_size!!)))
|
||||
.fontColor($r('app.color.color_90ffffff'))
|
||||
.fontSize(18)
|
||||
.fontFamily('ddp500m')
|
||||
.id('tv_month_size')
|
||||
|
||||
Text('本月流量')
|
||||
.fontColor($r("app.color.color_50ffffff"))
|
||||
.fontSize(12)
|
||||
.margin({ top: 4 })
|
||||
}
|
||||
.layoutWeight(1)
|
||||
.onClick(() => {
|
||||
this.getUIContext().getRouter().pushUrl({url: RouterUrls.DOWNLOAD_HISTORY_PAGE})
|
||||
EventReportGlobalManager.eventReport(EventConstants.JUMP_TO_DOWNLOAD_HISTORY)
|
||||
})
|
||||
|
||||
Divider().vertical(true).color('#1affffff').strokeWidth(1).height(26)
|
||||
|
||||
Column() {
|
||||
Text(this.userinfo?.month_download_count)
|
||||
.fontColor($r('app.color.color_90ffffff'))
|
||||
.fontSize(18)
|
||||
.fontFamily('ddp500m')
|
||||
.id('tv_month_count')
|
||||
|
||||
Text('本月下载')
|
||||
.fontColor($r("app.color.color_50ffffff"))
|
||||
.fontSize(12)
|
||||
.margin({ top: 4 })
|
||||
}
|
||||
.layoutWeight(1)
|
||||
.onClick(() => {
|
||||
this.getUIContext().getRouter().pushUrl({url: RouterUrls.DOWNLOAD_HISTORY_PAGE})
|
||||
EventReportGlobalManager.eventReport(EventConstants.JUMP_TO_DOWNLOAD_HISTORY)
|
||||
})
|
||||
|
||||
Divider().vertical(true).color('#1affffff').strokeWidth(1).height(26)
|
||||
|
||||
Column() {
|
||||
Text('0')
|
||||
.fontColor($r('app.color.color_90ffffff'))
|
||||
.fontSize(18)
|
||||
.fontFamily('ddp500m')
|
||||
.id('tv_task_count')
|
||||
|
||||
Text('下载任务')
|
||||
.fontColor($r("app.color.color_50ffffff"))
|
||||
.fontSize(12)
|
||||
.margin({ top: 4 })
|
||||
}
|
||||
.layoutWeight(1)
|
||||
.visibility(Visibility.None)
|
||||
}
|
||||
.padding({ top: 9, bottom: 9 })
|
||||
.width('100%')
|
||||
.height('auto')
|
||||
.id('layout_download_info')
|
||||
|
||||
RelativeContainer() {
|
||||
Text(this.userinfo?.vip === 1 ? '素材魔方·会员' : this.userinfo?.vip_name)
|
||||
.fontColor($r('app.color.color_90ffffff'))
|
||||
.fontSize(18)
|
||||
.fontWeight(FontWeight.Bold)
|
||||
.fontFamily('almmsht')
|
||||
.id('tv_vip_name')
|
||||
.alignRules({
|
||||
bottom: { anchor: '__container__', align: VerticalAlign.Center }
|
||||
})
|
||||
|
||||
Text(this.userinfo?.vip === 1 ? '点击成为会员解锁所有功能' : this.userinfo?.vip === 2 ? this.userinfo.vip_expire + ' 会员到期' : '享受永久会员专属权益')
|
||||
.fontColor($r('app.color.color_60ffffff'))
|
||||
.fontSize(14)
|
||||
.margin({ top: 8 })
|
||||
.id('tv_vip_expire')
|
||||
.alignRules({
|
||||
top: { anchor: '__container__', align: VerticalAlign.Center }
|
||||
})
|
||||
|
||||
Button(this.userinfo?.vip === 1 ? '立即开通' : this.userinfo?.vip === 2 ? '立即续费' : '永久会员' , { type: ButtonType.Capsule, stateEffect: true })
|
||||
.fontColor('#291966')
|
||||
.fontSize(14)
|
||||
.fontWeight(FontWeight.Medium)
|
||||
.alignRules({
|
||||
top: { anchor: '__container__', align: VerticalAlign.Top },
|
||||
bottom: { anchor: '__container__', align: VerticalAlign.Bottom },
|
||||
right: { anchor: '__container__', align: HorizontalAlign.End }
|
||||
})
|
||||
.linearGradient({
|
||||
colors: [['#D4C4F9', 0.0], ['#E9E6F9', 1.0]],
|
||||
direction: GradientDirection.Top
|
||||
})
|
||||
.width(88)
|
||||
.height(32)
|
||||
.visibility(this.userinfo?.vip === 3 ? Visibility.None : Visibility.Visible)
|
||||
.id('btn_to_vip')
|
||||
.onClick(() => {
|
||||
this.getUIContext().getRouter().pushUrl({url: RouterUrls.VIP_PAGE, params: {origin: 'center'}})
|
||||
EventReportGlobalManager.eventReport(EventConstants.JUMP_TO_MEMBER_RECHARGE, 'center')
|
||||
})
|
||||
}
|
||||
.margin({ left: 16, top: 10, right: 16 })
|
||||
.padding({ left: 16, right: 16 })
|
||||
.backgroundImage($r('app.media.ic_mine_vip_bg'))
|
||||
.backgroundImageSize({ width: '100%' })
|
||||
.aspectRatio(4.28)
|
||||
.id('layout_vip_info')
|
||||
|
||||
Column() {
|
||||
TextItemView({ image: $r("app.media.ic_mine_icon1"), leftText: '免单挑战' })
|
||||
.height(60)
|
||||
.id('item_challenge')
|
||||
.visibility(/*this.showChallenge ? Visibility.Visible : Visibility.None*/Visibility.None)
|
||||
TextItemView({ image: $r("app.media.ic_mine_icon2"), leftText: '兑换钻石' })
|
||||
.height(60)
|
||||
.id('item_diamond')
|
||||
.onClick(() => {
|
||||
this.getUIContext().getRouter().pushUrl({url: RouterUrls.RECHARGE_DIAMOND_PAGE});
|
||||
EventReportGlobalManager.eventReport(EventConstants.JUMP_TO_RECHARGE_DIAMOND, 'center')
|
||||
})
|
||||
.visibility(this.diamondInfo && this.diamondInfo?.buy_total > 0 ? Visibility.Visible : Visibility.None)
|
||||
TextItemView({ image: $r("app.media.ic_mine_icon3"), leftText: '优惠券' }).height(60).id('item_coupon')
|
||||
.visibility(Visibility.None)
|
||||
TextItemView({ image: $r("app.media.ic_mine_icon4"), leftText: '分享APP' })
|
||||
.height(60)
|
||||
.id('item_share')
|
||||
.visibility(/*this.showShare ? Visibility.Visible : Visibility.None*/Visibility.None)
|
||||
TextItemView({ image: $r("app.media.ic_mine_icon5"), leftText: '联系客服' }).height(60).id('item_service')
|
||||
.onClick(() => {
|
||||
if (!WXApi.isWXAppInstalled()) {
|
||||
ToastUtils.show('未安装微信客户端,请先下载安装微信客户端');
|
||||
return;
|
||||
}
|
||||
this.viewModel.getWxService()
|
||||
})
|
||||
TextItemView({ image: $r("app.media.ic_mine_icon6"), leftText: '清除缓存', rightText: FileUtil.getFormatFileSize(this.cacheSize) }).height(60).id('item_cache')
|
||||
.onClick(() => {
|
||||
if (this.cacheSize > 0) {
|
||||
TipDialog.show(this.getUIContext(), {title: '提示', content: '确定清除缓存?', callback: {
|
||||
confirm: () => {
|
||||
this.clearCache()
|
||||
}
|
||||
}})
|
||||
}
|
||||
})
|
||||
TextItemView({ image: $r("app.media.ic_mine_icon7"), leftText: '设置' }).height(60).id('item_setting')
|
||||
.onClick(() => {
|
||||
this.getUIContext().getRouter().pushUrl({url: RouterUrls.SETTING_PAGE});
|
||||
EventReportGlobalManager.eventReport(EventConstants.JUMP_TO_SYSTEM_SETTING)
|
||||
})
|
||||
}
|
||||
.margin({ top: 16, left: 16, right: 16 })
|
||||
.backgroundColor('#1E1D24')
|
||||
.borderRadius(8)
|
||||
.id('layout_menu')
|
||||
|
||||
Blank().layoutWeight(1)
|
||||
}
|
||||
}
|
||||
.alignContent(Alignment.Top)
|
||||
}
|
||||
.padding({ bottom: 20 })
|
||||
.scrollBar(BarState.Off)
|
||||
.width('100%')
|
||||
.height('100%')
|
||||
.backgroundColor($r('app.color.window_background'))
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,436 @@
|
|||
import { RouterUrls } from '../../../../common/RouterUrls';
|
||||
import { VipMealEntity } from '../../../../entity/VipMealEntity'
|
||||
import { LoginManager } from '../../../../manager/LoginGlobalManager';
|
||||
import { ConfigManager } from '../../../../manager/UserConfigManager';
|
||||
import { ToastUtils } from '../../../../utils/ToastUtils';
|
||||
import { TitleBar } from '../../../../view/TitleBar'
|
||||
import { LevelMode, router } from '@kit.ArkUI';
|
||||
import { OnWXResp, WXApi, WXEventHandler } from '../../../../utils/wechat/WXApiEventHandlerImpl';
|
||||
import { PayOrderEntity } from '../../../../entity/OrderPayEntity';
|
||||
import { PayUtils } from '../../../../utils/PayUtils';
|
||||
import { BusinessError } from '@kit.BasicServicesKit';
|
||||
import { NumberUtil, ObjectUtil, StrUtil } from '@pura/harmony-utils';
|
||||
import { ErrCode, PayResp } from '@tencent/wechat_open_sdk';
|
||||
import { DiamondViewModel } from '../../../../viewModel/DiamondViewModel';
|
||||
import { LoadingDialog } from '../../../../dialog/LoadingDialog';
|
||||
import { DiamondDetailEntity } from '../../../../entity/DiamondDetailEntity';
|
||||
import { DiamondItemView } from '../../../../view/DiamondItemView';
|
||||
import { DiamondRuleDialog } from '../../../../dialog/DiamondRuleDialog';
|
||||
import { EventReportGlobalManager } from '../../../../manager/EventReportGlobalManager';
|
||||
import { EventConstants } from '../../../../common/EventConstants';
|
||||
import { OrderEntity } from '../../../../entity/OrderEntity';
|
||||
import { TipDialog } from '../../../../dialog/TipDialog';
|
||||
|
||||
@Entry
|
||||
@ComponentV2
|
||||
struct DiamondPage {
|
||||
@Local origin: string = 'center';
|
||||
@Local diamondInfo?: DiamondDetailEntity
|
||||
@Local diamondList: Array<VipMealEntity> = [];
|
||||
@Local vipMeal?: VipMealEntity;
|
||||
@Local isAgree: boolean = false;
|
||||
@Local payType: number = 0; //0微信支付 1支付宝支付
|
||||
@Local totalPrice: number = 0;
|
||||
|
||||
showQueryTip: boolean = false //是否显示支付状态查询提示
|
||||
|
||||
diamondRuleDialogController?: CustomDialogController | null;
|
||||
|
||||
viewModel: DiamondViewModel = new DiamondViewModel(this.getUIContext());
|
||||
orderEntity?: PayOrderEntity;
|
||||
|
||||
//从微信返回的回调
|
||||
onWXResp: OnWXResp = (resp) => {
|
||||
//微信返回的数据
|
||||
if (resp instanceof PayResp) {
|
||||
const payResult = JSON.stringify(resp ?? {}, null, 2);
|
||||
const errCode = JSON.parse(payResult).errCode as number;
|
||||
if (errCode === ErrCode.ERR_OK) {
|
||||
this.viewModel.getOrderInfo(this.orderEntity!!.orderId)
|
||||
} else {
|
||||
ToastUtils.show(JSON.parse(payResult).errStr);
|
||||
EventReportGlobalManager.eventReport(
|
||||
EventConstants.PAY_CANCEL,
|
||||
`weixin:${this.origin}`, `{type:\"diamond\", orderId:${this.orderEntity?.orderId}, meal:${JSON.stringify(this.diamondInfo)}}`
|
||||
)
|
||||
}
|
||||
}
|
||||
LoadingDialog.dismiss();
|
||||
}
|
||||
|
||||
@Monitor('viewModel.diamondInfo')
|
||||
onDiamondInfoChange(monitor: IMonitor) {
|
||||
this.diamondInfo = monitor.value()?.now as DiamondDetailEntity;
|
||||
}
|
||||
|
||||
@Monitor('viewModel.goodsList')
|
||||
onGoodsListChange(monitor: IMonitor) {
|
||||
const list = monitor.value()?.now as Array<VipMealEntity>;
|
||||
this.diamondList = list.map(item => ObjectUtil.assign(new VipMealEntity(), item) as VipMealEntity);
|
||||
if (this.diamondList.length > 0) {
|
||||
this.vipMeal = this.diamondList.find(item => item.checked === true);
|
||||
if (!this.vipMeal) {
|
||||
this.vipMeal = this.diamondList[0];
|
||||
}
|
||||
if (this.vipMeal) {
|
||||
this.totalPrice = NumberUtil.toNumber(this.vipMeal.price);
|
||||
this.releasePayType();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Monitor('viewModel.payOrderEntity')
|
||||
onPayOrderChange(monitor: IMonitor) {
|
||||
const payOrderEntity = monitor.value()?.now as PayOrderEntity;
|
||||
this.orderEntity = payOrderEntity;
|
||||
if (this.payType === 0) {
|
||||
if (StrUtil.isNotEmpty(this.vipMeal?.weixinMpOriId)) {
|
||||
PayUtils.toWXMPPay(payOrderEntity.outTradeNo, this.vipMeal!!.weixinMpOriId)
|
||||
this.showQueryTip = true
|
||||
} else {
|
||||
PayUtils.toWXPay(payOrderEntity);
|
||||
}
|
||||
} else {
|
||||
PayUtils.toAliPay(payOrderEntity.payParam)
|
||||
.then((result) => {
|
||||
this.parseAlipayResult(result);
|
||||
})
|
||||
.catch((error: BusinessError) => {
|
||||
console.log(error.message);
|
||||
ToastUtils.show('支付失败');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Monitor('viewModel.orderInfoEntity')
|
||||
onOrderInfoChange(monitor: IMonitor) {
|
||||
const orderEntity = monitor.value()?.now as OrderEntity;
|
||||
if (orderEntity.status == "2") {
|
||||
ToastUtils.show('支付成功');
|
||||
EventReportGlobalManager.eventReport(
|
||||
EventConstants.PAY_SUCCESS,
|
||||
`alipay:${this.origin}`, `{type:\"diamond\", orderId:${this.orderEntity?.orderId}, meal:${JSON.stringify(this.diamondInfo)}}`
|
||||
)
|
||||
this.viewModel.getDiamondInfo()
|
||||
}
|
||||
}
|
||||
|
||||
aboutToAppear() {
|
||||
WXEventHandler.registerOnWXRespCallback(this.onWXResp)
|
||||
this.initParams();
|
||||
this.viewModel.getDiamondInfo()
|
||||
this.viewModel.mealList();
|
||||
}
|
||||
|
||||
aboutToDisappear() {
|
||||
WXEventHandler.unregisterOnWXRespCallback(this.onWXResp)
|
||||
this.diamondRuleDialogController = null
|
||||
this.viewModel.cancelInterval()
|
||||
}
|
||||
|
||||
onPageShow(): void {
|
||||
if (this.showQueryTip) {
|
||||
TipDialog.show(this.getUIContext(), { title: '温馨提示', content: '是否已完成支付', leftText: '未支付', rightText: '已支付', callback: {
|
||||
confirm: () => {
|
||||
this.viewModel.getOrderInfo(this.orderEntity!!.orderId)
|
||||
}
|
||||
} }, false)
|
||||
this.showQueryTip = false
|
||||
}
|
||||
}
|
||||
|
||||
initParams() {
|
||||
const params = this.getUIContext().getRouter().getParams() as Record<string, Object>;
|
||||
if (params) {
|
||||
this.origin = params.origin as string;
|
||||
}
|
||||
}
|
||||
|
||||
createOrder() {
|
||||
if (!ConfigManager.isNoLoginPayEnable() && !LoginManager.isLogin()) {
|
||||
ToastUtils.show('请登录后支付');
|
||||
this.getUIContext().getRouter().pushUrl({ url: RouterUrls.LOGIN_PAGE, params: { from: 1 } }, router.RouterMode.Single);
|
||||
return;
|
||||
}
|
||||
if (this.payType === 0 && !WXApi.isWXAppInstalled()) {
|
||||
ToastUtils.show('请先下载安装微信客户端');
|
||||
return;
|
||||
}
|
||||
if (this.payType === 0) {
|
||||
if (StrUtil.isNotEmpty(this.vipMeal!!.weixinMpOriId)) {
|
||||
this.viewModel.createOrder(this.vipMeal?.goods_id!!, 'combo', this.origin, '');
|
||||
} else {
|
||||
this.viewModel.createOrder(this.vipMeal?.goods_id!!, 'weixin', this.origin, '');
|
||||
}
|
||||
} else {
|
||||
this.viewModel.createOrder(this.vipMeal?.goods_id!!, 'alipay', this.origin, '');
|
||||
}
|
||||
}
|
||||
|
||||
parseAlipayResult(result: Map<string, string>) {
|
||||
const resultStatus = result.get('resultStatus');
|
||||
if (resultStatus === '9000') {
|
||||
this.viewModel.getOrderInfo(this.orderEntity!!.orderId)
|
||||
} else if (resultStatus === '6001') {
|
||||
ToastUtils.show('支付取消');
|
||||
EventReportGlobalManager.eventReport(
|
||||
EventConstants.PAY_CANCEL,
|
||||
`alipay:${this.origin}`, `{type:\"diamond\", orderId:${this.orderEntity?.orderId}, meal:${JSON.stringify(this.diamondInfo)}}`
|
||||
)
|
||||
} else {
|
||||
ToastUtils.show('支付失败');
|
||||
EventReportGlobalManager.eventReport(
|
||||
EventConstants.ERROR_CLIENT_ALIPAY_ERR,
|
||||
`{orderId:${this.orderEntity?.orderId}, meal:${JSON.stringify(this.diamondInfo)}}`, resultStatus
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
releasePayType() {
|
||||
if (this.vipMeal?.pay_type.startsWith('alipay')) {
|
||||
this.payType = 1;
|
||||
} else if (this.vipMeal?.pay_type.startsWith('weixin')) {
|
||||
this.payType = 0;
|
||||
}
|
||||
}
|
||||
|
||||
showRuleDialog() {
|
||||
this.diamondRuleDialogController = new CustomDialogController({
|
||||
builder: DiamondRuleDialog(),
|
||||
width: '100%',
|
||||
cornerRadius: 20,
|
||||
maskColor: '#CC000000',
|
||||
levelMode: LevelMode.EMBEDDED,
|
||||
backgroundBlurStyle: BlurStyle.NONE,
|
||||
alignment: DialogAlignment.Bottom
|
||||
})
|
||||
this.diamondRuleDialogController.open();
|
||||
}
|
||||
|
||||
build() {
|
||||
RelativeContainer() {
|
||||
Image($r('app.media.ic_diamond_top_bg')).width('100%').aspectRatio(1.524)
|
||||
|
||||
Column() {
|
||||
Scroll() {
|
||||
Column() {
|
||||
RelativeContainer() {
|
||||
Image(LoginManager.getUserInfo()?.avater)
|
||||
.width(46)
|
||||
.height(46)
|
||||
.borderRadius(25)
|
||||
.margin({ left: 7 })
|
||||
.id('iv_avatar')
|
||||
Text(LoginManager.getUserInfo()?.vip === 1 ? '非会员' : LoginManager.getUserInfo()?.vip === 3 ? '终身会员' : LoginManager.getUserInfo()?.vip_name)
|
||||
.fontColor('#4F59FF')
|
||||
.fontSize(12)
|
||||
.width('auto')
|
||||
.height(22)
|
||||
.padding({ left: 6, right: 6 })
|
||||
.borderRadius(25)
|
||||
.linearGradient({
|
||||
colors: [['#EFF0FB', 0.0], ['#ABC3FF', 1.0]],
|
||||
direction: GradientDirection.Right
|
||||
})
|
||||
.alignRules({
|
||||
top: { anchor: 'iv_avatar', align: VerticalAlign.Bottom },
|
||||
left: { anchor: 'iv_avatar', align: HorizontalAlign.Start },
|
||||
right: { anchor: 'iv_avatar', align: HorizontalAlign.End }
|
||||
})
|
||||
.margin({ top: -9 })
|
||||
Text(LoginManager.getUserInfo()?.name)
|
||||
.fontColor('#FFF4D0')
|
||||
.fontSize(15)
|
||||
.alignRules({
|
||||
top: { anchor: 'iv_avatar', align: VerticalAlign.Top },
|
||||
bottom: { anchor: 'iv_avatar', align: VerticalAlign.Center },
|
||||
left: { anchor: 'iv_avatar', align: HorizontalAlign.End }
|
||||
})
|
||||
.margin({ left: 16 })
|
||||
.id('tv_username')
|
||||
Text('ID:' + LoginManager.getUserInfo()?.user_id).fontColor('#FFF4D0').fontSize(12)
|
||||
.alignRules({
|
||||
left: { anchor: 'tv_username', align: HorizontalAlign.Start },
|
||||
top: { anchor: 'iv_avatar', align: VerticalAlign.Center },
|
||||
bottom: { anchor: 'iv_avatar', align: VerticalAlign.Bottom }
|
||||
})
|
||||
|
||||
Text() {
|
||||
Span('剩余总次数 ')
|
||||
Span(`${this.diamondInfo?.remain}`).fontSize(22).fontFamily('ddp500m')
|
||||
Span(' 次')
|
||||
}.fontColor('#FFF4D0').fontSize(12)
|
||||
.alignRules({
|
||||
top: { anchor: 'iv_avatar', align: VerticalAlign.Bottom },
|
||||
right: { anchor: '__container__', align: HorizontalAlign.End }
|
||||
})
|
||||
}
|
||||
.aspectRatio(2.584)
|
||||
.margin({ top: 120, left: 26, right: 26 })
|
||||
.padding({ top: 16, left: 12, right: 12 })
|
||||
.backgroundImage($r('app.media.ic_diamond_vip_bg1'))
|
||||
.backgroundImageSize({ width: '100%' })
|
||||
|
||||
Image($r('app.media.ic_diamond_vip_bg2')).width('100%').aspectRatio(4.866)
|
||||
.margin({ top: -30 })
|
||||
|
||||
Column() {
|
||||
Text('钻石消耗数量').fontColor('#8F4A2A').fontSize(16).fontWeight(FontWeight.Medium).margin({ top: 4 })
|
||||
|
||||
Column() {
|
||||
Row() {
|
||||
Text('本月固定钻石数量').fontColor($r('app.color.color_1a1a1a')).fontSize(14)
|
||||
Text('每月重置')
|
||||
.textAlign(TextAlign.Center)
|
||||
.fontColor('#FFA61E')
|
||||
.fontSize(12)
|
||||
.height(18)
|
||||
.padding({ left: 4, right: 4 })
|
||||
.borderWidth(1)
|
||||
.borderRadius(4)
|
||||
.borderColor('#FFA61E')
|
||||
.margin({left: 8})
|
||||
Blank().layoutWeight(1)
|
||||
Text() {
|
||||
Span(`${this.diamondInfo?.month_used}`).fontColor('#FFA61E').fontSize(20).fontFamily('ddp500m')
|
||||
Span(`/${this.diamondInfo?.month_total}`).fontColor($r('app.color.color_1a1a1a')).fontSize(14)
|
||||
}
|
||||
}
|
||||
|
||||
Progress({ value: this.diamondInfo?.month_used, total: this.diamondInfo?.month_total, type: ProgressType.Linear })
|
||||
.width('100%')
|
||||
.height(10)
|
||||
.style({ strokeWidth: 10, strokeRadius: 5 })
|
||||
.color('#FF9026')
|
||||
.borderRadius(5)
|
||||
.margin({top: 16})
|
||||
|
||||
Row() {
|
||||
Text('兑换钻石数量').fontColor($r('app.color.color_1a1a1a')).fontSize(14)
|
||||
Text('用完即止')
|
||||
.textAlign(TextAlign.Center)
|
||||
.fontColor('#FFA61E')
|
||||
.fontSize(12)
|
||||
.height(18)
|
||||
.padding({ left: 4, right: 4 })
|
||||
.borderWidth(1)
|
||||
.borderRadius(4)
|
||||
.borderColor('#FFA61E')
|
||||
.margin({left: 8})
|
||||
Blank().layoutWeight(1)
|
||||
Text() {
|
||||
Span(`${this.diamondInfo?.buy_used}`).fontColor('#FFA61E').fontSize(20).fontFamily('ddp500m')
|
||||
Span(`/${this.diamondInfo?.buy_total}`).fontColor($r('app.color.color_1a1a1a')).fontSize(14)
|
||||
}
|
||||
}.margin({top: 24})
|
||||
|
||||
Progress({ value: this.diamondInfo?.buy_used, total: this.diamondInfo?.buy_total, type: ProgressType.Linear })
|
||||
.width('100%')
|
||||
.height(10)
|
||||
.style({ strokeWidth: 10, strokeRadius: 5 })
|
||||
.color('#FF9026')
|
||||
.borderRadius(5)
|
||||
.margin({top: 16})
|
||||
}
|
||||
.backgroundColor(Color.White)
|
||||
.borderRadius(8)
|
||||
.margin({ top: 10 })
|
||||
.padding({
|
||||
left: 12,
|
||||
top: 16,
|
||||
right: 12,
|
||||
bottom: 16
|
||||
})
|
||||
}
|
||||
.alignItems(HorizontalAlign.Start)
|
||||
.height('auto')
|
||||
.padding(10)
|
||||
.margin({ top: -45, left: 16, right: 16 })
|
||||
.backgroundImage($r('app.media.ic_diamond_count_bg'))
|
||||
.backgroundImageSize({ width: '100%' })
|
||||
.borderRadius(10)
|
||||
.clip(true)
|
||||
|
||||
Text('钻石套餐').fontColor($r('app.color.color_1a1a1a')).fontSize(16).fontWeight(FontWeight.Medium).margin({left: 16, top: 26})
|
||||
.alignSelf(ItemAlign.Start)
|
||||
|
||||
List({space: 12}) {
|
||||
ForEach(this.diamondList, (item: VipMealEntity) => {
|
||||
ListItem() {
|
||||
DiamondItemView({ goodInfo: item })
|
||||
}
|
||||
.onClick(() => {
|
||||
let goodsInfo = this.diamondList.find(item => item.checked) as VipMealEntity
|
||||
goodsInfo.checked = false
|
||||
item.checked = true
|
||||
this.vipMeal = item
|
||||
this.releasePayType()
|
||||
})
|
||||
})
|
||||
}
|
||||
.width('auto')
|
||||
.height('auto')
|
||||
.margin({left: 16, top: 14, right: 16, bottom: 15 })
|
||||
}
|
||||
}
|
||||
.layoutWeight(1)
|
||||
.scrollBar(BarState.Off)
|
||||
|
||||
Column() {
|
||||
Row() {
|
||||
Row() {
|
||||
Image($r('app.media.ic_wx_pay3')).width(26).height(26)
|
||||
Text('微信').fontColor($r('app.color.color_1a1a1a')).fontSize(15).margin({left: 10})
|
||||
Blank().layoutWeight(1)
|
||||
Image(this.payType === 0 ? $r('app.media.ic_pay_true2') : $r('app.media.ic_pay_false2')).width(18).height(18)
|
||||
}.layoutWeight(1)
|
||||
.visibility(this.vipMeal?.pay_type.includes('weixin') ? Visibility.Visible : Visibility.None)
|
||||
.onClick(() => {
|
||||
this.payType = 0;
|
||||
})
|
||||
Divider().width(1).strokeWidth(1).height(26).color('#EEEEEE').margin({left: 20, right: 20})
|
||||
Row() {
|
||||
Image($r('app.media.ic_ali_pay3')).width(26).height(26)
|
||||
Text('支付宝').fontColor($r('app.color.color_1a1a1a')).fontSize(15).margin({left: 10})
|
||||
Blank().layoutWeight(1)
|
||||
Image(this.payType === 1 ? $r('app.media.ic_pay_true2') : $r('app.media.ic_pay_false2')).width(18).height(18)
|
||||
}.layoutWeight(1)
|
||||
.visibility(this.vipMeal?.pay_type.includes('alipay') ? Visibility.Visible : Visibility.None)
|
||||
.onClick(() => {
|
||||
this.payType = 1;
|
||||
})
|
||||
}
|
||||
|
||||
Button('立即支付', {type: ButtonType.Capsule, stateEffect: true})
|
||||
.width('100%')
|
||||
.height(46)
|
||||
.fontColor(Color.White)
|
||||
.fontSize(16)
|
||||
.fontWeight(FontWeight.Medium)
|
||||
.backgroundColor('#FF8D1B')
|
||||
.margin({top: 17})
|
||||
.onClick(() => {
|
||||
if (this.vipMeal) {
|
||||
this.createOrder()
|
||||
}
|
||||
})
|
||||
}.backgroundColor(Color.White)
|
||||
.padding({left: 16, top: 8, right: 16, bottom: 30})
|
||||
.shadow({radius: 6, offsetY: -2, color: '#1d000000'})
|
||||
}
|
||||
|
||||
TitleBar({
|
||||
title: '素材加油站',
|
||||
isDark: false,
|
||||
rightText: '规则说明',
|
||||
rightColor: '#6F3A21',
|
||||
onRightClick: () => {
|
||||
this.showRuleDialog()
|
||||
}
|
||||
}).id('titleBar')
|
||||
}
|
||||
.width('100%')
|
||||
.height('100%')
|
||||
.backgroundColor(Color.White)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,143 @@
|
|||
import { AppUtil, DateUtil } from "@pura/harmony-utils";
|
||||
import { EventConstants } from "../../../../common/EventConstants";
|
||||
import { DownloadHistoryEntity } from "../../../../entity/DownloadHistoryEntity";
|
||||
import { DownloadHistoryItemView } from "../../../../view/DownloadHistoryItemView";
|
||||
import { EmptyView, PageStatus } from "../../../../view/EmptyView";
|
||||
import { DownloadHistoryViewModel } from "../../../../viewModel/DownloadHistoryViewModel";
|
||||
|
||||
@ComponentV2
|
||||
export struct DownloadHistoryItemPage {
|
||||
@Local isRefreshing: boolean = false;
|
||||
@Local isLoading: boolean = false;
|
||||
@Local refreshOffset: number = 0;
|
||||
@Local refreshState: RefreshStatus = RefreshStatus.Inactive;
|
||||
@Local historyList: Array<DownloadHistoryEntity> = []
|
||||
|
||||
@Param type: number = 0
|
||||
|
||||
viewModel: DownloadHistoryViewModel = new DownloadHistoryViewModel(this.getUIContext())
|
||||
page: number = 1
|
||||
canLoadMore: boolean = false
|
||||
|
||||
@Monitor('viewModel.getHistory')
|
||||
onGetDownloadHistory(monitor: IMonitor) {
|
||||
const list = monitor.value()?.now as Array<DownloadHistoryEntity>
|
||||
if (this.page === 1) {
|
||||
this.historyList = list
|
||||
this.isRefreshing = false
|
||||
} else {
|
||||
this.historyList = this.historyList.concat(list)
|
||||
this.isLoading = false
|
||||
}
|
||||
this.canLoadMore = list.length === 20
|
||||
}
|
||||
|
||||
aboutToAppear(): void {
|
||||
this.isRefreshing = true
|
||||
this.initObserver()
|
||||
}
|
||||
|
||||
aboutToDisappear(): void {
|
||||
AppUtil.getContext().eventHub.off(EventConstants.DownloadHistoryRefreshEvent)
|
||||
}
|
||||
|
||||
initObserver() {
|
||||
AppUtil.getContext().eventHub.on(EventConstants.DownloadHistoryRefreshEvent, (type: number) => {
|
||||
if (type === this.type) {
|
||||
this.isRefreshing = true
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
getStartTime(): number {
|
||||
let nowDate = new Date(DateUtil.getNowYear(), DateUtil.getNowMonth() - 1, 1)
|
||||
let lastDate = new Date(DateUtil.getNowYear(), DateUtil.getNowMonth() - 2, 1)
|
||||
if (this.type === 0) {
|
||||
return Math.trunc(nowDate.getTime() / 1000)
|
||||
} else {
|
||||
return Math.trunc(lastDate.getTime() / 1000)
|
||||
}
|
||||
}
|
||||
|
||||
getEndTime(): number {
|
||||
let nowDate = new Date(DateUtil.getNowYear(), DateUtil.getNowMonth(), 1)
|
||||
let lastDate = new Date(DateUtil.getNowYear(), DateUtil.getNowMonth() - 1, 1)
|
||||
if (this.type === 0) {
|
||||
return Math.trunc(nowDate.getTime() / 1000)
|
||||
} else {
|
||||
return Math.trunc(lastDate.getTime() / 1000)
|
||||
}
|
||||
}
|
||||
|
||||
build() {
|
||||
Stack() {
|
||||
Refresh({refreshing: this.isRefreshing, builder: this.refreshBuilder()}) {
|
||||
List({space: 12}) {
|
||||
ForEach(this.historyList, (item: DownloadHistoryEntity) => {
|
||||
ListItem() {
|
||||
DownloadHistoryItemView({ historyEntity: item })
|
||||
}
|
||||
})
|
||||
ListItem() {
|
||||
this.footer();
|
||||
}
|
||||
}
|
||||
.width('100%')
|
||||
.height('100%')
|
||||
.onScrollIndex((start: number, end: number) => {
|
||||
// 当达到列表末尾时,触发新数据加载。
|
||||
if (this.canLoadMore && end >= this.historyList.length - 1) {
|
||||
this.page++
|
||||
this.isLoading = true;
|
||||
this.viewModel.getHistoryList(`${this.page}`, `${this.getStartTime()}`, `${this.getEndTime()}`)
|
||||
}
|
||||
})
|
||||
}
|
||||
.onRefreshing(() => {
|
||||
this.page = 1
|
||||
this.isRefreshing = true
|
||||
this.viewModel.getHistoryList(`${this.page}`, `${this.getStartTime()}`, `${this.getEndTime()}`)
|
||||
})
|
||||
.refreshOffset(50)
|
||||
.pullToRefresh(true)
|
||||
.visibility(this.historyList.length > 0 ? Visibility.Visible : Visibility.None)
|
||||
|
||||
EmptyView({
|
||||
status: this.historyList.length > 0 ? PageStatus.GONE : PageStatus.NO_DATA,
|
||||
noDataImage: $r('app.media.ic_empty_data'),
|
||||
noDataText: '暂无数据'
|
||||
})
|
||||
}
|
||||
.width('100%')
|
||||
.height('100%')
|
||||
}
|
||||
|
||||
@Builder
|
||||
refreshBuilder() {
|
||||
Stack({ alignContent: Alignment.Bottom }) {
|
||||
// 可以通过刷新状态控制是否存在Progress组件。
|
||||
// 当刷新状态处于下拉中或刷新中状态时Progress组件才存在。
|
||||
if (this.refreshState != RefreshStatus.Inactive && this.refreshState != RefreshStatus.Done) {
|
||||
Progress({ value: this.refreshOffset, total: 50, type: ProgressType.Ring })
|
||||
.width(32).height(32)
|
||||
.style({ status: this.isRefreshing ? ProgressStatus.LOADING : ProgressStatus.PROGRESSING })
|
||||
.margin(10)
|
||||
}
|
||||
}
|
||||
.clip(true)
|
||||
.height("100%")
|
||||
.width("100%")
|
||||
}
|
||||
|
||||
@Builder
|
||||
footer() {
|
||||
Row() {
|
||||
LoadingProgress().height(32).width(48)
|
||||
Text("加载中")
|
||||
}.width("100%")
|
||||
.height(50)
|
||||
.justifyContent(FlexAlign.Center)
|
||||
// 当不处于加载中状态时隐藏组件。
|
||||
.visibility(this.isLoading ? Visibility.Visible : Visibility.Hidden)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,102 @@
|
|||
import { AppUtil, DateUtil } from '@pura/harmony-utils';
|
||||
import { EventConstants } from '../../../../common/EventConstants';
|
||||
import { TipDialog } from '../../../../dialog/TipDialog';
|
||||
import { TitleBar } from '../../../../view/TitleBar';
|
||||
import { DownloadHistoryViewModel } from '../../../../viewModel/DownloadHistoryViewModel';
|
||||
import { DownloadHistoryItemPage } from './DownloadHistoryItemPage';
|
||||
|
||||
@Entry
|
||||
@ComponentV2
|
||||
struct DownloadHistory {
|
||||
@Local currentIndex: number = 0;
|
||||
tabController: TabsController = new TabsController();
|
||||
titles: Array<string> = ['本月', '上月'];
|
||||
|
||||
viewModel: DownloadHistoryViewModel = new DownloadHistoryViewModel(this.getUIContext())
|
||||
|
||||
@Monitor('viewModel.deleteHistory')
|
||||
onDeleteDownloadHistory(monitor: IMonitor) {
|
||||
AppUtil.getContext().eventHub.emit(EventConstants.DownloadHistoryRefreshEvent, this.currentIndex)
|
||||
}
|
||||
|
||||
getStartTime(): number {
|
||||
let nowDate = new Date(DateUtil.getNowYear(), DateUtil.getNowMonth() - 1, 1)
|
||||
let lastDate = new Date(DateUtil.getNowYear(), DateUtil.getNowMonth() - 2, 1)
|
||||
if (this.currentIndex === 0) {
|
||||
return Math.trunc(nowDate.getTime() / 1000)
|
||||
} else {
|
||||
return Math.trunc(lastDate.getTime() / 1000)
|
||||
}
|
||||
}
|
||||
|
||||
getEndTime(): number {
|
||||
let nowDate = new Date(DateUtil.getNowYear(), DateUtil.getNowMonth(), 1)
|
||||
let lastDate = new Date(DateUtil.getNowYear(), DateUtil.getNowMonth() - 1, 1)
|
||||
if (this.currentIndex === 0) {
|
||||
return Math.trunc(nowDate.getTime() / 1000)
|
||||
} else {
|
||||
return Math.trunc(lastDate.getTime() / 1000)
|
||||
}
|
||||
}
|
||||
|
||||
build() {
|
||||
Column() {
|
||||
TitleBar({ title: '本月下载' })
|
||||
|
||||
Stack({ alignContent: Alignment.TopStart }) {
|
||||
Tabs({ barPosition: BarPosition.Start, controller: this.tabController }) {
|
||||
TabContent() {
|
||||
DownloadHistoryItemPage({type: 0})
|
||||
}
|
||||
|
||||
TabContent() {
|
||||
DownloadHistoryItemPage({type: 1})
|
||||
}
|
||||
}
|
||||
.scrollable(false)
|
||||
/*.onSelected((index: number) => {
|
||||
this.currentIndex = index;
|
||||
})*/
|
||||
|
||||
Row({ space: 40 }) {
|
||||
ForEach(this.titles, (title: string, index) => {
|
||||
this.tab(title, index);
|
||||
})
|
||||
Blank().layoutWeight(1)
|
||||
Row() {
|
||||
Image($r('app.media.ic_clear_record')).width(16).height(16)
|
||||
Text('全部清空').fontColor($r('app.color.color_80ffffff')).fontSize(12).margin({ left: 4 })
|
||||
}
|
||||
.onClick(() => {
|
||||
TipDialog.show(this.getUIContext(), {title: '提示', content: '确定清空记录?', callback: {
|
||||
confirm: () => {
|
||||
this.viewModel.deleteHistoryList(`${this.getStartTime()}`, `${this.getEndTime()}`)
|
||||
}
|
||||
}})
|
||||
})
|
||||
}.padding({ left: 16, right: 16 })
|
||||
.margin({ top: 10 })
|
||||
}.layoutWeight(1)
|
||||
}
|
||||
.width('100%')
|
||||
.height('100%')
|
||||
.backgroundColor($r('app.color.window_background'))
|
||||
}
|
||||
|
||||
@Builder
|
||||
tab(tabName: string, tabIndex: number) {
|
||||
Row() {
|
||||
Text(tabName)
|
||||
.fontSize(this.currentIndex === tabIndex ? 17 : 14)
|
||||
.fontWeight(this.currentIndex === tabIndex ? FontWeight.Medium : FontWeight.Regular)
|
||||
.lineHeight(24)
|
||||
.fontColor(tabIndex === this.currentIndex ? $r("app.color.color_466afd") : $r('app.color.color_50ffffff'))
|
||||
}
|
||||
.width('auto')
|
||||
.height('auto')
|
||||
.onClick(() => {
|
||||
this.tabController.changeIndex(tabIndex);
|
||||
this.currentIndex = tabIndex;
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,103 @@
|
|||
import { AppUtil } from '@pura/harmony-utils'
|
||||
import { EventConstants } from '../../../../common/EventConstants'
|
||||
import { RouterUrls } from '../../../../common/RouterUrls'
|
||||
import { TipDialog } from '../../../../dialog/TipDialog'
|
||||
import { LoginManager } from '../../../../manager/LoginGlobalManager'
|
||||
import { ConfigManager } from '../../../../manager/UserConfigManager'
|
||||
import { ToastUtils } from '../../../../utils/ToastUtils'
|
||||
import { TextItemChildView } from '../../../../view/TextItemChildView'
|
||||
import { TitleBar } from '../../../../view/TitleBar'
|
||||
import { SettingsViewModel } from '../../../../viewModel/SettingsViewModel'
|
||||
import { router } from '@kit.ArkUI'
|
||||
import { EventReportGlobalManager } from '../../../../manager/EventReportGlobalManager'
|
||||
|
||||
@Entry
|
||||
@ComponentV2
|
||||
struct SettingsPage {
|
||||
viewModel: SettingsViewModel = new SettingsViewModel(this.getUIContext());
|
||||
|
||||
@Monitor('viewModel.destroy')
|
||||
onDestroy(monitor: IMonitor) {
|
||||
EventReportGlobalManager.eventReport(EventConstants.CANCEL_ACCOUNT)
|
||||
this.logout();
|
||||
ToastUtils.show('账户已注销');
|
||||
}
|
||||
|
||||
logout() {
|
||||
LoginManager.saveLastUserInfo(LoginManager.getUserInfo()!!);
|
||||
ConfigManager.saveBindWxPlaybackHelper(false);
|
||||
ConfigManager.saveBindWxVideoHelper(false);
|
||||
LoginManager.logout();
|
||||
AppUtil.getContext().eventHub.emit(EventConstants.LogoutSuccessEvent);
|
||||
this.getUIContext().getRouter().replaceUrl({ url: RouterUrls.LOGIN_PAGE }, router.RouterMode.Single);
|
||||
}
|
||||
|
||||
build() {
|
||||
Column() {
|
||||
TitleBar({ title: '设置' }).width('100%')
|
||||
Scroll() {
|
||||
Column() {
|
||||
TextItemChildView({ text: '意见反馈' }).height(60).margin({ left: 16, right: 16 })
|
||||
.onClick(() => {
|
||||
this.getUIContext().getRouter().pushUrl({url: RouterUrls.FEEDBACK_PAGE})
|
||||
EventReportGlobalManager.eventReport(EventConstants.JUMP_TO_FEEDBACK, 'center')
|
||||
})
|
||||
TextItemChildView({ text: '账号绑定' }).height(60).margin({ left: 16, right: 16 })
|
||||
.onClick(() => {
|
||||
this.getUIContext().getRouter().pushUrl({url: RouterUrls.BIND_ACCOUNT_PAGE});
|
||||
EventReportGlobalManager.eventReport(EventConstants.JUMP_TO_ACCOUNT_BIND)
|
||||
})
|
||||
TextItemChildView({ text: '账号管理' }).height(60).margin({ left: 16, right: 16 })
|
||||
.onClick(() => {
|
||||
this.getUIContext().getRouter().pushUrl({url: RouterUrls.MANAGE_ACCOUNT_PAGE});
|
||||
EventReportGlobalManager.eventReport(EventConstants.JUMP_TO_ACCOUNT_MANAGE)
|
||||
})
|
||||
TextItemChildView({ text: '关于我们' }).height(60).margin({ left: 16, right: 16 })
|
||||
.onClick(() => {
|
||||
this.getUIContext().getRouter().pushUrl({url: RouterUrls.ABOUT_PAGE});
|
||||
EventReportGlobalManager.eventReport(EventConstants.JUMP_TO_ABOUT_US)
|
||||
})
|
||||
TextItemChildView({ text: '注销账号' }).height(60).margin({ left: 16, right: 16 })
|
||||
.onClick(() => {
|
||||
TipDialog.show(this.getUIContext(), {title: '提示', content: '为了您的账户安全,注销账户后将会永久清除与该账户相关的所有信息,服务器不再保存', callback: {
|
||||
confirm: () => {
|
||||
this.viewModel.userDestroy();
|
||||
}
|
||||
}})
|
||||
})
|
||||
.visibility(LoginManager.isLogin() ? Visibility.Visible : Visibility.None)
|
||||
}
|
||||
.justifyContent(FlexAlign.Start)
|
||||
.height('100%')
|
||||
}
|
||||
.layoutWeight(1)
|
||||
|
||||
Stack() {
|
||||
Button('退出登录', { type: ButtonType.Capsule, stateEffect: true })
|
||||
.fontColor(Color.White)
|
||||
.fontSize(15)
|
||||
.fontWeight(FontWeight.Medium)
|
||||
.linearGradient({
|
||||
colors: [['#F62C6C', 0.0], ['#FC4F54', 1.0]],
|
||||
direction: GradientDirection.Right
|
||||
})
|
||||
.width('100%')
|
||||
.height(46)
|
||||
.onClick(() => {
|
||||
TipDialog.show(this.getUIContext(), {title: '温馨提示', content: '确定退出登录?', callback: {
|
||||
confirm: () => {
|
||||
EventReportGlobalManager.eventReport(EventConstants.EXIT_LOGIN)
|
||||
this.logout();
|
||||
}
|
||||
}})
|
||||
})
|
||||
}
|
||||
.padding({ left: 16, right: 16 })
|
||||
.margin({ bottom: 30 })
|
||||
.visibility(LoginManager.isLogin() ? Visibility.Visible : Visibility.None)
|
||||
}
|
||||
.width('100%')
|
||||
.height('100%')
|
||||
.backgroundColor($r('app.color.window_background'))
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
import { AppUtil } from '@pura/harmony-utils'
|
||||
import { Constants } from '../../../../../common/Constants'
|
||||
import { RouterUrls } from '../../../../../common/RouterUrls'
|
||||
import { TextItemChildView } from '../../../../../view/TextItemChildView'
|
||||
import { TitleBar } from '../../../../../view/TitleBar'
|
||||
|
||||
@Entry
|
||||
@ComponentV2
|
||||
struct AboutPage {
|
||||
build() {
|
||||
Column() {
|
||||
TitleBar({ title: '关于' }).width('100%')
|
||||
Image($r('app.media.ic_login_logo')).width(100).height(100).margin({ top: 100 })
|
||||
Text($r('app.string.app_name'))
|
||||
.fontColor(Color.White)
|
||||
.fontSize(16)
|
||||
.fontWeight(FontWeight.Medium)
|
||||
.margin({ top: 16 })
|
||||
.width('auto')
|
||||
Text('版本号:v' + AppUtil.getVersionName())
|
||||
.fontColor($r('app.color.color_999999'))
|
||||
.fontSize(14)
|
||||
.margin({ top: 6 })
|
||||
.width('auto')
|
||||
TextItemChildView({ text: '用户协议' }).height(60).margin({ left: 16, top: 52, right: 16 })
|
||||
.onClick(() => {
|
||||
this.getUIContext()
|
||||
.getRouter()
|
||||
.pushUrl({ url: RouterUrls.WEB_PAGE, params: { title: '用户协议', url: Constants.USER_AGREEMENT } })
|
||||
})
|
||||
TextItemChildView({ text: '隐私政策', divider: false }).height(60).margin({ left: 16, right: 16 })
|
||||
.onClick(() => {
|
||||
this.getUIContext()
|
||||
.getRouter()
|
||||
.pushUrl({ url: RouterUrls.WEB_PAGE, params: { title: '隐私政策', url: Constants.PRIVACY_POLICY } })
|
||||
})
|
||||
}
|
||||
.justifyContent(FlexAlign.Start)
|
||||
.backgroundColor($r('app.color.window_background'))
|
||||
.width('100%')
|
||||
.height('100%')
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,186 @@
|
|||
import { AppUtil, RandomUtil, StrUtil } from '@pura/harmony-utils';
|
||||
import { TipDialog } from '../../../../../dialog/TipDialog';
|
||||
import { UserEntity } from '../../../../../entity/UserEntity';
|
||||
import { ConfigManager } from '../../../../../manager/UserConfigManager';
|
||||
import { ToastUtils } from '../../../../../utils/ToastUtils';
|
||||
import { TitleBar } from '../../../../../view/TitleBar';
|
||||
import BindAccountViewModel from '../../../../../viewModel/BindAccountViewModel';
|
||||
import * as WxOpenSdk from '@tencent/wechat_open_sdk';
|
||||
import { ErrCode, SendAuthResp } from '@tencent/wechat_open_sdk';
|
||||
import { OnWXResp, WXApi, WXEventHandler } from '../../../../../utils/wechat/WXApiEventHandlerImpl';
|
||||
import BuildProfile from 'BuildProfile';
|
||||
import { BindPhoneDialog } from '../../../../../dialog/BindPhoneDialog';
|
||||
import { LevelMode } from '@kit.ArkUI';
|
||||
import { EventConstants } from '../../../../../common/EventConstants';
|
||||
import { LoadingDialog } from '../../../../../dialog/LoadingDialog';
|
||||
import { EventReportGlobalManager } from '../../../../../manager/EventReportGlobalManager';
|
||||
|
||||
@Entry
|
||||
@ComponentV2
|
||||
struct BindAccountPage {
|
||||
bindPhoneDialogController?: CustomDialogController | null;
|
||||
|
||||
viewModel: BindAccountViewModel = new BindAccountViewModel(this.getUIContext());
|
||||
|
||||
@Local userEntity?: UserEntity;
|
||||
|
||||
//从微信返回的回调
|
||||
onWXResp: OnWXResp = (resp) => {
|
||||
//微信返回的数据
|
||||
if (resp instanceof SendAuthResp && resp.state?.endsWith('bind')) {
|
||||
const authResult = JSON.stringify(resp ?? {}, null , 2);
|
||||
const errCode = JSON.parse(authResult).errCode as number;
|
||||
if (errCode === ErrCode.ERR_OK) {
|
||||
const authCode = JSON.parse(authResult).code as string;
|
||||
this.viewModel.bindWx(authCode);
|
||||
} else {
|
||||
ToastUtils.show(JSON.parse(authResult).errStr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Monitor('viewModel.userEntity')
|
||||
onUserinfoChange(monitor: IMonitor) {
|
||||
this.userEntity = monitor.value()?.now as UserEntity;
|
||||
}
|
||||
|
||||
@Monitor('viewModel.bindInfo')
|
||||
onBindInfoChange(monitor: IMonitor) {
|
||||
ToastUtils.show('绑定成功');
|
||||
this.refreshData();
|
||||
EventReportGlobalManager.eventReport(EventConstants.ACCOUNT_BIND)
|
||||
}
|
||||
|
||||
@Monitor('viewModel.unbindInfo')
|
||||
onUnbindInfoChange(monitor: IMonitor) {
|
||||
ToastUtils.show('解绑成功');
|
||||
this.refreshData();
|
||||
}
|
||||
|
||||
async aboutToAppear() {
|
||||
WXEventHandler.registerOnWXRespCallback(this.onWXResp)
|
||||
this.viewModel.userinfo();
|
||||
}
|
||||
|
||||
aboutToDisappear() {
|
||||
WXEventHandler.unregisterOnWXRespCallback(this.onWXResp)
|
||||
this.bindPhoneDialogController = null
|
||||
}
|
||||
|
||||
showBindPhoneDialog() {
|
||||
this.bindPhoneDialogController = new CustomDialogController({
|
||||
builder: BindPhoneDialog({
|
||||
success: () => {
|
||||
this.refreshData();
|
||||
}
|
||||
}),
|
||||
width: '100%',
|
||||
cornerRadius: 20,
|
||||
autoCancel: false,
|
||||
maskColor: '#CC000000',
|
||||
levelMode: LevelMode.EMBEDDED,
|
||||
backgroundBlurStyle: BlurStyle.NONE,
|
||||
alignment: DialogAlignment.Bottom
|
||||
})
|
||||
this.bindPhoneDialogController.open();
|
||||
}
|
||||
|
||||
async wxAuth() {
|
||||
if (!WXApi.isWXAppInstalled()) {
|
||||
ToastUtils.show('请先下载安装微信客户端');
|
||||
return;
|
||||
}
|
||||
LoadingDialog.show(this.getUIContext());
|
||||
let req = new WxOpenSdk.SendAuthReq;
|
||||
req.isOption1 = false;
|
||||
req.nonAutomatic = true;
|
||||
req.scope = 'snsapi_userinfo';
|
||||
req.state = BuildProfile.BUNDLE_NAME + RandomUtil.getRandomInt(0, 1000) + '_bind';
|
||||
req.transaction ='';
|
||||
|
||||
await WXApi.sendReq(AppUtil.getContext(), req)
|
||||
LoadingDialog.dismiss();
|
||||
}
|
||||
|
||||
refreshData() {
|
||||
ConfigManager.userConfig()
|
||||
.then(() => {
|
||||
this.viewModel.userinfo();
|
||||
AppUtil.getContext().eventHub.emit(EventConstants.HomeRefreshEvent);
|
||||
AppUtil.getContext().eventHub.emit(EventConstants.MineRefreshEvent);
|
||||
})
|
||||
}
|
||||
|
||||
build() {
|
||||
Column() {
|
||||
TitleBar({ title: '账号绑定' }).width('100%')
|
||||
Row() {
|
||||
Image($r('app.media.ic_bind_wx')).width(30).height(30)
|
||||
Text('微信绑定').fontColor(Color.White).fontSize(15).layoutWeight(1).margin({left: 14})
|
||||
Text(StrUtil.isEmpty(this.userEntity?.unionid) ? '立即绑定' : '解除绑定')
|
||||
.textAlign(TextAlign.Center)
|
||||
.fontColor(Color.White)
|
||||
.fontSize(12)
|
||||
.borderColor(Color.White)
|
||||
.borderWidth(1)
|
||||
.borderRadius(4)
|
||||
.width(64)
|
||||
.height(24)
|
||||
.onClick(() => {
|
||||
if (StrUtil.isEmpty(this.userEntity?.unionid)) {
|
||||
this.wxAuth();
|
||||
} else {
|
||||
TipDialog.show(this.getUIContext(), {title: '解除微信绑定', content: '解绑后将无法使用该微信号登录此账号,请谨慎操作!', callback: {
|
||||
confirm: () => {
|
||||
if (StrUtil.isNotEmpty(this.userEntity?.phone)) {
|
||||
this.viewModel.unbind('weixin');
|
||||
} else {
|
||||
TipDialog.show(this.getUIContext(), {title: '预警提示', content: '您若继续解除绑定,您的账号将没有绑定账号,软件在使用过程中可能会造成账号丢失!是否继续解除绑定!', callback: {
|
||||
confirm: () => {
|
||||
this.viewModel.unbind('weixin');
|
||||
}
|
||||
}})
|
||||
}
|
||||
}
|
||||
}})
|
||||
}
|
||||
})
|
||||
}.width('100%').height(60).padding({ left: 16, right: 16 })
|
||||
Divider().color($r('app.color.color_10ffffff')).strokeWidth(1).margin({left: 16, right: 16})
|
||||
Row() {
|
||||
Image($r('app.media.ic_bind_phone')).width(30).height(30)
|
||||
Text('手机绑定').fontColor(Color.White).fontSize(15).layoutWeight(1).margin({left: 14})
|
||||
Text(StrUtil.isEmpty(this.userEntity?.phone) ? '立即绑定' : '解除绑定')
|
||||
.textAlign(TextAlign.Center)
|
||||
.fontColor(Color.White)
|
||||
.fontSize(12)
|
||||
.borderColor(Color.White)
|
||||
.borderWidth(1)
|
||||
.borderRadius(4)
|
||||
.width(64)
|
||||
.height(24)
|
||||
.onClick(() => {
|
||||
if (StrUtil.isEmpty(this.userEntity?.phone)) {
|
||||
this.showBindPhoneDialog();
|
||||
} else {
|
||||
TipDialog.show(this.getUIContext(), {title: '解除手机绑定', content: '解绑后将无法使用该手机号登录此账号,请谨慎操作!', callback: {
|
||||
confirm: () => {
|
||||
if (StrUtil.isNotEmpty(this.userEntity?.unionid)) {
|
||||
this.viewModel.unbind('phone');
|
||||
} else {
|
||||
TipDialog.show(this.getUIContext(), {title: '预警提示', content: '您若继续解除绑定,您的账号将没有绑定账号,软件在使用过程中可能会造成账号丢失!是否继续解除绑定!', callback: {
|
||||
confirm: () => {
|
||||
this.viewModel.unbind('phone');
|
||||
}
|
||||
}})
|
||||
}
|
||||
}
|
||||
}})
|
||||
}
|
||||
})
|
||||
}.width('100%').height(60).padding({ left: 16, right: 16 })
|
||||
}
|
||||
.backgroundColor($r('app.color.window_background'))
|
||||
.height('100%')
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,130 @@
|
|||
import { AppUtil, StrUtil } from '@pura/harmony-utils';
|
||||
import { EventConstants } from '../../../../../common/EventConstants';
|
||||
import { LoadingDialog } from '../../../../../dialog/LoadingDialog';
|
||||
import { TipDialog } from '../../../../../dialog/TipDialog';
|
||||
import { AccountEntity } from '../../../../../entity/AccountEntity';
|
||||
import { LoginEntity } from '../../../../../entity/LoginEntity';
|
||||
import { EventReportGlobalManager } from '../../../../../manager/EventReportGlobalManager';
|
||||
import { LoginManager } from '../../../../../manager/LoginGlobalManager';
|
||||
import { ConfigManager } from '../../../../../manager/UserConfigManager';
|
||||
import { ToastUtils } from '../../../../../utils/ToastUtils';
|
||||
import { AccountItemView } from '../../../../../view/AccountItemView';
|
||||
import { TitleBar } from '../../../../../view/TitleBar';
|
||||
import ManageAccountViewModel from '../../../../../viewModel/ManageAccountViewModel';
|
||||
|
||||
@Entry
|
||||
@ComponentV2
|
||||
struct ManageAccountPage {
|
||||
viewModel: ManageAccountViewModel = new ManageAccountViewModel(this.getUIContext());
|
||||
|
||||
@Local accountList: AccountEntity[] = [];
|
||||
|
||||
@Local currentAccount?: AccountEntity;
|
||||
|
||||
@Monitor('viewModel.accounts')
|
||||
onAccountsChange(monitor: IMonitor) {
|
||||
const list = monitor.value()?.now as Array<AccountEntity>;
|
||||
list.forEach((item) => {
|
||||
if (item.user_id === LoginManager.getUserInfo()?.user_id) {
|
||||
this.currentAccount = item;
|
||||
} else {
|
||||
this.accountList.push(item);
|
||||
}
|
||||
})
|
||||
if (this.currentAccount === null && LoginManager.getUserInfo()) {
|
||||
let userinfo = LoginManager.getUserInfo()!!
|
||||
let account = new AccountEntity()
|
||||
let bind: string[] = []
|
||||
if (StrUtil.isNotEmpty(userinfo.unionid)) {
|
||||
bind.push("weixin")
|
||||
}
|
||||
if (StrUtil.isNotEmpty(userinfo.phone)) {
|
||||
bind.push('phone')
|
||||
}
|
||||
account.user_id = userinfo.user_id
|
||||
account.name = userinfo.name
|
||||
account.avater = userinfo.avater
|
||||
account.phone = userinfo.phone
|
||||
account.vip_name = userinfo.vip_name
|
||||
account.vip_type = userinfo.vip
|
||||
account.bind = bind
|
||||
this.currentAccount = account
|
||||
}
|
||||
}
|
||||
|
||||
@Monitor('viewModel.loginEntity')
|
||||
onLoginChange(monitor: IMonitor) {
|
||||
const loginEntity = monitor.value()?.now as LoginEntity;
|
||||
LoginManager.saveToken(loginEntity.token);
|
||||
LoginManager.saveLastUserInfo(LoginManager.getUserInfo()!!);
|
||||
ConfigManager.saveBindWxPlaybackHelper(false);
|
||||
ConfigManager.saveBindWxVideoHelper(false);
|
||||
ConfigManager.userConfig()
|
||||
.then(() => {
|
||||
ToastUtils.show('切换成功');
|
||||
AppUtil.getContext().eventHub.emit(EventConstants.LoginSuccessEvent);
|
||||
this.getUIContext().getRouter().back();
|
||||
})
|
||||
.finally(() => {
|
||||
LoadingDialog.dismiss();
|
||||
})
|
||||
}
|
||||
|
||||
aboutToAppear(): void {
|
||||
this.viewModel.accountList();
|
||||
}
|
||||
|
||||
build() {
|
||||
Column() {
|
||||
TitleBar({ title: '名下账户管理' }).width('100%')
|
||||
|
||||
Scroll() {
|
||||
Column() {
|
||||
Text('当前登录的账户')
|
||||
.fontColor($r('app.color.color_90ffffff'))
|
||||
.fontSize(15)
|
||||
.fontWeight(FontWeight.Medium)
|
||||
.margin({ left: 20, top: 24, right: 20 })
|
||||
.alignSelf(ItemAlign.Start)
|
||||
|
||||
AccountItemView({ account: this.currentAccount }).margin({ left: 20, top: 14, right: 20 })
|
||||
|
||||
Text('你名下其他账户')
|
||||
.fontColor($r('app.color.color_90ffffff'))
|
||||
.fontSize(15)
|
||||
.fontWeight(FontWeight.Medium)
|
||||
.margin({ left: 20, top: 30, right: 20 })
|
||||
.alignSelf(ItemAlign.Start)
|
||||
.visibility(this.accountList.length > 0 ? Visibility.Visible : Visibility.Hidden)
|
||||
|
||||
List() {
|
||||
ForEach(this.accountList, (item: AccountEntity) => {
|
||||
ListItem() {
|
||||
AccountItemView({account: item})
|
||||
}
|
||||
.margin({ left: 20, top: 14, right: 20 })
|
||||
.onClick(() => {
|
||||
TipDialog.show(this.getUIContext(), {content: '您确定要切换账户吗?', callback: {
|
||||
confirm: () => {
|
||||
LoginManager.saveToken('');
|
||||
this.viewModel.changeAccount(item.user_id);
|
||||
EventReportGlobalManager.eventReport(EventConstants.SWITCH_ACCOUNT,item.user_id)
|
||||
}
|
||||
}})
|
||||
})
|
||||
})
|
||||
}
|
||||
.width('100%')
|
||||
.height('auto')
|
||||
.layoutWeight(1)
|
||||
.margin({ bottom: 30 })
|
||||
.visibility(this.accountList.length > 0 ? Visibility.Visible : Visibility.Hidden)
|
||||
}
|
||||
}
|
||||
.layoutWeight(1)
|
||||
}
|
||||
.width('100%')
|
||||
.height('100%')
|
||||
.backgroundColor($r('app.color.window_background'))
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue