PageRenderTime 81ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/Chapter 11/FifteenSeconds_Starter/FifteenSeconds/Controllers/THTimelineDataSource.m

https://gitlab.com/Mr.Tomato/Learning-AV-Foundation
Objective C | 248 lines | 184 code | 39 blank | 25 comment | 52 complexity | 0c1f4154af9b863bfbfc98e65d0558bd MD5 | raw file
  1. //
  2. // MIT License
  3. //
  4. // Copyright (c) 2014 Bob McCune http://bobmccune.com/
  5. // Copyright (c) 2014 TapHarmonic, LLC http://tapharmonic.com/
  6. //
  7. // Permission is hereby granted, free of charge, to any person obtaining a copy
  8. // of this software and associated documentation files (the "Software"), to deal
  9. // in the Software without restriction, including without limitation the rights
  10. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  11. // copies of the Software, and to permit persons to whom the Software is
  12. // furnished to do so, subject to the following conditions:
  13. //
  14. // The above copyright notice and this permission notice shall be included in
  15. // all copies or substantial portions of the Software.
  16. //
  17. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  18. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  20. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  21. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  22. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  23. // THE SOFTWARE.
  24. //
  25. #import "THTimelineDataSource.h"
  26. #import "THVideoItemCollectionViewCell.h"
  27. #import "THTransitionCollectionViewCell.h"
  28. #import "THAudioItemCollectionViewCell.h"
  29. #import "THTimelineItemViewModel.h"
  30. #import "THTimelineItemCell.h"
  31. #import "THCompositionLayer.h"
  32. #import "THModels.h"
  33. #import "THTransitionViewController.h"
  34. #import "THFunctions.h"
  35. static NSString * const THVideoItemCollectionViewCellID = @"THVideoItemCollectionViewCell";
  36. static NSString * const THTransitionCollectionViewCellID = @"THTransitionCollectionViewCell";
  37. static NSString * const THTitleItemCollectionViewCellID = @"THTitleItemCollectionViewCell";
  38. static NSString * const THAudioItemCollectionViewCellID = @"THAudioItemCollectionViewCell";
  39. @interface THTimelineDataSource () <THTransitionViewControllerDelegate>
  40. @property (weak, nonatomic) THTimelineViewController *controller;
  41. @property (strong, nonatomic) UIPopoverController *transitionPopoverController;
  42. @end
  43. @implementation THTimelineDataSource
  44. + (id)dataSourceWithController:(THTimelineViewController *)controller {
  45. return [[self alloc] initWithController:controller];
  46. }
  47. - (id)initWithController:(THTimelineViewController *)controller {
  48. self = [super init];
  49. if (self) {
  50. _controller = controller;
  51. [self resetTimeline];
  52. }
  53. return self;
  54. }
  55. - (void)clearTimeline {
  56. self.timelineItems = [NSMutableArray array];
  57. }
  58. - (void)resetTimeline {
  59. NSMutableArray *items = [NSMutableArray array];
  60. [items addObject:[NSMutableArray array]];
  61. [items addObject:[NSMutableArray array]];
  62. [items addObject:[NSMutableArray array]];
  63. [items addObject:[NSMutableArray array]];
  64. self.timelineItems = items;
  65. }
  66. #pragma mark - UICollectionViewDataSource methods
  67. - (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
  68. return self.timelineItems.count;
  69. }
  70. - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
  71. return [self.timelineItems[section] count];
  72. }
  73. - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
  74. NSString *cellID = [self cellIDForIndexPath:indexPath];
  75. UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:cellID forIndexPath:indexPath];
  76. cell.contentView.frame = cell.bounds;
  77. cell.contentView.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleRightMargin |UIViewAutoresizingFlexibleTopMargin |UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleBottomMargin;
  78. if ([cellID isEqualToString:THVideoItemCollectionViewCellID]) {
  79. [self configureVideoItemCell:(THVideoItemCollectionViewCell *)cell withItemAtIndexPath:indexPath];
  80. } else if ([cellID isEqualToString:THAudioItemCollectionViewCellID]) {
  81. [self configureAudioItemCell:(THAudioItemCollectionViewCell *)cell withItemAtIndexPath:indexPath];
  82. } else if ([cellID isEqualToString:THTransitionCollectionViewCellID]) {
  83. THTransitionCollectionViewCell *transCell = (THTransitionCollectionViewCell *)cell;
  84. THVideoTransition *transition = self.timelineItems[indexPath.section][indexPath.row];
  85. transCell.button.transitionType = transition.type;
  86. } else if ([cellID isEqualToString:THTitleItemCollectionViewCellID]) {
  87. [self configureTitleItemCell:(THTimelineItemCell *)cell withItemAtIndexPath:indexPath];
  88. }
  89. return cell;
  90. }
  91. - (void)configureVideoItemCell:(THVideoItemCollectionViewCell *)cell withItemAtIndexPath:(NSIndexPath *)indexPath {
  92. THTimelineItemViewModel *model = self.timelineItems[indexPath.section][indexPath.row];
  93. THVideoItem *item = (THVideoItem *)model.timelineItem;
  94. cell.maxTimeRange = item.timeRange;
  95. cell.itemView.label.text = item.title;
  96. cell.itemView.backgroundColor = [UIColor colorWithRed:0.523 green:0.641 blue:0.851 alpha:1.000];
  97. }
  98. - (void)configureAudioItemCell:(THAudioItemCollectionViewCell *)cell withItemAtIndexPath:(NSIndexPath *)indexPath {
  99. THTimelineItemViewModel *model = self.timelineItems[indexPath.section][indexPath.row];
  100. if (indexPath.section == THMusicTrack) {
  101. THAudioItem *item = (THAudioItem *)model.timelineItem;
  102. cell.volumeAutomationView.audioRamps = item.volumeAutomation;
  103. cell.volumeAutomationView.duration = item.timeRange.duration;
  104. cell.itemView.backgroundColor = [UIColor colorWithRed:0.361 green:0.724 blue:0.366 alpha:1.000];
  105. } else {
  106. cell.volumeAutomationView.audioRamps = nil;
  107. cell.volumeAutomationView.duration = kCMTimeZero;
  108. cell.itemView.backgroundColor = [UIColor colorWithRed:0.992 green:0.785 blue:0.106 alpha:1.000];
  109. }
  110. }
  111. - (void)configureTitleItemCell:(THTimelineItemCell *)cell withItemAtIndexPath:(NSIndexPath *)indexPath {
  112. THTimelineItemViewModel *model = self.timelineItems[indexPath.section][indexPath.row];
  113. THCompositionLayer *layer = (THCompositionLayer *)model.timelineItem;
  114. cell.itemView.label.text = layer.identifier;
  115. cell.itemView.backgroundColor = [UIColor colorWithRed:0.741 green:0.556 blue:1.000 alpha:1.000];
  116. }
  117. - (NSString *)cellIDForIndexPath:(NSIndexPath *)indexPath {
  118. if (self.controller.transitionsEnabled && indexPath.section == 0) {
  119. // Video items are at odd indexes, transitions are at even indexes
  120. return (indexPath.item % 2 == 0) ? THVideoItemCollectionViewCellID : THTransitionCollectionViewCellID;
  121. } else if (indexPath.section == 0) {
  122. return THVideoItemCollectionViewCellID;
  123. } else if (indexPath.section == 1) {
  124. return THTitleItemCollectionViewCellID;
  125. } else if (indexPath.section == 2 || indexPath.section == 3) {
  126. return THAudioItemCollectionViewCellID;
  127. }
  128. return nil;
  129. }
  130. - (void)collectionView:(UICollectionView *)collectionView didAdjustToWidth:(CGFloat)width forItemAtIndexPath:(NSIndexPath *)indexPath {
  131. THTimelineItemViewModel *model = self.timelineItems[indexPath.section][indexPath.row];
  132. if (width <= model.maxWidthInTimeline) {
  133. model.widthInTimeline = width;
  134. }
  135. }
  136. - (void)collectionView:(UICollectionView *)collectionView didAdjustToPosition:(CGPoint)position forItemAtIndexPath:(NSIndexPath *)indexPath {
  137. if (indexPath.section == THCommentaryTrack || indexPath.section == THTitleTrack) {
  138. THTimelineItemViewModel *model = self.timelineItems[indexPath.section][indexPath.row];
  139. model.positionInTimeline = position;
  140. [model updateTimelineItem];
  141. if (indexPath.section == THCommentaryTrack) {
  142. [self.controller updateMusicTrackVolumeAutomation];
  143. }
  144. [self.controller.collectionView reloadData];
  145. }
  146. }
  147. - (CGFloat)collectionView:(UICollectionView *)collectionView widthForItemAtIndexPath:(NSIndexPath *)indexPath {
  148. if (self.controller.transitionsEnabled && indexPath.section == 0 && indexPath.item > 0) {
  149. if (indexPath.item % 2 != 0) {
  150. return 32.0f;
  151. }
  152. }
  153. THTimelineItemViewModel *model = self.timelineItems[indexPath.section][indexPath.row];
  154. return model.widthInTimeline;
  155. }
  156. - (CGPoint)collectionView:(UICollectionView *)collectionView positionForItemAtIndexPath:(NSIndexPath *)indexPath {
  157. if (indexPath.section == THCommentaryTrack || indexPath.section == THTitleTrack) {
  158. THTimelineItemViewModel *model = self.timelineItems[indexPath.section][indexPath.row];
  159. return model.positionInTimeline;
  160. }
  161. return CGPointZero;
  162. }
  163. - (BOOL)collectionView:(UICollectionView *)collectionView canAdjustToPosition:(CGPoint)point forItemAtIndexPath:(NSIndexPath *)indexPath {
  164. if (indexPath.section == THCommentaryTrack) {
  165. CMTime time = THGetTimeForOrigin(point.x, THTimelineWidth / THTimelineSeconds);
  166. CMTime fadeInEnd = CMTimeAdd(THDefaultFadeInOutTime, THDefaultDuckingFadeInOutTime);
  167. CMTime fadeOutBegin = CMTimeSubtract(CMTimeMake((int64_t)THTimelineSeconds, 1), fadeInEnd);
  168. return CMTIME_COMPARE_INLINE(time, >=, fadeInEnd) && CMTIME_COMPARE_INLINE(time, <=, fadeOutBegin);
  169. }
  170. return YES;
  171. }
  172. - (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
  173. id selectedItem = self.timelineItems[indexPath.section][indexPath.item];
  174. if ([selectedItem isKindOfClass:[THVideoTransition class]]) {
  175. [self configureTransition:selectedItem atIndexPath:indexPath];
  176. }
  177. }
  178. - (void)configureTransition:(THVideoTransition *)transition atIndexPath:(NSIndexPath *)indexPath {
  179. THTransitionViewController *transitionController = [THTransitionViewController controllerWithTransition:transition];
  180. transitionController.delegate = self;
  181. self.transitionPopoverController = [[UIPopoverController alloc] initWithContentViewController:transitionController];
  182. UICollectionViewCell *cell = [self.controller.collectionView cellForItemAtIndexPath:indexPath];
  183. [self.transitionPopoverController presentPopoverFromRect:cell.frame
  184. inView:self.controller.view
  185. permittedArrowDirections:UIPopoverArrowDirectionDown animated:YES];
  186. }
  187. - (void)transitionSelected {
  188. [self.transitionPopoverController dismissPopoverAnimated:YES];
  189. self.transitionPopoverController = nil;
  190. [self.controller.collectionView reloadData];
  191. }
  192. - (BOOL)collectionView:(UICollectionView *)collectionView canMoveItemAtIndexPath:(NSIndexPath *)indexPath {
  193. return indexPath.section == 0 && !self.controller.transitionsEnabled;
  194. }
  195. - (void)collectionView:(UICollectionView *)collectionView didMoveMediaItemAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath {
  196. NSMutableArray *items = self.timelineItems[fromIndexPath.section];
  197. if (fromIndexPath.item == toIndexPath.item) {
  198. NSLog(@"FUBAR: Attempting to move: %li to %li.", (long)fromIndexPath.item, (long)toIndexPath.item);
  199. NSAssert(NO, @"Attempting to make invalid move.");
  200. }
  201. [items exchangeObjectAtIndex:fromIndexPath.item withObjectAtIndex:toIndexPath.item];
  202. }
  203. - (BOOL)collectionView:(UICollectionView *)theCollectionView layout:(UICollectionViewLayout *)theLayout itemAtIndexPath:(NSIndexPath *)theFromIndexPath shouldMoveToIndexPath:(NSIndexPath *)theToIndexPath {
  204. return theFromIndexPath.section == theToIndexPath.section;
  205. }
  206. - (void)collectionView:(UICollectionView *)collectionView willDeleteItemAtIndexPath:(NSIndexPath *)indexPath {
  207. [self.timelineItems[indexPath.section] removeObjectAtIndex:indexPath.row];
  208. }
  209. @end