recordViewController.m 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  1. //
  2. // recordViewController.m
  3. // 双子星云手机
  4. //
  5. // Created by xd h on 2025/3/28.
  6. //
  7. #import "recordViewController.h"
  8. #import "recordBottomView.h"
  9. #import "recordingView.h"
  10. #import <AVFoundation/AVFoundation.h>
  11. #import "recordFileModel.h"
  12. #import "recordFileCell.h"
  13. @interface recordViewController ()<UITableViewDelegate,UITableViewDataSource,DZNEmptyDataSetSource, DZNEmptyDataSetDelegate>
  14. @property (nonatomic, strong) UITableView *tableView;
  15. @property(nonatomic,strong)NSMutableArray *audioArr;//音频数据
  16. @property(nonatomic,strong)recordBottomView *recordBottomV;//底部视图
  17. @property(nonatomic,strong)recordingView *recordingV;//录音中
  18. @end
  19. @implementation recordViewController
  20. - (void)viewDidLoad {
  21. [super viewDidLoad];
  22. // Do any additional setup after loading the view.
  23. _audioArr = [NSMutableArray new];
  24. [self drawAnyView];
  25. [self getRecordDataFun];
  26. }
  27. - (void)drawAnyView
  28. {
  29. [self.view setBackgroundColor:HWF5F7FAColor];
  30. self.navBarBGView.hidden = NO;
  31. [self.navigationBar setHidden:YES];
  32. [self.toolBar setHidden:YES];
  33. [self.titleLabel setText:NSLocalizedString(@"mine_record_title",nil)];
  34. //底部视图
  35. _recordBottomV = [[recordBottomView alloc] init];
  36. [self.view addSubview:_recordBottomV];
  37. [_recordBottomV mas_makeConstraints:^(MASConstraintMaker *make) {
  38. make.left.mas_equalTo(0.f);
  39. make.right.mas_equalTo(0.f);
  40. make.bottom.mas_equalTo(0.f);
  41. make.height.mas_equalTo(100.f + AdaptTabHeight);
  42. }];
  43. KWeakSelf
  44. _recordBottomV.didClickRecordFun = ^{
  45. [weakSelf didClickRecordFun];
  46. };
  47. [self.view addSubview:self.tableView];
  48. [self.tableView mas_makeConstraints:^(MASConstraintMaker *make) {
  49. make.left.mas_equalTo(0);
  50. make.right.mas_equalTo(0);
  51. make.bottom.equalTo(self.recordBottomV.mas_top).offset(0.f);
  52. //make.bottom.mas_equalTo(0);
  53. make.top.equalTo(self.navBarBGView.mas_bottom).offset(10.f);
  54. }];
  55. }
  56. #pragma mark - 懒加载
  57. - (UITableView *)tableView{
  58. if (!_tableView) {
  59. _tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, SCREEN_W, SCREEN_H - TABBARHEIGHT) style:UITableViewStylePlain];
  60. _tableView.delegate = self;
  61. _tableView.dataSource = self;
  62. _tableView.showsVerticalScrollIndicator = NO;
  63. _tableView.showsHorizontalScrollIndicator = NO;
  64. // _tableView.contentInset = UIEdgeInsetsMake(-H_STATE_BAR, 0, 0, 0);
  65. [_tableView setSeparatorStyle:(UITableViewCellSeparatorStyleNone)];
  66. [_tableView setSeparatorColor:[UIColor clearColor]];
  67. [_tableView setBackgroundColor:[UIColor clearColor]];
  68. [_tableView setTableFooterView:[UIView new]];
  69. [_tableView setBounces:YES];
  70. if (@available(iOS 15.0, *)) {
  71. _tableView.sectionHeaderTopPadding = 0;
  72. }
  73. //空数据引入第三方开源处理
  74. _tableView.emptyDataSetSource = self;
  75. _tableView.emptyDataSetDelegate = self;
  76. // 下拉追加
  77. // MJRefreshAutoNormalFooter *footer = [MJRefreshAutoNormalFooter footerWithRefreshingBlock:^{
  78. // [self getMoreNetWorkData];
  79. // }];
  80. //
  81. // NSString *text = NSLocalizedString(@"NAS_bottom_tip",nil);
  82. // [footer setTitle:text forState:MJRefreshStateNoMoreData];
  83. // _tableView.mj_footer = footer;
  84. }
  85. return _tableView;
  86. }
  87. #pragma mark - 列表委托
  88. - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView{
  89. return 1;
  90. }
  91. - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
  92. if(!_audioArr){
  93. return 0;
  94. }
  95. return _audioArr.count;
  96. }
  97. - (recordFileCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
  98. __block NSInteger row = indexPath.row;
  99. static NSString *identifier = @"recordFileCell";
  100. recordFileCell * cell = [tableView dequeueReusableCellWithIdentifier:identifier];
  101. cell.selectionStyle = UITableViewCellSelectionStyleNone;
  102. if (!cell){
  103. cell = [[recordFileCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:identifier];
  104. [cell setSelectionStyle:UITableViewCellSelectionStyleNone];
  105. [cell setBackgroundColor:[UIColor clearColor]];
  106. [cell setAccessoryType:(UITableViewCellAccessoryNone)];
  107. }
  108. if(row < _audioArr.count){
  109. recordFileModel* dataModel = _audioArr[row];
  110. cell.curRecordFileModel = dataModel;
  111. //
  112. // KWeakSelf
  113. // cell.didClickSwitch = ^(BOOL SwitchOn) {
  114. // //if([weakSelf userCheckFileModel:dataModel withShowTip:YES]){
  115. // [weakSelf userCheckFilePreviewByRow:row];
  116. // //}
  117. // };
  118. }
  119. return cell;
  120. }
  121. - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
  122. NSInteger row = indexPath.row;
  123. if(row >=_audioArr.count){
  124. return 0.0;
  125. }
  126. recordFileModel *model = _audioArr[row];
  127. if (model.showAllType) {
  128. return 150;
  129. }
  130. return 65;
  131. }
  132. - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
  133. {
  134. NSInteger row = indexPath.row;
  135. // if(row < _curNASFileAudioMod.data.list.count){
  136. //
  137. // NASFilePicDataArrModel *dataModel = _curNASFileAudioMod.data.list[row];
  138. // //videoPlayViewController *vc = [videoPlayViewController new];
  139. // videoPlayByAVPlayerViewController *vc = [videoPlayByAVPlayerViewController new];
  140. // vc.VideoDataMode = dataModel;
  141. // [self.navigationController pushViewController:vc animated:YES];
  142. //
  143. // KWeakSelf
  144. // vc.didNeedDeleteFile = ^(NSString * _Nonnull filePath) {
  145. // [weakSelf deleteNetDataByFilePath:filePath];
  146. // };
  147. // }
  148. }
  149. #pragma mark 空数据
  150. - (UIImage *)imageForEmptyDataSet:(UIScrollView *)scrollView {
  151. NSString *imageName = @"common_no_data_pic";
  152. return [UIImage imageNamed:imageName];
  153. }
  154. - (NSAttributedString *)titleForEmptyDataSet:(UIScrollView *)scrollView {
  155. NSString *text = NSLocalizedString(@"common_no_data_tip",nil);
  156. NSDictionary *attributes = @{NSFontAttributeName: [UIFont systemFontOfSize:16.0f],
  157. NSForegroundColorAttributeName: HW999999Color};
  158. return [[NSAttributedString alloc] initWithString:text attributes:attributes];
  159. }
  160. //调整图片位置
  161. - (CGFloat)verticalOffsetForEmptyDataSet:(UIScrollView *)scrollView {
  162. return -150;
  163. }
  164. #pragma mark 读取本地数据
  165. - (void)getRecordDataFun
  166. {
  167. NSString *documentsDirectory = kSHPath_Record;
  168. NSFileManager *fileManager = [NSFileManager defaultManager];
  169. NSError *error = nil;
  170. NSArray *fileList = [fileManager contentsOfDirectoryAtPath:documentsDirectory error:&error];
  171. if (error) {
  172. HLog(@"Error reading contents of directory: %@", error.localizedDescription);
  173. }
  174. BOOL isFirstType = YES;
  175. for (NSString *fileName in fileList) {
  176. NSString *filePath = [documentsDirectory stringByAppendingPathComponent:fileName];
  177. // 获取文件属性
  178. NSDictionary *fileAttributes = [fileManager attributesOfItemAtPath:filePath error:&error];
  179. if (error) {
  180. NSLog(@"获取文件属性出错: %@ - %@", fileName, error.localizedDescription);
  181. error = nil;
  182. continue;
  183. }
  184. // 判断是否是目录
  185. BOOL isDirectory = [fileAttributes[NSFileType] isEqualToString:NSFileTypeDirectory];
  186. // 获取文件大小
  187. unsigned long long fileSize = [fileAttributes[NSFileSize] unsignedLongLongValue];
  188. recordFileModel *model = [recordFileModel new];
  189. model.fileName = fileName;
  190. model.filePath = filePath;
  191. model.fileSize = fileSize;
  192. model.isDirectory = isDirectory;
  193. model.modificationDate = fileAttributes[NSFileModificationDate] ?: [NSDate date];
  194. NSURL *fileUrl = [NSURL URLWithString:model.filePath];
  195. NSTimeInterval time = [self getDurationOfAudioFile:fileUrl];
  196. model.totalTime = (NSInteger)ceil(time); // 结果为 5;
  197. if (isFirstType) {
  198. model.showAllType = YES;
  199. }
  200. // 创建文件信息字典
  201. // NSDictionary *fileInfo = @{
  202. // @"name": fileName,
  203. // @"path": filePath,
  204. // @"size": @(fileSize),
  205. // @"isDirectory": @(isDirectory),
  206. // @"modificationDate": fileAttributes[NSFileModificationDate] ?: [NSDate date]
  207. // };
  208. [_audioArr addObject:model];
  209. }
  210. }
  211. #pragma mark 获取录音文件的时长
  212. - (NSTimeInterval)getDurationOfAudioFile:(NSURL *)fileURL {
  213. NSError *error;
  214. AVAudioPlayer *player = [[AVAudioPlayer alloc] initWithContentsOfURL:fileURL error:&error];
  215. if (error) {
  216. HLog(@"Error: %@", error.localizedDescription);
  217. return 0;
  218. }
  219. return player.duration;
  220. }
  221. #pragma mark 点击了录音
  222. - (void)didClickRecordFun
  223. {
  224. if(_recordingV){
  225. return;
  226. }
  227. //检测麦克风权限
  228. AVAudioSessionRecordPermission permissionStatus = [[AVAudioSession sharedInstance] recordPermission];
  229. // MicrophonePermissionStatus status;
  230. // switch (permissionStatus) {
  231. // case AVAudioSessionRecordPermissionUndetermined:
  232. // status = MicrophonePermissionStatusNotDetermined;
  233. // break;
  234. // case AVAudioSessionRecordPermissionDenied:
  235. // status = MicrophonePermissionStatusDenied;
  236. // break;
  237. // case AVAudioSessionRecordPermissionGranted:
  238. // status = MicrophonePermissionStatusGranted;
  239. // break;
  240. // }
  241. if (permissionStatus == AVAudioSessionRecordPermissionDenied) {
  242. NSString *tip = NSLocalizedString(@"mine_record_microphone_tip",nil);
  243. [[iToast makeText:tip] show];
  244. return;
  245. }
  246. else if(permissionStatus == AVAudioSessionRecordPermissionUndetermined) {
  247. KWeakSelf
  248. [[AVAudioSession sharedInstance] requestRecordPermission:^(BOOL granted) {
  249. dispatch_async(dispatch_get_main_queue(), ^{
  250. if (granted) {
  251. [weakSelf beginRecordFun];
  252. } else {
  253. }
  254. });
  255. }];
  256. return;
  257. }
  258. [self beginRecordFun];
  259. }
  260. #pragma mark 弹起录音功能
  261. - (void)beginRecordFun
  262. {
  263. _recordingV = [[recordingView alloc] init];
  264. [ksharedAppDelegate.window addSubview:_recordingV];
  265. [_recordingV mas_makeConstraints:^(MASConstraintMaker *make) {
  266. make.left.mas_equalTo(0.f);
  267. make.right.mas_equalTo(0.f);
  268. make.bottom.mas_equalTo(0.f);
  269. make.top.mas_equalTo(0);
  270. }];
  271. [_recordingV beginRecordFun];
  272. KWeakSelf
  273. _recordingV.didClickRecordEndFun = ^{
  274. [weakSelf deleteRecordingViewFun];
  275. };
  276. }
  277. #pragma mark 删除录音中界面
  278. - (void)deleteRecordingViewFun
  279. {
  280. [_recordingV removeFromSuperview];
  281. _recordingV = nil;
  282. }
  283. @end