增加换肤功能

This commit is contained in:
启星
2025-08-14 10:07:49 +08:00
parent f6964c1e89
commit 4f9318d98e
8789 changed files with 978530 additions and 2 deletions

View File

@@ -0,0 +1,27 @@
// Copyright (c) 2024 Tencent. All rights reserved.
// Author: eddardliu
#import <AVKit/AVKit.h>
#import <UIKit/UIKit.h>
#import "TUIMultimediaPlugin/TUIMultimediaPasterConfig.h"
#import "TUIMultimediaPlugin/TUIMultimediaPopupController.h"
#import "TUIMultimediaPlugin/TUIMultimediaVideoBgmEditInfo.h"
NS_ASSUME_NONNULL_BEGIN
@protocol TUIMultimediaBGMEditControllerDelegate;
/**
背景音乐选择界面Controller
*/
@interface TUIMultimediaBGMEditController : TUIMultimediaPopupController
@property(nonatomic) float clipDuration;
@property(readonly, nonatomic) TUIMultimediaVideoBgmEditInfo *bgmEditInfo;
@property(weak, nullable, nonatomic) id<TUIMultimediaBGMEditControllerDelegate> delegate;
@end
@protocol TUIMultimediaBGMEditControllerDelegate <NSObject>
- (void)onBGMEditController:(TUIMultimediaBGMEditController *)c bgmInfoChanged:(TUIMultimediaVideoBgmEditInfo *)bgmInfo;
- (void)onBGMEditControllerExit:(TUIMultimediaBGMEditController *)c;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,80 @@
// Copyright (c) 2024 Tencent. All rights reserved.
// Author: eddardliu
#import "TUIMultimediaBGMEditController.h"
#import <Masonry/Masonry.h>
#import <ReactiveObjC/RACEXTScope.h>
#import "TUIMultimediaPlugin/NSArray+Functional.h"
#import "TUIMultimediaPlugin/TUIMultimediaBGMEditView.h"
#import "TUIMultimediaPlugin/TUIMultimediaCommon.h"
#import "TUIMultimediaPlugin/TUIMultimediaImagePicker.h"
#import "TUIMultimediaPlugin/TUIMultimediaPasterSelectView.h"
#import "TUIMultimediaPlugin/TUIMultimediaPersistence.h"
@interface TUIMultimediaBGMEditController () <TUIMultimediaBGMEditViewDelegate> {
TUIMultimediaBGMEditView *_editView;
NSArray<TUIMultimediaBGMGroup *> *_bgmConfig;
dispatch_block_t _blockBGMNotify;
}
@end
@implementation TUIMultimediaBGMEditController
- (instancetype)init {
self = [super init];
_bgmConfig = [TUIMultimediaBGMGroup loadBGMConfigs];
_bgmEditInfo = [[TUIMultimediaVideoBgmEditInfo alloc] init];
_bgmEditInfo.originAudio = YES;
_bgmEditInfo.bgm = nil;
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
_editView = [[TUIMultimediaBGMEditView alloc] init];
_editView.bgmConfig = _bgmConfig;
_editView.originAudioEnabled = YES;
_editView.clipDuration = _clipDuration;
_editView.delegate = self;
self.mainView = _editView;
}
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
}
- (void)popupControllerDidCanceled {
[_delegate onBGMEditControllerExit:self];
}
#pragma mark - Properties
- (void)setClipDuration:(float)videoDuration {
_clipDuration = videoDuration;
_editView.clipDuration = videoDuration;
}
#pragma mark - TUIMultimediaBGMEditViewDelegate protocol
- (void)bgmEditViewValueChanged:(TUIMultimediaBGMEditView *)v {
TUIMultimediaVideoBgmEditInfo *newBgmInfo = [[TUIMultimediaVideoBgmEditInfo alloc] init];
if (v.bgmEnabled) {
newBgmInfo.bgm = [v.selectedBgm copy];
} else {
newBgmInfo.bgm = nil;
}
newBgmInfo.originAudio = v.originAudioEnabled;
// ,
if (_blockBGMNotify != nil) {
dispatch_block_cancel(_blockBGMNotify);
_blockBGMNotify = nil;
}
_blockBGMNotify = dispatch_block_create(DISPATCH_BLOCK_INHERIT_QOS_CLASS, ^{
self->_bgmEditInfo = newBgmInfo;
[self->_delegate onBGMEditController:self bgmInfoChanged:self->_bgmEditInfo];
});
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.050 * NSEC_PER_SEC)), dispatch_get_main_queue(), _blockBGMNotify);
}
@end

View File

@@ -0,0 +1,22 @@
// Copyright (c) 2024 Tencent. All rights reserved.
// Author: eddardliu
#import <AVFoundation/AVFoundation.h>
#import <UIKit/UIKit.h>
#import "TUIMultimediaPlugin/TUIMultimediaEncodeConfig.h"
NS_ASSUME_NONNULL_BEGIN
/**
视频编辑界面Controller
*/
@interface TUIMultimediaVideoEditorController : UIViewController
@property(nullable, nonatomic) NSString *sourceVideoPath;
@property(nullable, nonatomic) NSString *resultVideoPath;
@property(nonatomic)int sourceType;
@property(nonatomic, nullable) void (^completeCallback)(NSString *resultVideoPath, int resultCode);
- (instancetype)init;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,299 @@
// Copyright (c) 2024 Tencent. All rights reserved.
// Author: eddardliu
#import "TUIMultimediaVideoEditorController.h"
#import <Masonry/Masonry.h>
#import <ReactiveObjC/RACEXTScope.h>
#import <TUICore/TUIDefine.h>
#import <TXLiteAVSDK_Professional/TXVideoEditer.h>
#import <TXLiteAVSDK_Professional/TXVideoEditerTypeDef.h>
#import "TUIMultimediaPlugin/NSArray+Functional.h"
#import "TUIMultimediaPlugin/TUIMultimediaBGMEditController.h"
#import "TUIMultimediaPlugin/TUIMultimediaCommon.h"
#import "TUIMultimediaPlugin/TUIMultimediaCommonEditorControlView.h"
#import "TUIMultimediaPlugin/TUIMultimediaImagePicker.h"
#import "TUIMultimediaPlugin/TUIMultimediaPasterConfig.h"
#import "TUIMultimediaPlugin/TUIMultimediaPasterSelectController.h"
#import "TUIMultimediaPlugin/TUIMultimediaPersistence.h"
#import "TUIMultimediaPlugin/TUIMultimediaSubtitleEditController.h"
#import "TUIMultimediaPlugin/TUIMultimediaConfig.h"
#import "TUIMultimediaPlugin/TUIMultimediaConstant.h"
#import "TUIMultimediaPlugin/TUIMultimediaAuthorizationPrompter.h"
@interface TUIMultimediaVideoEditorController () <TXVideoPreviewListener,
TXVideoGenerateListener,
TUIMultimediaPasterSelectControllerDelegate,
TUIMultimediaCommonEditorControlViewDelegate,
TUIMultimediaBGMEditControllerDelegate> {
TUIMultimediaPasterSelectController *_pasterSelectController;
TUIMultimediaCommonEditorControlView *_commonEditCtrlView;
TXVideoEditer *_editor;
NSString *_sourceVideoPath;
TXVideoInfo *_videoInfo;
TUIMultimediaSubtitleEditController *_subtitleEditController;
TUIMultimediaBGMEditController *_musicController;
TUIMultimediaEncodeConfig *_encodeConfig;
BOOL _originNavgationBarHidden;
float _lastGenerateProgress;
BOOL _hasAudioEdited;
}
@end
@implementation TUIMultimediaVideoEditorController
@dynamic sourceVideoPath;
- (instancetype)init {
self = [super init];
_encodeConfig = [[TUIMultimediaEncodeConfig alloc] initWithVideoQuality:[[TUIMultimediaConfig sharedInstance] getVideoQuality]];
_lastGenerateProgress = 0;
_sourceType = SOURCE_TYPE_RECORD;
_hasAudioEdited = NO;
return self;
}
- (void)viewDidLoad {
[self initUI];
_pasterSelectController = [[TUIMultimediaPasterSelectController alloc] init];
_pasterSelectController.delegate = self;
_pasterSelectController.modalPresentationStyle = UIModalPresentationOverCurrentContext;
_subtitleEditController = [[TUIMultimediaSubtitleEditController alloc] init];
_subtitleEditController.modalPresentationStyle = UIModalPresentationOverCurrentContext;
_musicController = [[TUIMultimediaBGMEditController alloc] init];
_musicController.modalPresentationStyle = UIModalPresentationOverCurrentContext;
_musicController.delegate = self;
_musicController.clipDuration = _videoInfo.duration;
}
- (void)viewWillAppear:(BOOL)animated {
if (self.navigationController != nil) {
_originNavgationBarHidden = self.navigationController.navigationBarHidden;
self.navigationController.navigationBarHidden = YES;
}
}
- (void)viewWillDisappear:(BOOL)animated {
if (self.navigationController != nil) {
self.navigationController.navigationBarHidden = _originNavgationBarHidden;
}
}
- (NSString *)sourceVideoPath {
return _sourceVideoPath;
}
- (void)setSourceVideoPath:(NSString *)sourceVideoPath {
_sourceVideoPath = sourceVideoPath;
NSString *currentSourceVideoPath = sourceVideoPath;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
if (self->_sourceVideoPath != currentSourceVideoPath) return;
self->_videoInfo = [TXVideoInfoReader getVideoInfo:self->_sourceVideoPath];
NSLog(@"videoInfo angle = %d, width = %d, height = %d, duration = %f",
self->_videoInfo.angle, self->_videoInfo.width, self->_videoInfo.height, self->_videoInfo.duration);
if (self->_videoInfo.angle == 90 || self->_videoInfo.angle == 270) {
int temp = self->_videoInfo.width;
self->_videoInfo.width = self->_videoInfo.height;
self->_videoInfo.height = temp;
}
dispatch_async(dispatch_get_main_queue(), ^{
[self tryReloadVideoAsset];
self->_musicController.clipDuration = self->_videoInfo.duration;
});
});
}
- (void)setSourceType:(int)sourceType {
NSLog(@"setSourceType sourceType = %d",sourceType);
_sourceType = sourceType;
if (_commonEditCtrlView != nil) {
_commonEditCtrlView.sourceType = sourceType;
}
}
- (void)tryReloadVideoAsset {
if (_editor == nil || _sourceVideoPath == nil) return;
int code = [_editor setVideoPath:_sourceVideoPath];
[_editor startPlayFromTime:0 toTime:_videoInfo.duration];
if (code != 0) {
NSString *title = [TUIMultimediaCommon localizedStringForKey:@"modify_load_assert_failed"];
[self showAlertWithTitle:title message:@"" action:@"OK"];
}
_commonEditCtrlView.previewSize = CGSizeMake(_videoInfo.width, _videoInfo.height);
}
#pragma mark - UI Init
- (void)initUI {
_commonEditCtrlView = [[TUIMultimediaCommonEditorControlView alloc] initWithConfig:TUIMultimediaCommonEditorConfig.configForVideoEditor];
[self.view addSubview:_commonEditCtrlView];
_commonEditCtrlView.backgroundColor = UIColor.blackColor;
_commonEditCtrlView.previewSize = CGSizeMake(_videoInfo.width, _videoInfo.height);
_commonEditCtrlView.sourceType = _sourceType;
_commonEditCtrlView.delegate = self;
TXPreviewParam *param = [[TXPreviewParam alloc] init];
param.videoView = _commonEditCtrlView.previewView;
param.renderMode = PREVIEW_RENDER_MODE_FILL_EDGE;
_editor = [[TXVideoEditer alloc] initWithPreview:param];
[self tryReloadVideoAsset];
_editor.previewDelegate = self;
_editor.generateDelegate = self;
[_commonEditCtrlView mas_makeConstraints:^(MASConstraintMaker *make) {
make.edges.equalTo(self.view);
}];
}
- (void)showAlertWithTitle:(NSString *)title message:(NSString *)message action:(NSString *)action {
UIAlertController *alert = [UIAlertController alertControllerWithTitle:title message:message preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *defaultAction = [UIAlertAction actionWithTitle:action style:UIAlertActionStyleDefault handler:nil];
[alert addAction:defaultAction];
[self presentViewController:alert animated:YES completion:nil];
}
#pragma mark - TXVideoPreviewListener protocol
- (void)onPreviewProgress:(CGFloat)time {
}
- (void)onPreviewFinished {
[_editor startPlayFromTime:0 toTime:_videoInfo.duration];
}
#pragma mark - TXVideoGenerateListener protocol
- (void)onGenerateProgress:(float)progress {
NSLog(@"TUIMultimediaVideoEditorController onGenerateProgress progress = %f",progress);
if (progress - _lastGenerateProgress > 0.01f || progress == 1.0f) {
_commonEditCtrlView.progressBarProgress = progress;
_lastGenerateProgress = progress;
}
}
- (void)onGenerateComplete:(TXGenerateResult *)result {
NSLog(@"TUIMultimediaVideoEditorController onGenerateComplete retCode = %ld",(long)result.retCode);
int resultCode = (result.retCode != 0) ? VIDEO_EDIT_RESULT_CODE_GENERATE_FAIL : VIDEO_EDIT_RESULT_CODE_GENERATE_SUCCESS;
_completeCallback(_resultVideoPath, resultCode);
}
#pragma mark - TUIMultimediaCommonEditorControlViewDelegate protocol
- (void)onCommonEditorControlViewComplete:(TUIMultimediaCommonEditorControlView *)view stickers:(NSArray<TUIMultimediaSticker *> *)stickers {
if (![TUIMultimediaAuthorizationPrompter verifyPermissionGranted:self]) {
return;
}
if (stickers.count == 0 && !_hasAudioEdited && _sourceType == SOURCE_TYPE_ALBUM) {
NSLog(@"Return directly without encoding the video");
_resultVideoPath = _sourceVideoPath;
_completeCallback(_resultVideoPath, VIDEO_EDIT_RESULT_CODE_NO_EDIT);
return;
}
NSArray<TXPaster *> *pasterList = [stickers tui_multimedia_map:^TXPaster *(TUIMultimediaSticker *s) {
TXPaster *p = [[TXPaster alloc] init];
p.pasterImage = s.image;
p.frame = s.frame;
p.startTime = 0.0;
p.endTime = self->_videoInfo.duration;
return p;
}];
[_editor setPasterList:pasterList];
_commonEditCtrlView.isGenerating = YES;
[self.view bringSubviewToFront:_commonEditCtrlView];
if (_resultVideoPath == nil || _resultVideoPath.length == 0) {
_resultVideoPath = [self getOutFilePath];
}
[_editor setVideoBitrate:_encodeConfig.bitrate];
[_editor generateVideo:[_encodeConfig getVideoEditCompressed] videoOutputPath:_resultVideoPath];
}
- (void)onCommonEditorControlViewCancel:(TUIMultimediaCommonEditorControlView *)view {
[_editor stopPlay];
_completeCallback(nil, VIDEO_EDIT_RESULT_CODE_CANCEL);
}
- (void)onCommonEditorControlViewNeedAddPaster:(TUIMultimediaCommonEditorControlView *)view {
NSLog(@"onCommonEditorControlViewNeedAddPaster");
_commonEditCtrlView.modifyButtonsHidden = YES;
[self presentViewController:_pasterSelectController animated:NO completion:nil];
}
- (void)onCommonEditorControlViewNeedModifySubtitle:(TUIMultimediaSubtitleInfo *)info callback:(void (^)(TUIMultimediaSubtitleInfo *info, BOOL isOk))callback {
_subtitleEditController.subtitleInfo = info;
_subtitleEditController.callback = ^(TUIMultimediaSubtitleEditController *c, BOOL isOk) {
[c.presentingViewController dismissViewControllerAnimated:NO completion:nil];
if (callback != nil) {
callback(c.subtitleInfo, isOk);
}
};
[self presentViewController:_subtitleEditController animated:NO completion:nil];
}
- (void)onCommonEditorControlViewNeedEditMusic:(TUIMultimediaCommonEditorControlView *)view {
_commonEditCtrlView.modifyButtonsHidden = YES;
[self presentViewController:_musicController animated:NO completion:nil];
}
- (void)onCommonEditorControlViewCancelGenerate:(TUIMultimediaCommonEditorControlView *)view {
[_editor cancelGenerate];
TXPreviewParam *param = [[TXPreviewParam alloc] init];
param.videoView = _commonEditCtrlView.previewView;
param.renderMode = PREVIEW_RENDER_MODE_FILL_EDGE;
_editor = [[TXVideoEditer alloc] initWithPreview:param];
[self tryReloadVideoAsset];
_editor.previewDelegate = self;
_editor.generateDelegate = self;
}
-(NSString*) getOutFilePath{
NSDate* currentDate = [NSDate date];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss.SSS"];
NSString* currentDateString = [dateFormatter stringFromDate:currentDate];
NSString* outFileName = [NSString stringWithFormat:@"%@-%u-temp.mp4", currentDateString, arc4random()];
return [NSTemporaryDirectory() stringByAppendingPathComponent:outFileName];
}
#pragma mark - TUIMultimediaPasterSelectControllerDelegate protocol
- (void)pasterSelectController:(TUIMultimediaPasterSelectController *)c onPasterSelected:(UIImage *)image {
[_commonEditCtrlView addPaster:image];
_commonEditCtrlView.modifyButtonsHidden = NO;
[c.presentingViewController dismissViewControllerAnimated:NO completion:nil];
}
- (void)onPasterSelectControllerExit:(TUIMultimediaPasterSelectController *)c {
_commonEditCtrlView.modifyButtonsHidden = NO;
[c.presentingViewController dismissViewControllerAnimated:NO completion:nil];
}
#pragma mark - TUIMultimediaMusicControllerDelegate protocol
- (void)onBGMEditController:(TUIMultimediaBGMEditController *)bgmController bgmInfoChanged:(TUIMultimediaVideoBgmEditInfo *)bgmInfo {
if (![TUIMultimediaAuthorizationPrompter verifyPermissionGranted:bgmController]) {
return;
}
[_editor setBGMLoop:YES];
@weakify(self);
[_editor setBGMAsset:bgmInfo.bgm.asset
result:^(int result) {
@strongify(self);
if (result != 0) {
NSString *title = [TUIMultimediaCommon localizedStringForKey:@"modify_load_assert_failed"];
[self showAlertWithTitle:title message:@"" action:@"OK"];
}
}];
[_editor setBGMAtVideoTime:0];
[_editor setBGMStartTime:bgmInfo.bgm.startTime endTime:bgmInfo.bgm.endTime];
[_editor setBGMVolume:1];
if (bgmInfo.originAudio) {
[_editor setVideoVolume:1];
} else {
[_editor setVideoVolume:0];
}
_commonEditCtrlView.musicEdited = bgmInfo.bgm != nil;
_hasAudioEdited = (!bgmInfo.originAudio) || (bgmInfo.bgm != nil);
}
- (void)onBGMEditControllerExit:(nonnull TUIMultimediaBGMEditController *)c {
_commonEditCtrlView.modifyButtonsHidden = NO;
[c.presentingViewController dismissViewControllerAnimated:NO completion:nil];
}
@end

View File

@@ -0,0 +1,31 @@
// Copyright (c) 2024 Tencent. All rights reserved.
// Author: eddardliu
#import <UIKit/UIKit.h>
#import "TUIMultimediaPlugin/TUIMultimediaBGM.h"
NS_ASSUME_NONNULL_BEGIN
typedef NS_ENUM(NSInteger, TUIMultimediaMusicCellState) {
TUIMultimediaMusicCellStateNormal,
TUIMultimediaMusicCellStateSelected,
TUIMultimediaMusicCellStateEnabled,
};
@protocol TUIMultimediaMusicCellDelegate;
@interface TUIMultimediaMusicCell : UITableViewCell
@property(nonatomic) TUIMultimediaMusicCellState state;
@property(nullable, nonatomic) TUIMultimediaBGM *music;
@property(nonatomic) float selectDuration;
@property(weak, nullable, nonatomic) id<TUIMultimediaMusicCellDelegate> delegate;
+ (NSString *)reuseIdentifier;
@end
@protocol TUIMultimediaMusicCellDelegate <NSObject>
- (void)musicCell:(TUIMultimediaMusicCell *)cell onEditStateChanged:(BOOL)editState;
- (void)musicCell:(TUIMultimediaMusicCell *)cell onBGMRangeChanged:(TUIMultimediaBGM *)bgm;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,128 @@
// Copyright (c) 2024 Tencent. All rights reserved.
// Author: eddardliu
#import "TUIMultimediaMusicCell.h"
#import <TUICore/TUIThemeManager.h>
#import "Masonry/Masonry.h"
#import "TUIMultimediaPlugin/TUIMultimediaAutoScrollLabel.h"
#import "TUIMultimediaPlugin/TUIMultimediaCommon.h"
#import "TUIMultimediaPlugin/TUIMultimediaConfig.h"
#import "TUIMultimediaPlugin/TUIMultimediaFakeAudioWaveView.h"
static const CGFloat TitleFontSize = 14;
static const CGFloat SubtitleFontSize = 12;
@interface TUIMultimediaMusicCell () {
TUIMultimediaAutoScrollLabel *_lbTitle;
UILabel *_lbSubTitle;
UILabel *_lbDuration;
TUIMultimediaFakeAudioWaveView *_waveView;
}
@end
@implementation TUIMultimediaMusicCell
+ (NSString *)reuseIdentifier {
return NSStringFromClass([self class]);
}
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self != nil) {
[self initUI];
}
return self;
}
- (void)initUI {
self.contentView.backgroundColor = UIColor.clearColor;
self.backgroundColor = UIColor.clearColor;
self.selectionStyle = UITableViewCellSelectionStyleNone;
_lbTitle = [[TUIMultimediaAutoScrollLabel alloc] init];
[self.contentView addSubview:_lbTitle];
_lbSubTitle = [[UILabel alloc] init];
[self.contentView addSubview:_lbSubTitle];
_lbSubTitle.font = [UIFont systemFontOfSize:SubtitleFontSize];
_lbSubTitle.textColor = TUIMultimediaPluginDynamicColor(@"editor_bgm_text_color", @"#FFFFFF99");
_lbDuration = [[UILabel alloc] init];
[self.contentView addSubview:_lbDuration];
_lbDuration.font = [UIFont monospacedSystemFontOfSize:SubtitleFontSize weight:UIFontWeightMedium];
_lbDuration.textColor = TUIMultimediaPluginDynamicColor(@"editor_bgm_text_color", @"#FFFFFF99");
_waveView = [[TUIMultimediaFakeAudioWaveView alloc] init];
[self addSubview:_waveView];
_waveView.hidden = YES;
[_lbTitle mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.top.equalTo(self.contentView).inset(10);
make.width.mas_equalTo(120);
}];
[_lbSubTitle mas_makeConstraints:^(MASConstraintMaker *make) {
make.top.equalTo(_lbTitle.mas_bottom).inset(5);
make.left.equalTo(self.contentView).inset(14);
make.bottom.equalTo(self.contentView).inset(10);
}];
[_lbDuration mas_makeConstraints:^(MASConstraintMaker *make) {
make.centerY.equalTo(self.contentView);
make.right.equalTo(self.contentView).inset(10);
}];
[_waveView mas_makeConstraints:^(MASConstraintMaker *make) {
make.right.equalTo(_lbDuration.mas_left).inset(50);
make.centerY.equalTo(self);
make.height.mas_equalTo(12);
make.width.mas_equalTo(48);
}];
}
- (void)updateTitle {
UIColor *color = UIColor.whiteColor;
BOOL active = NO;
if (_state == TUIMultimediaMusicCellStateEnabled) {
color = [[TUIMultimediaConfig sharedInstance] getThemeColor];
if (_music.lyric != nil && _music.lyric.length > 0) {
active = YES;
}
}
NSString *title = _music.lyric != nil && _music.lyric.length > 0 ? _music.lyric : _music.name;
_lbTitle.text = [[NSAttributedString alloc] initWithString:title
attributes:@{
NSFontAttributeName : [UIFont systemFontOfSize:TitleFontSize],
NSForegroundColorAttributeName : color,
}];
_lbTitle.active = active;
}
- (void)updateWave {
switch (_state) {
case TUIMultimediaMusicCellStateNormal:
_waveView.hidden = YES;
_waveView.enabled = NO;
break;
case TUIMultimediaMusicCellStateSelected:
_waveView.color = TUIMultimediaPluginDynamicColor(@"editor_bgm_text_color", @"#FFFFFF99");
_waveView.hidden = NO;
_waveView.enabled = NO;
break;
case TUIMultimediaMusicCellStateEnabled:
_waveView.color = [[TUIMultimediaConfig sharedInstance] getThemeColor];
_waveView.hidden = NO;
_waveView.enabled = YES;
break;
}
}
#pragma mark - Properties
- (void)setState:(TUIMultimediaMusicCellState)state {
_state = state;
[self updateTitle];
[self updateWave];
}
- (void)setMusic:(TUIMultimediaBGM *)music {
_music = music;
[self updateTitle];
_lbSubTitle.text = music.source;
float duration = music.asset == nil ? 0 : music.asset.duration.value / music.asset.duration.timescale;
int min = (int)(duration / 60);
_lbDuration.text = [NSString stringWithFormat:@"%02d:%02d", min, (int)(duration - min * 60)];
}
@end

View File

@@ -0,0 +1,24 @@
// Copyright (c) 2024 Tencent. All rights reserved.
// Author: eddardliu
#import <UIKit/UIKit.h>
#import "TUIMultimediaPlugin/TUIMultimediaBGM.h"
NS_ASSUME_NONNULL_BEGIN
@protocol TUIMultimediaBGMEditViewDelegate;
@interface TUIMultimediaBGMEditView : UIView
@property(nonatomic) NSArray<TUIMultimediaBGMGroup *> *bgmConfig;
@property(nonatomic) float clipDuration;
@property(nonatomic) TUIMultimediaBGM *selectedBgm;
@property(nonatomic) BOOL originAudioEnabled;
@property(nonatomic) BOOL bgmEnabled;
@property(weak, nullable, nonatomic) id<TUIMultimediaBGMEditViewDelegate> delegate;
@end
@protocol TUIMultimediaBGMEditViewDelegate <NSObject>
- (void)bgmEditViewValueChanged:(TUIMultimediaBGMEditView *)v;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,164 @@
// Copyright (c) 2024 Tencent. All rights reserved.
// Author: eddardliu
#import "TUIMultimediaBGMEditView.h"
#import <Masonry/Masonry.h>
#import <TUICore/TUIThemeManager.h>
#import "TUIMultimediaPlugin/NSArray+Functional.h"
#import "TUIMultimediaPlugin/TUIMultimediaCheckBox.h"
#import "TUIMultimediaPlugin/TUIMultimediaCommon.h"
#import "TUIMultimediaPlugin/TUIMultimediaMusicCell.h"
#import "TUIMultimediaPlugin/TUIMultimediaTabPanel.h"
static const CGFloat ItemInset = 10;
static const CGFloat ItemWidthFactor = 0.7;
static const CGFloat CollectionViewHeight = 100;
@interface TUIMultimediaBGMEditView () <UITableViewDataSource, UITableViewDelegate> {
NSArray<UITableView *> *_tableViews;
TUIMultimediaTabPanel *_tabPanel;
NSInteger _selectedIndex;
TUIMultimediaCheckBox *_switchOriginAudio;
TUIMultimediaCheckBox *_switchBgm;
}
@end
@implementation TUIMultimediaBGMEditView
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self != nil) {
_bgmConfig = @[];
_selectedIndex = -1;
[self initUI];
}
return self;
}
- (void)initUI {
self.backgroundColor = TUIMultimediaPluginDynamicColor(@"editor_popup_view_bg_color", @"#000000BF");
_tabPanel = [[TUIMultimediaTabPanel alloc] initWithFrame:self.bounds];
[self addSubview:_tabPanel];
_switchOriginAudio = [[TUIMultimediaCheckBox alloc] init];
[self addSubview:_switchOriginAudio];
_switchOriginAudio.text = [TUIMultimediaCommon localizedStringForKey:@"editor_origin_audio"];
[_switchOriginAudio addTarget:self action:@selector(onSwitchOriginAudioChanged) forControlEvents:UIControlEventValueChanged];
_switchBgm = [[TUIMultimediaCheckBox alloc] init];
[self addSubview:_switchBgm];
_switchBgm.text = [TUIMultimediaCommon localizedStringForKey:@"editor_bgm"];
[_switchBgm addTarget:self action:@selector(onSwitchBGMChanged) forControlEvents:UIControlEventValueChanged];
[_tabPanel mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.right.top.equalTo(self);
make.bottom.equalTo(_switchBgm.mas_top).inset(10);
make.height.mas_equalTo(400);
}];
[_switchBgm mas_makeConstraints:^(MASConstraintMaker *make) {
make.bottom.equalTo(self.mas_safeAreaLayoutGuideBottom);
make.height.mas_equalTo(24);
make.left.equalTo(self).inset(20);
}];
[_switchOriginAudio mas_makeConstraints:^(MASConstraintMaker *make) {
make.height.mas_equalTo(24);
make.bottom.equalTo(self.mas_safeAreaLayoutGuideBottom);
make.right.equalTo(self).inset(20);
}];
[self reloadConfig];
}
- (void)reloadConfig {
_tableViews = [_bgmConfig tui_multimedia_mapWithIndex:^UITableView *(TUIMultimediaBGMGroup *group, NSUInteger idx) {
UITableView *v = [[UITableView alloc] init];
v.tag = idx;
v.backgroundColor = UIColor.clearColor;
v.dataSource = self;
v.delegate = self;
[v registerClass:TUIMultimediaMusicCell.class forCellReuseIdentifier:TUIMultimediaMusicCell.reuseIdentifier];
return v;
}];
_tabPanel.tabs = [_tableViews tui_multimedia_map:^TUIMultimediaTabPanelTab *(UITableView *v) {
return [[TUIMultimediaTabPanelTab alloc] initWithName:[TUIMultimediaCommon localizedStringForKey:self->_bgmConfig[v.tag].name] icon:nil view:v];
}];
}
- (void)layoutSubviews {
[super layoutSubviews];
}
- (NSArray<TUIMultimediaBGM *> *)getBgmListByTableView:(UITableView *)v {
return _bgmConfig[v.tag].bgmList;
}
#pragma mark - UITableViewDataSource
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [self getBgmListByTableView:tableView].count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
TUIMultimediaMusicCell *cell = [tableView dequeueReusableCellWithIdentifier:TUIMultimediaMusicCell.reuseIdentifier forIndexPath:indexPath];
cell.music = [self getBgmListByTableView:tableView][indexPath.item];
if (cell.music == _selectedBgm) {
if (_switchBgm.on) {
cell.state = TUIMultimediaMusicCellStateEnabled;
} else {
cell.state = TUIMultimediaMusicCellStateSelected;
}
} else {
cell.state = TUIMultimediaMusicCellStateNormal;
}
return cell;
}
#pragma mark - UITableViewDelegate
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[tableView deselectRowAtIndexPath:indexPath animated:NO];
_selectedBgm = [self getBgmListByTableView:tableView][indexPath.item];
if (!_switchBgm.on) {
_switchBgm.on = YES;
}
[_delegate bgmEditViewValueChanged:self];
for (UITableView *v in _tableViews) {
[v reloadData];
}
}
#pragma mark - Actions
- (void)onSwitchOriginAudioChanged {
[_delegate bgmEditViewValueChanged:self];
}
- (void)onSwitchBGMChanged {
[_delegate bgmEditViewValueChanged:self];
for (UITableView *v in _tableViews) {
[v reloadData];
}
}
#pragma mark - Properties
- (void)setBgmConfig:(NSArray<TUIMultimediaBGMGroup *> *)bgmConfig {
_bgmConfig = bgmConfig;
[self reloadConfig];
}
- (BOOL)originAudioEnabled {
return _switchOriginAudio.on;
}
- (void)setOriginAudioEnabled:(BOOL)originAudioEnabled {
_switchOriginAudio.on = originAudioEnabled;
}
- (BOOL)bgmEnabled {
return _switchBgm.on;
}
- (void)setBgmEnabled:(BOOL)bgmEnabled {
_switchBgm.on = bgmEnabled;
}
- (void)setClipDuration:(float)videoDuration {
_clipDuration = videoDuration;
}
@end