ChatMessageModel.m 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591
  1. //
  2. // ChatMessageModel.m
  3. // AIIM
  4. //
  5. // Created by qitewei on 2025/5/14.
  6. //
  7. #import "ChatMessageModel.h"
  8. #import "CryptoAES.h"
  9. #import "ChatsStore.h"
  10. #import "AVFoundation/AVFoundation.h"
  11. #import "FileNetApi.h"
  12. @implementation ChatMessageModel
  13. + (instancetype)modelWithDictionary:(NSDictionary *)dict {
  14. ChatMessageModel *model = [[ChatMessageModel alloc] init];
  15. [model setupWithDictionary:dict];
  16. return model;
  17. }
  18. - (void)setupWithDictionary:(NSDictionary *)dict {
  19. NSMutableDictionary * mutableDict = [NSMutableDictionary dictionaryWithDictionary:dict];
  20. [mutableDict jk_each:^(id k, id v) {
  21. if ([v isKindOfClass:[NSNull class]]) {
  22. [mutableDict setObject:@"" forKey:k];
  23. }
  24. }];
  25. //原消息
  26. self.formerMessage = dict;
  27. self.chatId = mutableDict[@"chatId"];
  28. // 消息类型
  29. NSInteger type = [mutableDict[@"messageType"] integerValue];
  30. self.messageType = (ChatMessageType)type;
  31. self.type = [mutableDict[@"type"] integerValue];
  32. self.nickName = mutableDict[@"fromName"]?:@"";
  33. self.avatar = mutableDict[@"fromAvatar"]?:@"";
  34. // 通用内容
  35. // self.content = mutableDict[@"content"] ?: @"";//本地明文存储
  36. self.content =[CryptoAES.shareInstance decryptDataL:mutableDict[@"content"] ?: @""];//本地加密存储
  37. self.msgId = mutableDict[@"id"];
  38. self.fromId = mutableDict[@"fromId"];
  39. // 发送方标识
  40. NSDictionary *userinfo = [UDManager.shareInstance getDDManager:dkuserinfo];
  41. NSString *userId = userinfo[@"id"];
  42. if([self.fromId isEqualToString:userId]){
  43. self.isSender=true;
  44. }
  45. else{
  46. self.isSender=false;
  47. }
  48. // 处理媒体尺寸
  49. CGFloat width = [mutableDict[@"width"] floatValue];
  50. CGFloat height = [mutableDict[@"height"] floatValue];
  51. if (width > 0 && height > 0) {
  52. self.mediaSize = CGSizeMake(width, height);
  53. } else {
  54. // 默认尺寸
  55. self.mediaSize = CGSizeMake(200, 150);
  56. }
  57. self.placeholderImage = kImageMake(@"pictrue_placeholder");
  58. // 文件消息
  59. NSDictionary * extend = [mutableDict[@"extend"] isKindOfClass:NSDictionary.class]?mutableDict[@"extend"]:@{};
  60. self.fileName = extend[@"fileName"] ?: @"未知文件";
  61. self.fileSize = extend[@"size"] ?: @"0KB";
  62. self.url = extend[@"url"] ?: @"";
  63. NSCharacterSet *allowedCharacters = [NSCharacterSet URLQueryAllowedCharacterSet];
  64. self.url = [self.url stringByAddingPercentEncodingWithAllowedCharacters:allowedCharacters];
  65. self.localurl = extend[@"localurl"] ?: @"";
  66. self.quoteMessage = ![extend jk_hasKey:@"quoteMessage"] ?NULL: [ChatMessageModel modelWithDictionary:extend[@"quoteMessage"]];
  67. // 语音消息
  68. NSInteger duration = [extend[@"time"] integerValue];
  69. if (duration<=60) {
  70. self.voiceDuration = duration;
  71. }else{
  72. self.voiceDuration = duration/1000;
  73. }
  74. self.voiceWidth = self.voiceDuration==0?0:[self voiceBubbleWidth];
  75. //文件传输成功或失败
  76. self.fileError = 0;
  77. NSInteger fileError = [extend[@"fileError"] integerValue];
  78. if (fileError!=0) {
  79. self.fileError = fileError;
  80. }
  81. else{
  82. if(self.url.length>0){
  83. self.fileError = 0;
  84. }
  85. }
  86. //合并转发
  87. self.forwardMsgArray = extend[@"messageList"] ?:@[];
  88. // 通话记录
  89. self.callDuration = [mutableDict[@"duration"] integerValue];
  90. self.isCallSuccess = [mutableDict[@"result"] boolValue];
  91. self.isVideo = [mutableDict[@"video"] boolValue];
  92. //@相关
  93. self.atAll = extend[@"atAll"]?[extend[@"atAll"] boolValue]:NO;
  94. self.atUserIds = extend[@"atUserIds"]?:@[];
  95. // 时间戳(如果需要)
  96. self.timestamp = [mutableDict[@"timestamp"] longLongValue];
  97. self.localtime = [mutableDict[@"localtime"] longLongValue];
  98. self.formatterTime = [self timeF:self.timestamp];
  99. // 其他自定义字段...
  100. self.readStatus = [self getReadStatus];
  101. }
  102. - (void)exchangeModelWithModel:(ChatMessageModel *)model{
  103. self.msgId = model.msgId;
  104. self.formerMessage = model.formerMessage;
  105. if(self.messageType!=model.messageType){
  106. self.cellHeight=0;
  107. }
  108. self.messageType = model.messageType;
  109. self.type = model.type;
  110. self.isSender = model.isSender;
  111. self.content = model.content;
  112. self.msgId = model.msgId;
  113. self.mediaSize = model.mediaSize;
  114. self.placeholderImage = model.placeholderImage;
  115. self.fileName = model.fileName;
  116. self.fileSize = model.fileSize;
  117. self.url = model.url;
  118. self.localurl = model.localurl;
  119. //文件传输成功或失败
  120. self.fileError = model.fileError;
  121. // 通话记录
  122. self.callDuration = model.callDuration;
  123. self.isCallSuccess = model.isCallSuccess;
  124. self.isVideo = model.isVideo;
  125. self.avatar = model.avatar;
  126. self.nickName = model.nickName;
  127. //@相关
  128. self.atAll = model.atAll;
  129. self.atUserIds = model.atUserIds;
  130. // 时间戳(如果需要)
  131. self.timestamp = model.timestamp;
  132. self.localtime = model.localtime;
  133. self.formatterTime = model.formatterTime;
  134. // // 其他自定义字段...
  135. // 其他自定义字段...
  136. self.readStatus = [self getReadStatus];
  137. }
  138. -(NSString *)timeF:(NSInteger)time{
  139. //NSLog(@"time:%ld",(long)time);
  140. // 创建日期格式器
  141. NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
  142. [formatter setDateFormat:@"dd"]; // 设置你想要的日期格式
  143. long long timestamp =(long)time/1000; // 例如:2021-10-01 00:00:00 UTC
  144. // 转换为NSDate
  145. NSDate *date = [NSDate dateWithTimeIntervalSince1970:timestamp];
  146. NSString *dateString = [formatter stringFromDate:date];
  147. NSDate *now = [NSDate date];
  148. NSTimeInterval trt = [now timeIntervalSince1970];
  149. date = [NSDate dateWithTimeIntervalSince1970:trt];
  150. NSString *tdateString = [formatter stringFromDate:date];
  151. NSInteger shijiancha = trt-timestamp;
  152. if(shijiancha<60){
  153. return NSLocalizedString(@"time-oneminint", @"");
  154. }
  155. if(shijiancha>24*3600||dateString.intValue!=tdateString.intValue){
  156. // 假设这是你的时间戳(以秒为单位)
  157. long long timestamp =(long)time/1000; // 例如:2021-10-01 00:00:00 UTC
  158. // 转换为NSDate
  159. NSDate *date = [NSDate dateWithTimeIntervalSince1970:timestamp];
  160. // 创建日期格式器
  161. NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
  162. [formatter setDateFormat:@"yyyy-MM-dd HH:mm"]; // 设置你想要的日期格式
  163. // 转换为字符串
  164. NSString *dateString = [formatter stringFromDate:date];
  165. return dateString;
  166. }
  167. else{
  168. NSInteger xiaoshi = shijiancha/3600;
  169. NSInteger fenzhong = shijiancha/60;
  170. if(xiaoshi>0){
  171. // 假设这是你的时间戳(以秒为单位)
  172. long long timestamp =(long)time/1000; // 例如:2021-10-01 00:00:00 UTC
  173. // 转换为NSDate
  174. NSDate *date = [NSDate dateWithTimeIntervalSince1970:timestamp];
  175. // 创建日期格式器
  176. NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
  177. [formatter setDateFormat:@"HH:mm"]; // 设置你想要的日期格式
  178. // 转换为字符串
  179. NSString *dateString = [formatter stringFromDate:date];
  180. return dateString;
  181. }
  182. else{
  183. return [NSString stringWithFormat:@"%ld%@",(long)fenzhong,NSLocalizedString(@"time-outmin", @"")];
  184. }
  185. }
  186. return @"";
  187. }
  188. - (NSString *)getReadStatus{
  189. NSString * readStatus;
  190. self.readstate = 0;
  191. if(self.timestamp == 0){
  192. return @"";
  193. }
  194. if(self.messageType==11||self.messageType==12){
  195. return @"";
  196. }
  197. if(self.type==0){
  198. if (self.localtime != 0 && self.localtime == self.timestamp) {
  199. NSDate *now = [NSDate date];
  200. NSTimeInterval trt = [now timeIntervalSince1970];
  201. NSInteger time = trt*1000;
  202. NSInteger outTime =time-self.localtime;
  203. if(outTime>33000){
  204. if(self.messageType==1||self.messageType==2||self.messageType==5){
  205. readStatus = @"正在发送";
  206. self.readstate = 3;
  207. }else{
  208. readStatus = @"发送失败";
  209. self.readstate = 4;
  210. }
  211. }else{
  212. readStatus = @"正在发送";
  213. self.readstate = 3;
  214. }
  215. }
  216. else{
  217. //判断已读未读
  218. if(self.timestamp>ChatsStore.shareInstance.lastreadTime){
  219. readStatus = @"未读";
  220. self.readstate = 1;
  221. }
  222. else{
  223. readStatus = @"已读";
  224. self.readstate = 2;
  225. }
  226. if(self.fileError==1){
  227. readStatus = @"發送失敗,點擊重發";
  228. self.readstate = 4;
  229. }
  230. }
  231. }else{
  232. return @"";
  233. }
  234. return readStatus;
  235. }
  236. - (void)generateThumbnailWithCompletion:(void(^)(UIImage *thumbnail))completion {
  237. if (self.videoThumbnailImage) {
  238. if (completion) completion(self.videoThumbnailImage);
  239. return;
  240. }
  241. NSURL *videoURL = nil;
  242. if (self.localurl.length != 0 && [[NSFileManager defaultManager] fileExistsAtPath:self.localurl]) {
  243. NSLog(@"generateThumbnailWithCompletion localurl:%@",self.localurl);
  244. videoURL = [NSURL fileURLWithPath:self.localurl];
  245. dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
  246. AVURLAsset *asset = [[AVURLAsset alloc] initWithURL:videoURL options:nil];
  247. AVAssetImageGenerator *generator = [[AVAssetImageGenerator alloc] initWithAsset:asset];
  248. generator.appliesPreferredTrackTransform = YES;
  249. CMTime acttime;
  250. NSError *error = nil;
  251. CGImageRef imageRef = [generator copyCGImageAtTime:CMTimeMake(0, 600) actualTime:&acttime error:&error];
  252. NSLog(@"error:%@",error);
  253. if (!error && imageRef) {
  254. UIImage *thumbnail = [[UIImage alloc] initWithCGImage:imageRef];
  255. CGImageRelease(imageRef);
  256. // 缓存到内存
  257. self.videoThumbnailImage = thumbnail;
  258. if (completion){
  259. completion(thumbnail);
  260. }
  261. } else {
  262. if (completion) completion(nil);
  263. }
  264. });
  265. }else{
  266. NSLog(@"generateThumbnailWithCompletion url");
  267. if (self.url.length == 0){
  268. completion(nil);
  269. return;
  270. }
  271. NSDictionary *options = @{AVURLAssetAllowsCellularAccessKey: @YES,
  272. AVURLAssetPreferPreciseDurationAndTimingKey: @YES};
  273. AVURLAsset *asset = [AVURLAsset URLAssetWithURL:getURL(self.url) options:options];
  274. // 创建图像生成器
  275. AVAssetImageGenerator *generator = [AVAssetImageGenerator assetImageGeneratorWithAsset:asset];
  276. generator.appliesPreferredTrackTransform = YES; // 应用视频的方向
  277. generator.maximumSize = CGSizeMake(320, 0); // 设置最大尺寸,保持宽高比
  278. // 异步生成缩略图
  279. [generator generateCGImagesAsynchronouslyForTimes:@[[NSValue valueWithCMTime:kCMTimeZero]]
  280. completionHandler:^(CMTime requestedTime, CGImageRef image, CMTime actualTime, AVAssetImageGeneratorResult result, NSError *error) {
  281. __block UIImage *thumbnail = nil;
  282. // 处理生成结果
  283. if (result == AVAssetImageGeneratorSucceeded && image) {
  284. // 创建UIImage,注意CGImageCreateCopy不是必需的
  285. thumbnail = [UIImage imageWithCGImage:image];
  286. self.videoThumbnailImage = thumbnail;
  287. // 重要:虽然UIImage会retain CGImageRef,但最佳实践是手动管理
  288. // 这里不需要调用CGImageRelease,因为imageWithCGImage会自动retain
  289. }
  290. dispatch_async(dispatch_get_main_queue(), ^{
  291. if (completion) completion(thumbnail);
  292. });
  293. }];
  294. }
  295. }
  296. //下载视频文件
  297. -(void)xiazaishipin:(void(^)(NSInteger persent))loading{
  298. NSLog(@"xiazaishipin--------");
  299. if(!self.isSender){
  300. NSString *localFileurl = [self.localurl stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLPathAllowedCharacterSet]];
  301. if (self.localurl.length != 0 && [[NSFileManager defaultManager] fileExistsAtPath:localFileurl]){
  302. // NSLog(@"文件已经存在本地");
  303. if (loading) {
  304. loading(100);
  305. }
  306. }
  307. else{
  308. // NSLog(@"文件不存在");
  309. if(self.url&&self.url.length != 0){
  310. NSURL *documentsDirectoryURL = [[NSFileManager defaultManager] URLForDirectory:NSDocumentDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:NO error:nil];
  311. NSURL *tempUrl = [NSURL URLWithString:self.url];
  312. NSString *fileName = tempUrl.lastPathComponent;
  313. NSString *fileExtension = [fileName pathExtension];
  314. NSString *newfileName = [NSString stringWithFormat:@"%@.%@", self.msgId,fileExtension];
  315. documentsDirectoryURL = [documentsDirectoryURL URLByAppendingPathComponent:newfileName];
  316. NSLog(@"文件已经存在本地1-:%@",documentsDirectoryURL.path);
  317. if ([[NSFileManager defaultManager] fileExistsAtPath:documentsDirectoryURL.path]){
  318. NSLog(@"文件已经存在本地2-:%@",documentsDirectoryURL.path);
  319. NSMutableDictionary *mutableDict = [self.formerMessage mutableCopy];
  320. NSMutableDictionary *extend = [self.formerMessage[@"extend"] mutableCopy];
  321. [extend setObject:documentsDirectoryURL.path forKey:@"localurl"];
  322. [mutableDict setObject:extend forKey:@"extend"];
  323. self.localurl = documentsDirectoryURL.path;
  324. NSDictionary *NewMsg = [mutableDict copy];
  325. [ChatsStore.shareInstance reciveMsg:NewMsg];
  326. if (loading) {
  327. loading(100);
  328. }
  329. }
  330. else{
  331. [FileNetApi downLoadWToken:getURL(self.url) thrid:self.msgId succ:^(int code, NSDictionary * res) {
  332. if(res!=nil){
  333. NSMutableDictionary *mutableDict = [self.formerMessage mutableCopy];
  334. NSMutableDictionary *extend = [self.formerMessage[@"extend"] mutableCopy];
  335. [extend setObject:res[@"filePath"] forKey:@"localurl"];
  336. [mutableDict setObject:extend forKey:@"extend"];
  337. self.localurl = res[@"filePath"];
  338. NSDictionary *NewMsg = [mutableDict copy];
  339. [ChatsStore.shareInstance reciveMsg:NewMsg];
  340. if (loading) {
  341. loading(100);
  342. }
  343. }
  344. else{
  345. if (code>=0&&code<200) {
  346. if (loading) {
  347. loading(code);
  348. }
  349. }
  350. }
  351. } fail:^(NSError * _Nonnull error) {
  352. NSLog(@"error:%@",error);
  353. }];
  354. }
  355. }
  356. else{
  357. if (loading) {
  358. loading(0);
  359. }
  360. }
  361. }
  362. }
  363. else{
  364. NSLog(@"downLoadWToken xiazaishipin-----");
  365. }
  366. }
  367. -(void)xiazaiwenjian:(void(^)(NSInteger persent))loading{
  368. NSLog(@"xiazaiwenjian---");
  369. if (self.isSender) {
  370. return;
  371. }
  372. else{
  373. // NSLog(@"self.localurl2:%@",self.localurl);
  374. if (self.localurl.length != 0 && [[NSFileManager defaultManager] fileExistsAtPath:self.localurl]){
  375. // NSLog(@"文件已经存在本地");
  376. if (loading) {
  377. loading(100);
  378. }
  379. return;
  380. }
  381. else{
  382. if(self.url&&self.url.length != 0){
  383. NSURL *documentsDirectoryURL = [[NSFileManager defaultManager] URLForDirectory:NSDocumentDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:NO error:nil];
  384. NSURL *tempUrl = [NSURL URLWithString:self.url];
  385. NSString *fileName = tempUrl.lastPathComponent;
  386. NSString *fileExtension = [fileName pathExtension];
  387. NSString *newfileName = [NSString stringWithFormat:@"%@.%@", self.msgId,fileExtension];
  388. documentsDirectoryURL = [documentsDirectoryURL URLByAppendingPathComponent:newfileName];
  389. NSLog(@"文件已经存在本地1-:%@",documentsDirectoryURL.path);
  390. if ([[NSFileManager defaultManager] fileExistsAtPath:documentsDirectoryURL.path]){
  391. NSLog(@"文件已经存在本地2-:%@",documentsDirectoryURL.path);
  392. NSMutableDictionary *mutableDict = [self.formerMessage mutableCopy];
  393. NSMutableDictionary *extend = [self.formerMessage[@"extend"] mutableCopy];
  394. [extend setObject:documentsDirectoryURL.path forKey:@"localurl"];
  395. [mutableDict setObject:extend forKey:@"extend"];
  396. self.localurl = documentsDirectoryURL.path;
  397. NSDictionary *NewMsg = [mutableDict copy];
  398. [ChatsStore.shareInstance reciveMsg:NewMsg];
  399. if (loading) {
  400. loading(100);
  401. }
  402. }
  403. else{
  404. [FileNetApi downLoadWToken:getURL(self.url) thrid:self.msgId succ:^(int code, NSDictionary * res) {
  405. if(res!=nil){
  406. NSMutableDictionary *mutableDict = [self.formerMessage mutableCopy];
  407. NSMutableDictionary *extend = [self.formerMessage[@"extend"] mutableCopy];
  408. [extend setObject:res[@"filePath"] forKey:@"localurl"];
  409. [mutableDict setObject:extend forKey:@"extend"];
  410. self.localurl = res[@"filePath"];
  411. NSDictionary *NewMsg = [mutableDict copy];
  412. [ChatsStore.shareInstance reciveMsg:NewMsg];
  413. if (loading) {
  414. loading(100);
  415. }
  416. }
  417. else{
  418. if (code>=0&&code<200) {
  419. if (loading) {
  420. loading(code);
  421. }
  422. }
  423. }
  424. } fail:^(NSError * _Nonnull error) {
  425. NSLog(@"error:%@",error);
  426. }];
  427. }
  428. }
  429. else{
  430. if (loading) {
  431. loading(0);
  432. }
  433. }
  434. }
  435. }
  436. }
  437. -(void)xiazaiyuyin:(void(^)(NSInteger persent))loading{
  438. NSLog(@"xiazaiwenjian---");
  439. if (self.isSender) {
  440. return;
  441. }
  442. else{
  443. // NSLog(@"self.localurl2:%@",self.localurl);
  444. if (self.localurl.length != 0 && [[NSFileManager defaultManager] fileExistsAtPath:self.localurl]){
  445. // NSLog(@"文件已经存在本地");
  446. if (loading) {
  447. loading(100);
  448. }
  449. return;
  450. }
  451. if(self.url&&self.url.length != 0){
  452. NSURL *documentsDirectoryURL = [[NSFileManager defaultManager] URLForDirectory:NSDocumentDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:NO error:nil];
  453. NSURL *tempUrl = [NSURL URLWithString:self.url];
  454. NSString *fileName = tempUrl.lastPathComponent;
  455. NSString *fileExtension = [fileName pathExtension];
  456. NSString *newfileName = [NSString stringWithFormat:@"%@.%@", self.msgId,fileExtension];
  457. documentsDirectoryURL = [documentsDirectoryURL URLByAppendingPathComponent:newfileName];
  458. NSLog(@"文件已经存在本地1-:%@",documentsDirectoryURL.path);
  459. if ([[NSFileManager defaultManager] fileExistsAtPath:documentsDirectoryURL.path]){
  460. NSLog(@"文件已经存在本地2-:%@",documentsDirectoryURL.path);
  461. NSMutableDictionary *mutableDict = [self.formerMessage mutableCopy];
  462. NSMutableDictionary *extend = [self.formerMessage[@"extend"] mutableCopy];
  463. [extend setObject:documentsDirectoryURL.path forKey:@"localurl"];
  464. [mutableDict setObject:extend forKey:@"extend"];
  465. self.localurl = documentsDirectoryURL.path;
  466. NSDictionary *NewMsg = [mutableDict copy];
  467. [ChatsStore.shareInstance reciveMsg:NewMsg];
  468. if (loading) {
  469. loading(100);
  470. }
  471. }
  472. else{
  473. [FileNetApi downLoadWToken:getURL(self.url) thrid:self.msgId succ:^(int code, NSDictionary * res) {
  474. if(res!=nil){
  475. NSMutableDictionary *mutableDict = [self.formerMessage mutableCopy];
  476. NSMutableDictionary *extend = [self.formerMessage[@"extend"] mutableCopy];
  477. [extend setObject:res[@"filePath"] forKey:@"localurl"];
  478. [mutableDict setObject:extend forKey:@"extend"];
  479. self.localurl = res[@"filePath"];
  480. NSDictionary *NewMsg = [mutableDict copy];
  481. [ChatsStore.shareInstance reciveMsg:NewMsg];
  482. if (loading) {
  483. loading(100);
  484. }
  485. }
  486. else{
  487. if (code>=0&&code<200) {
  488. if (loading) {
  489. loading(code);
  490. }
  491. }
  492. }
  493. } fail:^(NSError * _Nonnull error) {
  494. NSLog(@"error:%@",error);
  495. }];
  496. }
  497. }
  498. else{
  499. if (loading) {
  500. loading(0);
  501. }
  502. }
  503. }
  504. }
  505. -(void)setuploadPersent:(NSInteger)persent localtime:(NSInteger)localtime{
  506. if(self.uploadPersentChange && localtime==self.localtime){
  507. self.uploadPersentChange(persent,localtime);
  508. }
  509. }
  510. // 根据语音时长计算气泡宽度
  511. - (CGFloat)voiceBubbleWidth {
  512. // 基础宽度
  513. CGFloat minWidth = 60.0f;
  514. CGFloat maxWidth = 200.0f;
  515. // 最大限制时长(如60秒)
  516. NSInteger maxDuration = 60;
  517. NSInteger duration = MIN(self.voiceDuration, maxDuration);
  518. // 线性增长计算
  519. CGFloat width = minWidth + (maxWidth - minWidth) * (duration / (CGFloat)maxDuration);
  520. return width;
  521. }
  522. @end