OperationNodeMultiple.m 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376
  1. //
  2. // OperationNodeMultiple.m
  3. // sampleSDK
  4. //
  5. // Created by 王昭威 on 2023/1/17.
  6. //
  7. #import "PCSBaseViewController.h"
  8. #import "OperationNodeMultiple.h"
  9. #import "PCSTools.h"
  10. #import <Photos/Photos.h>
  11. #import "NSString+Localization.h"
  12. #import <AVFoundation/AVFoundation.h>
  13. #import "QuitMultipleModeAlertViewController.h"
  14. #import "DBManager.h"
  15. #import "LenzSDKConstant.h"
  16. #import "LenzHeader.h"
  17. @interface OperationNodeMultiple ()
  18. @property (nonatomic, strong) NSMutableArray<UIImage*>* caches;
  19. @property (nonatomic, strong) NSMutableArray<NSString*>* imgNamesOnDisk;
  20. @end
  21. @implementation OperationNodeMultiple
  22. - (NSArray<UIImage *> *)cachesInMemory{
  23. return [NSArray arrayWithArray:self.caches];
  24. }
  25. - (NSArray<NSString *> *)cachesOnDisk{
  26. return [NSArray arrayWithArray:self.imgNamesOnDisk];
  27. }
  28. - (BOOL)hasCache{
  29. return self.numberOfCaches != 0;
  30. }
  31. - (UIImage *)lastImage{
  32. // return self.caches.lastObject;
  33. if (self.controller.totalArray.count > 0) {
  34. return self.controller.totalArray.lastObject;
  35. }else{
  36. return nil;
  37. }
  38. }
  39. - (instancetype)initWithController:(PCSBaseViewController *)controller {
  40. self = [super init];
  41. if(self){
  42. _controller = controller;
  43. _caches = [[NSMutableArray alloc] init];
  44. _imgNamesOnDisk = [[NSMutableArray alloc] init];
  45. _maxNumberOfImages = 10lu;
  46. }
  47. return self;
  48. }
  49. - (NSString *)modeTitleString{
  50. return LOCALIZATION_STRING_KEY_MODE_TITLE_MULTIPLE;
  51. }
  52. - (NSString*)imagePathByName: (NSString*)name{
  53. NSString* tmpPath = [PCSTools shared].tmpPath;
  54. return [tmpPath stringByAppendingPathComponent:name];
  55. }
  56. - (BOOL)saveIntoDisk{
  57. UIImage* img = self.caches.firstObject;
  58. if(img != nil){
  59. NSData* imgData = UIImageJPEGRepresentation(img, 1);
  60. NSString* imgName = [NSUUID UUID].UUIDString;
  61. if([[LenzDBManager shared] insertWithName:imgName type:SDKCameraCapturedResourceIndexPhoto] &&
  62. [imgData writeToURL:[NSURL fileURLWithPath:[[PCSTools shared] imagePathByName:imgName]] atomically:YES]){
  63. [self.imgNamesOnDisk addObject:imgName];
  64. [self.caches removeObjectAtIndex:0lu];
  65. }
  66. else{
  67. return NO;
  68. }
  69. }
  70. return YES;
  71. }
  72. - (void)showAlbumButton{
  73. self.controller.albumButton.hidden = NO;
  74. self.controller.backButton.hidden = YES;
  75. }
  76. - (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo{
  77. if(error != nil){
  78. return;
  79. }
  80. [self showAlbumButton];
  81. }
  82. - (void)saveImage: (NSArray<UIImage*>*)images urls: (NSArray<NSURL*>*)urls group: (dispatch_group_t)group completionHandler: (void(^)(BOOL success, NSError * _Nullable error))completionHandler{
  83. [[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
  84. [images enumerateObjectsUsingBlock:^(UIImage * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
  85. PHAssetChangeRequest *req = [PHAssetChangeRequest creationRequestForAssetFromImage:obj];
  86. PHObjectPlaceholder *assetPlaceholder = req.placeholderForCreatedAsset;
  87. }];
  88. [urls enumerateObjectsUsingBlock:^(NSURL * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
  89. PHAssetChangeRequest *req = [PHAssetChangeRequest creationRequestForAssetFromVideoAtFileURL:obj];
  90. PHObjectPlaceholder *assetPlaceholder = req.placeholderForCreatedAsset;
  91. }];
  92. } completionHandler:^(BOOL success, NSError * _Nullable error) {
  93. if (@available(iOS 15, *)) {
  94. if(error.code == PHPhotosErrorAccessUserDenied){
  95. }
  96. else if(error.code == PHPhotosErrorNotEnoughSpace){
  97. [[NSNotificationCenter defaultCenter] postNotificationName:LenzSDKNotificationDiskIsFull object:nil];
  98. }
  99. } else {
  100. if(error.code == 2047){
  101. }
  102. // Fallback on earlier versions
  103. }
  104. completionHandler(success, error);
  105. [images enumerateObjectsUsingBlock:^(UIImage * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
  106. dispatch_group_leave(group);
  107. }];
  108. [urls enumerateObjectsUsingBlock:^(NSURL * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
  109. dispatch_group_leave(group);
  110. }];
  111. }];
  112. }
  113. - (void)deleteCacheForKey:(NSString *)key completion:(void (^)(BOOL))completion{
  114. dispatch_async(dispatch_get_global_queue(0, 0), ^{
  115. NSString* imgName = key;
  116. NSFileManager* fileMgr = [NSFileManager defaultManager];
  117. NSString* path = [self imagePathByName:imgName];
  118. NSError* err = nil;
  119. if([self.imgNamesOnDisk containsObject:key] && [fileMgr fileExistsAtPath:path]){
  120. if([fileMgr removeItemAtPath:path error:&err]){
  121. [[LenzDBManager shared] deleteByName:key type:SDKCameraCapturedResourceIndexPhoto];
  122. [self.imgNamesOnDisk removeObject:key];
  123. }
  124. else{
  125. NSLog(@"%@", err);
  126. }
  127. }
  128. completion(err == nil);
  129. });
  130. }
  131. - (void)deleteCacheForImage:(UIImage *)image completion:(void (^)(BOOL))completion{
  132. dispatch_async(dispatch_get_global_queue(0, 0), ^{
  133. [self.caches removeObject:image];
  134. [self.controller.totalArray removeObject:image];
  135. completion(YES);
  136. });
  137. }
  138. - (void)save {
  139. if(!self.hasCache){
  140. return;
  141. }
  142. // loading indicator
  143. dispatch_block_t block = dispatch_block_create(0, ^{
  144. self.controller.loadingIndicator.hidden = NO;
  145. [self.controller.loadingIndicator.layer removeAnimationForKey:@"rotation"];
  146. CATransform3D myRotationTransform = CATransform3DRotate(self.controller.loadingIndicator.layer.transform, dgree_2_rad(359), 0.0, 0.0, 1.0);
  147. self.controller.loadingIndicator.layer.transform = CATransform3DIdentity;
  148. CABasicAnimation *rotateAnim = [CABasicAnimation animationWithKeyPath:@"transform.rotation"];
  149. rotateAnim.duration = 0.75;
  150. rotateAnim.fromValue = @(0);
  151. rotateAnim.toValue = @(dgree_2_rad(359));
  152. rotateAnim.repeatCount = INFINITY;
  153. // rotateAnim.autoreverses = YES;
  154. [self.controller.loadingIndicator.layer addAnimation:rotateAnim forKey:@"rotation"];
  155. });
  156. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 200 * NSEC_PER_MSEC), dispatch_get_main_queue(), block);
  157. dispatch_group_t group = dispatch_group_create();
  158. [self.caches enumerateObjectsUsingBlock:^(UIImage * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
  159. dispatch_group_enter(group);
  160. }];
  161. [self.imgNamesOnDisk enumerateObjectsUsingBlock:^(NSString * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
  162. dispatch_group_enter(group);
  163. }];
  164. // self.controller.view.userInteractionEnabled = NO;
  165. dispatch_group_notify(group, dispatch_get_main_queue(), ^{
  166. [self.caches removeAllObjects];
  167. [self.imgNamesOnDisk removeAllObjects];
  168. dispatch_block_cancel(block);
  169. // self.controller.view.userInteractionEnabled = YES;
  170. self.controller.loadingIndicator.hidden = YES;
  171. [self.controller.loadingIndicator.layer removeAnimationForKey:@"rotation"];
  172. [self.controller dismissViewControllerAnimated:YES completion:^{}];
  173. });
  174. dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
  175. NSMutableArray<UIImage*>* images = [[NSMutableArray alloc] initWithArray:self.caches];
  176. NSMutableArray<NSString*>* imgPaths = [NSMutableArray array];
  177. NSMutableArray<NSURL*>* imgUrls = [NSMutableArray array];
  178. [self.imgNamesOnDisk enumerateObjectsUsingBlock:^(NSString * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
  179. NSString* imgPath = [[PCSTools shared] imagePathByName:obj];
  180. if([[NSFileManager defaultManager] fileExistsAtPath:imgPath]){
  181. [imgUrls addObject:[NSURL fileURLWithPath:imgPath]];
  182. [imgPaths addObject:imgPath];
  183. }
  184. else{
  185. dispatch_group_leave(group);
  186. }
  187. }];
  188. [self saveImage:images urls: imgUrls group:group completionHandler:^(BOOL success, NSError * _Nullable error) {
  189. if(success){
  190. [imgPaths enumerateObjectsUsingBlock:^(NSString * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
  191. NSError* err = nil;
  192. if([[NSFileManager defaultManager] removeItemAtPath:obj error:&err]){
  193. [[LenzDBManager shared] deleteByName:obj type:SDKCameraCapturedResourceIndexPhoto];
  194. }
  195. else{
  196. NSLog(@"%@", err);
  197. }
  198. }];
  199. }
  200. }];
  201. });
  202. }
  203. - (void)cleanOnCompleted:(void(^)(void))block{
  204. if(self.caches.count == 0 && self.imgNamesOnDisk == 0){
  205. dispatch_async(dispatch_get_main_queue(), ^{
  206. block();
  207. });
  208. }
  209. [self.caches removeAllObjects];
  210. dispatch_group_t group = dispatch_group_create();
  211. [self.imgNamesOnDisk enumerateObjectsUsingBlock:^(NSString * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
  212. dispatch_group_enter(group);
  213. }];
  214. dispatch_group_notify(group, dispatch_get_main_queue(), ^{
  215. [self.imgNamesOnDisk removeAllObjects];
  216. block();
  217. });
  218. NSString* tmpPath = [PCSTools shared].tmpPath;
  219. [self.imgNamesOnDisk enumerateObjectsUsingBlock:^(NSString * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
  220. NSString* imgPath = [tmpPath stringByAppendingPathComponent:obj];
  221. if([[NSFileManager defaultManager] fileExistsAtPath:imgPath]){
  222. NSError* error;
  223. if([[NSFileManager defaultManager] removeItemAtPath:imgPath error:&error]){
  224. [[LenzDBManager shared] deleteByName:obj type:SDKCameraCapturedResourceIndexPhoto];
  225. }
  226. }
  227. dispatch_group_leave(group);
  228. }];
  229. }
  230. - (NSUInteger)numberOfCaches{
  231. return self.controller.totalArray.count + self.imgNamesOnDisk.count;
  232. // return self.caches.count + self.imgNamesOnDisk.count;
  233. }
  234. - (void)takePhotoButtonTouched{
  235. [self.controller takeStillPhoto];
  236. }
  237. - (void)updateUI{
  238. // self.controller.savePhotoButton.hidden = !self.hasCache;
  239. // self.controller.discardPhotoButton.hidden = !self.hasCache;
  240. //
  241. // self.controller.albumButton.hidden = !self.hasCache;
  242. // self.controller.backButton.hidden = self.hasCache;
  243. //
  244. // [self.controller.albumButton setImage:self.lastImage forState:UIControlStateNormal];
  245. self.controller.numberOfImagesLabel.hidden = !self.hasCache;
  246. self.controller.numberOfImagesLabel.text = [NSString stringWithFormat:LOCALIZATION_STRING_KEY_NUM_OF_PHOTOS, [@(self.numberOfCaches) stringValue]];
  247. }
  248. - (void)discardPhotoResultButtonTouchUpInside{
  249. // [QuitMultipleModeAlertViewController show:self.controller title:@"确认提醒" text:@"返回会清空已拍摄图片,请确认!" leftBtnTitle:@"取消" rightBtnTitle:@"确定" withLeftButtonCallBack:^(QuitMultipleModeAlertViewController * _Nonnull alertController) {
  250. //
  251. // [alertController dismissViewControllerAnimated:NO completion:^{}];
  252. // } rightButtonCallBack:^(QuitMultipleModeAlertViewController * _Nonnull alertController) {
  253. //
  254. // [alertController dismissViewControllerAnimated:NO completion:^{
  255. //// [self cleanOnCompleted:^{
  256. //// [self.controller dismissViewControllerAnimated:YES completion:^{}];
  257. //// }];
  258. // }];
  259. // }];
  260. }
  261. - (SDKCaptureModeIndex)modeIndex{
  262. return SDK_CAPTURE_MODE_CONTINUOUS;
  263. }
  264. - (NSString *)modeItemString{
  265. return @"连拍";
  266. }
  267. - (void)triggered {
  268. if (self.controller.capturedImage == nil) {
  269. return;
  270. }
  271. if (self.caches.count >= self.maxNumberOfImages) {
  272. if(![self saveIntoDisk]){
  273. [[NSNotificationCenter defaultCenter] postNotificationName:LenzSDKNotificationDiskIsFull object:nil];
  274. return;
  275. }
  276. }
  277. [self.caches addObject:self.controller.capturedImage];
  278. NSLog(@"-------:%lu",(unsigned long)self.caches.count);
  279. self.controller.numberOfImagesLabel.text = [NSString stringWithFormat:LOCALIZATION_STRING_KEY_NUM_OF_PHOTOS, [@(self.caches.count + self.imgNamesOnDisk.count) stringValue]];
  280. [self showAlbumButton];
  281. [self.controller.albumButton setImage:self.controller.capturedImage forState:UIControlStateNormal];
  282. self.controller.albumButton.layer.transform = CATransform3DScale(self.controller.albumButton.layer.transform, 0.1, 0.1, 1);
  283. CABasicAnimation *flash = [CABasicAnimation animationWithKeyPath:@"opacity"];
  284. flash.fromValue = [NSNumber numberWithFloat:0.0];
  285. flash.toValue = [NSNumber numberWithFloat:1.0];
  286. flash.duration = 0.35;
  287. flash.autoreverses = NO;
  288. flash.repeatCount = 0;
  289. NSString* aniKey = @"flashAnimation";
  290. [self.controller.previewLayer removeAnimationForKey:aniKey];
  291. [self.controller.previewLayer addAnimation:flash forKey:aniKey];
  292. [UIView animateWithDuration:0.35 delay:0 options:UIViewAnimationOptionCurveEaseIn animations:^{
  293. self.controller.albumButton.layer.transform = CATransform3DIdentity;
  294. } completion:^(BOOL finished) {}];
  295. [self updateUI];
  296. }
  297. - (void)willQuitOnCompletion: (WillQuitCompletionBlockType)block{
  298. showAlertToDiscardCachesWithTitle(self, @"", @"", block);
  299. }
  300. - (NSString *)segueForAlbum{
  301. return @"show-photos";
  302. }
  303. - ( UIImage * _Nullable )firstCoverImage{
  304. UIImage* img = nil;
  305. if(self.imgNamesOnDisk.firstObject != nil){
  306. NSString* imgName = self.imgNamesOnDisk.firstObject;
  307. NSData* imgData = [NSData dataWithContentsOfURL:[NSURL fileURLWithPath:[[PCSTools shared].tmpPath stringByAppendingPathComponent:imgName]]];
  308. img = [UIImage imageWithData:imgData];
  309. }
  310. else{
  311. img = self.caches.firstObject;
  312. }
  313. return img;
  314. }
  315. @end