WFCUUtilities.m 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385
  1. //
  2. // Utilities.m
  3. // WFChat UIKit
  4. //
  5. // Created by WF Chat on 2017/9/1.
  6. // Copyright © 2017年 WildFireChat. All rights reserved.
  7. //
  8. #import "WFCUUtilities.h"
  9. #import "WFCUImage.h"
  10. #import <AVFoundation/AVFoundation.h>
  11. #import <AVKit/AVKit.h>
  12. #define kIs_iPhoneX ([UIScreen mainScreen].bounds.size.height == 812.0f ||[UIScreen mainScreen].bounds.size.height == 896.0f ||[UIScreen mainScreen].bounds.size.height == 844.0f ||[UIScreen mainScreen].bounds.size.height == 926.0f ||[UIScreen mainScreen].bounds.size.height == 932.0f)
  13. #define kTabbarSafeBottomMargin (kIs_iPhoneX ? 34.f : 0.f)
  14. @implementation WFCUUtilities
  15. + (CGSize)getTextDrawingSize:(NSString *)text
  16. font:(UIFont *)font
  17. constrainedSize:(CGSize)constrainedSize {
  18. if (text.length <= 0) {
  19. return CGSizeZero;
  20. }
  21. if ([text respondsToSelector:@selector(boundingRectWithSize:
  22. options:
  23. attributes:
  24. context:)]) {
  25. return [text boundingRectWithSize:constrainedSize
  26. options:(NSStringDrawingTruncatesLastVisibleLine |
  27. NSStringDrawingUsesLineFragmentOrigin |
  28. NSStringDrawingUsesFontLeading)
  29. attributes:@{
  30. NSFontAttributeName : font
  31. }
  32. context:nil]
  33. .size;
  34. } else {
  35. return [text sizeWithFont:font
  36. constrainedToSize:constrainedSize
  37. lineBreakMode:NSLineBreakByTruncatingTail];
  38. }
  39. }
  40. + (NSString *)formatTimeLabel:(int64_t)timestamp {
  41. if (timestamp == 0) {
  42. return nil;
  43. }
  44. NSDate *date = [NSDate dateWithTimeIntervalSince1970:timestamp/1000];
  45. NSDate *current = [[NSDate alloc] init];
  46. NSCalendar *calendar = [NSCalendar currentCalendar];
  47. NSInteger years = [calendar component:NSCalendarUnitYear fromDate:date];
  48. NSInteger curYears = [calendar component:NSCalendarUnitYear fromDate:current];
  49. if ([calendar isDateInToday:date]) {
  50. NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
  51. [formatter setDateFormat:@"HH:mm"];
  52. return [formatter stringFromDate:date];
  53. } else if([calendar isDateInYesterday:date]) {
  54. return @"昨天";
  55. } else {
  56. if (years == curYears) {
  57. NSInteger weeks = [calendar component:NSCalendarUnitWeekOfYear fromDate:date];
  58. NSInteger curWeeks = [calendar component:NSCalendarUnitWeekOfYear fromDate:current];
  59. NSInteger weekDays = [calendar component:NSCalendarUnitWeekday fromDate:date];
  60. if (weeks == curWeeks) {
  61. switch (weekDays) {
  62. case 1:
  63. return @"周日";
  64. break;
  65. case 2:
  66. return @"周一";
  67. break;
  68. case 3:
  69. return @"周二";
  70. break;
  71. case 4:
  72. return @"周三";
  73. break;
  74. case 5:
  75. return @"周四";
  76. break;
  77. case 6:
  78. return @"周五";
  79. break;
  80. case 7:
  81. return @"周六";
  82. break;
  83. default:
  84. break;
  85. }
  86. return [NSString stringWithFormat:@"周%ld", (long)weekDays];
  87. } else {
  88. NSInteger month = [calendar component:NSCalendarUnitMonth fromDate:date];
  89. NSInteger day = [calendar component:NSCalendarUnitDay fromDate:date];
  90. return [NSString stringWithFormat:@"%d月%d号", (int)month, (int)day];
  91. }
  92. } else {
  93. NSInteger month = [calendar component:NSCalendarUnitMonth fromDate:date];
  94. NSInteger day = [calendar component:NSCalendarUnitDay fromDate:date];
  95. return [NSString stringWithFormat:@"%d年%d月%d号",(int)years,(int)month, (int)day];
  96. }
  97. }
  98. }
  99. + (NSString *)formatTimeDetailLabel:(int64_t)timestamp {
  100. if (timestamp == 0) {
  101. return nil;
  102. }
  103. NSDate *date = [NSDate dateWithTimeIntervalSince1970:timestamp/1000];
  104. NSDate *current = [[NSDate alloc] init];
  105. NSCalendar *calendar = [NSCalendar currentCalendar];
  106. NSInteger months = [calendar component:NSCalendarUnitMonth fromDate:date];
  107. NSInteger curMonths = [calendar component:NSCalendarUnitMonth fromDate:current];
  108. NSInteger years = [calendar component:NSCalendarUnitYear fromDate:date];
  109. NSInteger curYears = [calendar component:NSCalendarUnitYear fromDate:current];
  110. NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
  111. [formatter setDateFormat:@"HH:mm"];
  112. NSString *hourTimeStr = [formatter stringFromDate:date];
  113. NSInteger weeks = [calendar component:NSCalendarUnitWeekOfYear fromDate:date];
  114. NSInteger curWeeks = [calendar component:NSCalendarUnitWeekOfYear fromDate:current];
  115. NSInteger weekDays = [calendar component:NSCalendarUnitWeekday fromDate:date];
  116. if ([calendar isDateInToday:date]) {
  117. return hourTimeStr;
  118. } else if([calendar isDateInYesterday:date]) {
  119. return [NSString stringWithFormat:@"昨天 %@", hourTimeStr];
  120. } else if (years != curYears) {
  121. [formatter setDateFormat:@"yyyy'年'MM'月'dd'日 'HH':'mm"];
  122. return [formatter stringFromDate:date];
  123. } else if(months != curMonths) {
  124. if(weeks == curWeeks) {
  125. return [NSString stringWithFormat:@"%@ %@", [WFCUUtilities formatWeek:weekDays], hourTimeStr];
  126. }
  127. [formatter setDateFormat:@"MM'月'dd'日 'HH':'mm"];
  128. return [formatter stringFromDate:date];
  129. } else {
  130. if(weeks == curWeeks) {
  131. return [NSString stringWithFormat:@"%@ %@", [WFCUUtilities formatWeek:weekDays], hourTimeStr];
  132. }
  133. [formatter setDateFormat:@"dd'日 'HH':'mm"];
  134. return [formatter stringFromDate:date];
  135. }
  136. }
  137. + (NSString *)formatWeek:(NSUInteger)weekDays {
  138. weekDays = weekDays % 7;
  139. switch (weekDays) {
  140. case 2:
  141. return @"周一";
  142. case 3:
  143. return @"周二";
  144. case 4:
  145. return @"周三";
  146. case 5:
  147. return @"周四";
  148. case 6:
  149. return @"周五";
  150. case 0:
  151. return @"周六";
  152. case 1:
  153. return @"周日";
  154. default:
  155. break;
  156. }
  157. return nil;
  158. }
  159. + (UIImage *)thumbnailWithImage:(UIImage *)originalImage maxSize:(CGSize)size {
  160. CGSize originalsize = [originalImage size];
  161. //原图长宽均小于标准长宽的,不作处理返回原图
  162. if (originalsize.width<size.width && originalsize.height<size.height){
  163. return originalImage;
  164. }
  165. //原图长宽均大于标准长宽的,按比例缩小至最大适应值
  166. else if(originalsize.width>size.width && originalsize.height>size.height){
  167. CGFloat rate = 1.0;
  168. CGFloat widthRate = originalsize.width/size.width;
  169. CGFloat heightRate = originalsize.height/size.height;
  170. rate = widthRate>heightRate?heightRate:widthRate;
  171. CGImageRef imageRef = nil;
  172. if (heightRate>widthRate){
  173. imageRef = CGImageCreateWithImageInRect([originalImage CGImage], CGRectMake(0, originalsize.height/2-size.height*rate/2, originalsize.width, size.height*rate));//获取图片整体部分
  174. }else{
  175. imageRef = CGImageCreateWithImageInRect([originalImage CGImage], CGRectMake(originalsize.width/2-size.width*rate/2, 0, size.width*rate, originalsize.height));//获取图片整体部分
  176. }
  177. UIGraphicsBeginImageContext(size);//指定要绘画图片的大小
  178. CGContextRef con = UIGraphicsGetCurrentContext();
  179. CGContextTranslateCTM(con, 0.0, size.height);
  180. CGContextScaleCTM(con, 1.0, -1.0);
  181. CGContextDrawImage(con, CGRectMake(0, 0, size.width, size.height), imageRef);
  182. UIImage *standardImage = UIGraphicsGetImageFromCurrentImageContext();
  183. UIGraphicsEndImageContext();
  184. CGImageRelease(imageRef);
  185. return standardImage;
  186. }
  187. //原图长宽有一项大于标准长宽的,对大于标准的那一项进行裁剪,另一项保持不变
  188. else if(originalsize.height>size.height || originalsize.width>size.width){
  189. CGImageRef imageRef = nil;
  190. if(originalsize.height>size.height){
  191. imageRef = CGImageCreateWithImageInRect([originalImage CGImage], CGRectMake(0, originalsize.height/2-originalsize.width/2, originalsize.width, originalsize.width));//获取图片整体部分
  192. }
  193. else if (originalsize.width>size.width){
  194. imageRef = CGImageCreateWithImageInRect([originalImage CGImage], CGRectMake(originalsize.width/2-originalsize.height/2, 0, originalsize.height, originalsize.height));//获取图片整体部分
  195. }
  196. UIGraphicsBeginImageContext(size);//指定要绘画图片的大小
  197. CGContextRef con = UIGraphicsGetCurrentContext();
  198. CGContextTranslateCTM(con, 0.0, size.height);
  199. CGContextScaleCTM(con, 1.0, -1.0);
  200. CGContextDrawImage(con, CGRectMake(0, 0, size.width, size.height), imageRef);
  201. UIImage *standardImage = UIGraphicsGetImageFromCurrentImageContext();
  202. UIGraphicsEndImageContext();
  203. CGImageRelease(imageRef);
  204. return standardImage;
  205. }
  206. //原图为标准长宽的,不做处理
  207. else{
  208. return originalImage;
  209. }
  210. }
  211. + (NSString *)formatSizeLable:(int64_t)size {
  212. if (size < 1024) {
  213. return [NSString stringWithFormat:@"%lldB", size];
  214. } else if(size < 1024*1024) {
  215. return [NSString stringWithFormat:@"%lldK", size/1024];
  216. } else {
  217. return [NSString stringWithFormat:@"%.2fM", size/1024.f/1024];
  218. }
  219. }
  220. + (UIImage *)imageForExt:(NSString *)extName {
  221. NSString *fileImage = nil;
  222. if ([extName isEqualToString:@"doc"] || [extName isEqualToString:@"docx"] || [extName isEqualToString:@"pages"]) {
  223. fileImage = @"file_type_word";
  224. } else if ([extName isEqualToString:@"xls"] || [extName isEqualToString:@"xlsx"] || [extName isEqualToString:@"numbers"]) {
  225. fileImage = @"file_type_xls";
  226. } else if ([extName isEqualToString:@"ppt"] || [extName isEqualToString:@"pptx"] || [extName isEqualToString:@"keynote"]) {
  227. fileImage = @"file_type_ppt";
  228. } else if ([extName isEqualToString:@"pdf"]) {
  229. fileImage = @"file_type_pdf";
  230. } else if([extName isEqualToString:@"html"] || [extName isEqualToString:@"htm"]) {
  231. fileImage = @"file_type_html";
  232. } else if([extName isEqualToString:@"txt"]) {
  233. fileImage = @"file_type_text";
  234. } else if([extName isEqualToString:@"jpg"] || [extName isEqualToString:@"png"] || [extName isEqualToString:@"jpeg"]) {
  235. fileImage = @"file_type_image";
  236. } else if([extName isEqualToString:@"mp3"] || [extName isEqualToString:@"amr"] || [extName isEqualToString:@"acm"] || [extName isEqualToString:@"aif"]) {
  237. fileImage = @"file_type_audio";
  238. } else if([extName isEqualToString:@"mp4"] || [extName isEqualToString:@"avi"]
  239. || [extName isEqualToString:@"mov"] || [extName isEqualToString:@"asf"]
  240. || [extName isEqualToString:@"wmv"] || [extName isEqualToString:@"mpeg"]
  241. || [extName isEqualToString:@"ogg"] || [extName isEqualToString:@"mkv"]
  242. || [extName isEqualToString:@"rmvb"] || [extName isEqualToString:@"f4v"]) {
  243. fileImage = @"file_type_video";
  244. } else if([extName isEqualToString:@"exe"]) {
  245. fileImage = @"file_type_exe";
  246. } else if([extName isEqualToString:@"xml"]) {
  247. fileImage = @"file_type_xml";
  248. } else if([extName isEqualToString:@"zip"] || [extName isEqualToString:@"rar"]
  249. || [extName isEqualToString:@"gzip"] || [extName isEqualToString:@"gz"]) {
  250. fileImage = @"file_type_zip";
  251. } else {
  252. fileImage = @"file_type_unknown";
  253. }
  254. return [WFCUImage imageNamed:fileImage];
  255. }
  256. + (NSString *)getUnduplicatedPath:(NSString *)path {
  257. int count = 1;
  258. NSString *fileName = [path stringByDeletingPathExtension];
  259. NSString *fileExt = [path pathExtension];
  260. while ([[NSFileManager defaultManager] fileExistsAtPath:path]) {
  261. path = [[NSString stringWithFormat:@"%@(%d)", fileName, count++] stringByAppendingPathExtension:fileExt];
  262. }
  263. return path;
  264. }
  265. + (BOOL)isFileExist:(NSString *)filePath {
  266. return [[NSFileManager defaultManager] fileExistsAtPath:filePath];
  267. }
  268. + (CGFloat)wf_navigationHeight {
  269. return 44.f;
  270. }
  271. + (CGFloat)wf_statusBarHeight {
  272. if (@available(iOS 13.0, *)) {
  273. NSSet *set = [UIApplication sharedApplication].connectedScenes;
  274. UIWindowScene *windowScene = [set anyObject];
  275. UIStatusBarManager *statusBarManager = windowScene.statusBarManager;
  276. return statusBarManager.statusBarFrame.size.height;
  277. } else {
  278. return [UIApplication sharedApplication].statusBarFrame.size.height;
  279. }
  280. }
  281. + (CGFloat)wf_navigationFullHeight {
  282. return [WFCUUtilities wf_statusBarHeight] + 44;
  283. }
  284. + (CGFloat)wf_safeDistanceBottom {
  285. if (@available(iOS 13.0, *)) {
  286. NSSet *set = [UIApplication sharedApplication].connectedScenes;
  287. UIWindowScene *windowScene = [set anyObject];
  288. UIWindow *window = windowScene.windows.firstObject;
  289. return window.safeAreaInsets.bottom;
  290. } else if (@available(iOS 11.0, *)) {
  291. UIWindow *window = [UIApplication sharedApplication].windows.firstObject;
  292. return window.safeAreaInsets.bottom;
  293. }
  294. return kTabbarSafeBottomMargin;
  295. }
  296. + (BOOL)checkRecordOrCameraPermission:(BOOL)isAudio complete:(void (^)(BOOL granted))complete viewController:(UIViewController *)controller {
  297. AVAuthorizationStatus authStatus = [AVCaptureDevice authorizationStatusForMediaType:isAudio?AVMediaTypeAudio:AVMediaTypeVideo];
  298. if(authStatus == AVAuthorizationStatusRestricted) {
  299. [WFCUUtilities showPermissionAlertWithMessage:isAudio?@"没有麦克风权限,无法完成语音通话或者录音功能":@"没有录像权限,无法完成视频通话" withSettingAction:NO withController:controller];
  300. if(complete) complete(NO);
  301. } else if (authStatus == AVAuthorizationStatusDenied) {
  302. [WFCUUtilities showPermissionAlertWithMessage:isAudio?@"通话或者录音需要麦克风权限,请开启麦克风权限":@"视频通话需要摄像头权限,请开启摄像头权限" withSettingAction:YES withController:controller];
  303. if(complete) complete(NO);
  304. } else if (authStatus == AVAuthorizationStatusNotDetermined) {
  305. [AVCaptureDevice
  306. requestAccessForMediaType:isAudio?AVMediaTypeAudio:AVMediaTypeVideo
  307. completionHandler:^(BOOL granted) {
  308. if(!granted) {
  309. [WFCUUtilities showPermissionAlertWithMessage:isAudio?@"通话需要麦克风权限,请开启麦克风权限":@"视频通话需要摄像头权限,请开启摄像头权限" withSettingAction:YES withController:controller];
  310. }
  311. if(complete) {
  312. dispatch_async(dispatch_get_main_queue(), ^{
  313. complete(granted);
  314. });
  315. }
  316. }];
  317. } else {
  318. if(complete) complete(YES);
  319. return YES;
  320. }
  321. return NO;
  322. }
  323. + (void)showPermissionAlertWithMessage:(NSString *)message withSettingAction:(BOOL)goSetting withController:(UIViewController *)controller {
  324. UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"权限请求"
  325. message:message
  326. preferredStyle:UIAlertControllerStyleAlert];
  327. if(goSetting) {
  328. UIAlertAction *settingsAction = [UIAlertAction actionWithTitle:@"前往设置"
  329. style:UIAlertActionStyleDefault
  330. handler:^(UIAlertAction * _Nonnull action) {
  331. NSURL *settingsURL = [NSURL URLWithString:UIApplicationOpenSettingsURLString];
  332. if ([[UIApplication sharedApplication] canOpenURL:settingsURL]) {
  333. if (@available(iOS 10.0, *)) {
  334. [[UIApplication sharedApplication] openURL:settingsURL options:@{} completionHandler:nil];
  335. } else {
  336. [[UIApplication sharedApplication] openURL:settingsURL];
  337. }
  338. }
  339. }];
  340. [alertController addAction:settingsAction];
  341. }
  342. UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"取消"
  343. style:UIAlertActionStyleCancel
  344. handler:nil];
  345. [alertController addAction:cancelAction];
  346. [controller presentViewController:alertController animated:YES completion:nil];
  347. }
  348. @end