|  |  | @ -84,7 +84,7 @@ public class MediaTileViewController: UICollectionViewController, MediaGalleryCe | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |         collectionView.register(MediaGalleryCell.self, forCellWithReuseIdentifier: MediaGalleryCell.reuseIdentifier) |  |  |  |         collectionView.register(MediaGalleryCell.self, forCellWithReuseIdentifier: MediaGalleryCell.reuseIdentifier) | 
			
		
	
		
		
			
				
					
					|  |  |  |         collectionView.register(MediaGallerySectionHeader.self, forSupplementaryViewOfKind: UICollectionElementKindSectionHeader, withReuseIdentifier: MediaGallerySectionHeader.reuseIdentifier) |  |  |  |         collectionView.register(MediaGallerySectionHeader.self, forSupplementaryViewOfKind: UICollectionElementKindSectionHeader, withReuseIdentifier: MediaGallerySectionHeader.reuseIdentifier) | 
			
		
	
		
		
			
				
					
					|  |  |  |         collectionView.register(MediaGalleryLoadingHeader.self, forSupplementaryViewOfKind: UICollectionElementKindSectionHeader, withReuseIdentifier: MediaGalleryLoadingHeader.reuseIdentifier) |  |  |  |         collectionView.register(MediaGalleryStaticHeader.self, forSupplementaryViewOfKind: UICollectionElementKindSectionHeader, withReuseIdentifier: MediaGalleryStaticHeader.reuseIdentifier) | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |         collectionView.delegate = self |  |  |  |         collectionView.delegate = self | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
	
		
		
			
				
					|  |  | @ -146,10 +146,22 @@ public class MediaTileViewController: UICollectionViewController, MediaGalleryCe | 
			
		
	
		
		
			
				
					
					|  |  |  |     // MARK: UIColletionViewDataSource |  |  |  |     // MARK: UIColletionViewDataSource | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     override public func numberOfSections(in collectionView: UICollectionView) -> Int { |  |  |  |     override public func numberOfSections(in collectionView: UICollectionView) -> Int { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         guard galleryDates.count > 0 else { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             // empty gallery | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             return 1 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         // One for each galleryDate plus a "loading older" and "loading newer" section | 
			
		
	
		
		
			
				
					
					|  |  |  |         return galleryItems.keys.count + 2 |  |  |  |         return galleryItems.keys.count + 2 | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     override public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection sectionIdx: Int) -> Int { |  |  |  |     override public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection sectionIdx: Int) -> Int { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         guard galleryDates.count > 0 else { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             // empty gallery | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             return 0 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |         if sectionIdx == kLoadOlderSectionIdx { |  |  |  |         if sectionIdx == kLoadOlderSectionIdx { | 
			
		
	
		
		
			
				
					
					|  |  |  |             // load older |  |  |  |             // load older | 
			
		
	
		
		
			
				
					
					|  |  |  |             return 0 |  |  |  |             return 0 | 
			
		
	
	
		
		
			
				
					|  |  | @ -176,10 +188,22 @@ public class MediaTileViewController: UICollectionViewController, MediaGalleryCe | 
			
		
	
		
		
			
				
					
					|  |  |  |     override public func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView { |  |  |  |     override public func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView { | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |         let defaultView = UICollectionReusableView() |  |  |  |         let defaultView = UICollectionReusableView() | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         guard galleryDates.count > 0 else { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             guard let sectionHeader = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: MediaGalleryStaticHeader.reuseIdentifier, for: indexPath) as? MediaGalleryStaticHeader else { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 owsFail("\(logTag) in \(#function) unable to build section header for kLoadOlderSectionIdx") | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 return defaultView | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             let title = NSLocalizedString("GALLERY_TILES_EMPTY_GALLERY", comment: "Label indicating media gallery is empty") | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             sectionHeader.configure(title: title) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             return sectionHeader | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |         if (kind == UICollectionElementKindSectionHeader) { |  |  |  |         if (kind == UICollectionElementKindSectionHeader) { | 
			
		
	
		
		
			
				
					
					|  |  |  |             switch indexPath.section { |  |  |  |             switch indexPath.section { | 
			
		
	
		
		
			
				
					
					|  |  |  |             case kLoadOlderSectionIdx: |  |  |  |             case kLoadOlderSectionIdx: | 
			
		
	
		
		
			
				
					
					|  |  |  |                 guard let sectionHeader = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: MediaGalleryLoadingHeader.reuseIdentifier, for: indexPath) as? MediaGalleryLoadingHeader else { |  |  |  |                 guard let sectionHeader = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: MediaGalleryStaticHeader.reuseIdentifier, for: indexPath) as? MediaGalleryStaticHeader else { | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |                     owsFail("\(logTag) in \(#function) unable to build section header for kLoadOlderSectionIdx") |  |  |  |                     owsFail("\(logTag) in \(#function) unable to build section header for kLoadOlderSectionIdx") | 
			
		
	
		
		
			
				
					
					|  |  |  |                     return defaultView |  |  |  |                     return defaultView | 
			
		
	
	
		
		
			
				
					|  |  | @ -188,7 +212,7 @@ public class MediaTileViewController: UICollectionViewController, MediaGalleryCe | 
			
		
	
		
		
			
				
					
					|  |  |  |                 sectionHeader.configure(title: title) |  |  |  |                 sectionHeader.configure(title: title) | 
			
		
	
		
		
			
				
					
					|  |  |  |                 return sectionHeader |  |  |  |                 return sectionHeader | 
			
		
	
		
		
			
				
					
					|  |  |  |             case loadNewerSectionIdx: |  |  |  |             case loadNewerSectionIdx: | 
			
		
	
		
		
			
				
					
					|  |  |  |                 guard let sectionHeader = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: MediaGalleryLoadingHeader.reuseIdentifier, for: indexPath) as? MediaGalleryLoadingHeader else { |  |  |  |                 guard let sectionHeader = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: MediaGalleryStaticHeader.reuseIdentifier, for: indexPath) as? MediaGalleryStaticHeader else { | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |                     owsFail("\(logTag) in \(#function) unable to build section header for kLoadOlderSectionIdx") |  |  |  |                     owsFail("\(logTag) in \(#function) unable to build section header for kLoadOlderSectionIdx") | 
			
		
	
		
		
			
				
					
					|  |  |  |                     return defaultView |  |  |  |                     return defaultView | 
			
		
	
	
		
		
			
				
					|  |  | @ -219,6 +243,11 @@ public class MediaTileViewController: UICollectionViewController, MediaGalleryCe | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |         let defaultCell = UICollectionViewCell() |  |  |  |         let defaultCell = UICollectionViewCell() | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         guard galleryDates.count > 0 else { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             owsFail("\(logTag) in \(#function) unexpected cell for loadNewerSectionIdx") | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             return defaultCell | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |         switch indexPath.section { |  |  |  |         switch indexPath.section { | 
			
		
	
		
		
			
				
					
					|  |  |  |         case kLoadOlderSectionIdx: |  |  |  |         case kLoadOlderSectionIdx: | 
			
		
	
		
		
			
				
					
					|  |  |  |             owsFail("\(logTag) in \(#function) unexpected cell for kLoadOlderSectionIdx") |  |  |  |             owsFail("\(logTag) in \(#function) unexpected cell for kLoadOlderSectionIdx") | 
			
		
	
	
		
		
			
				
					|  |  | @ -259,25 +288,27 @@ public class MediaTileViewController: UICollectionViewController, MediaGalleryCe | 
			
		
	
		
		
			
				
					
					|  |  |  |                                layout collectionViewLayout: UICollectionViewLayout, |  |  |  |                                layout collectionViewLayout: UICollectionViewLayout, | 
			
		
	
		
		
			
				
					
					|  |  |  |                                referenceSizeForHeaderInSection section: Int) -> CGSize { |  |  |  |                                referenceSizeForHeaderInSection section: Int) -> CGSize { | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |         let kHeaderHeight: CGFloat = 50 |  |  |  |         let kMonthHeaderSize: CGSize = CGSize(width: 0, height: 50) | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         let kStaticHeaderSize: CGSize = CGSize(width: 0, height: 100) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         guard galleryDates.count > 0 else { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             return kStaticHeaderSize | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |         switch section { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         case kLoadOlderSectionIdx: |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |             // Show "loading older..." iff there is still older data to be fetched |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         guard let mediaGalleryDataSource = self.mediaGalleryDataSource else { |  |  |  |         guard let mediaGalleryDataSource = self.mediaGalleryDataSource else { | 
			
		
	
		
		
			
				
					
					|  |  |  |             owsFail("\(logTag) in \(#function) mediaGalleryDataSource was unexpectedly nil") |  |  |  |             owsFail("\(logTag) in \(#function) mediaGalleryDataSource was unexpectedly nil") | 
			
		
	
		
		
			
				
					
					|  |  |  |             return CGSize.zero |  |  |  |             return CGSize.zero | 
			
		
	
		
		
			
				
					
					|  |  |  |         } |  |  |  |         } | 
			
		
	
		
		
			
				
					
					|  |  |  |             return mediaGalleryDataSource.hasFetchedOldest ? CGSize.zero : CGSize(width: 0, height: 100) |  |  |  | 
 | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         switch section { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         case kLoadOlderSectionIdx: | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             // Show "loading older..." iff there is still older data to be fetched | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             return mediaGalleryDataSource.hasFetchedOldest ? CGSize.zero : kStaticHeaderSize | 
			
		
	
		
		
			
				
					
					|  |  |  |         case loadNewerSectionIdx: |  |  |  |         case loadNewerSectionIdx: | 
			
		
	
		
		
			
				
					
					|  |  |  |             // Show "loading newer..." iff there is still more recent data to be fetched |  |  |  |             // Show "loading newer..." iff there is still more recent data to be fetched | 
			
		
	
		
		
			
				
					
					|  |  |  |             guard let mediaGalleryDataSource = self.mediaGalleryDataSource else { |  |  |  |             return mediaGalleryDataSource.hasFetchedMostRecent ? CGSize.zero : kStaticHeaderSize | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |                 owsFail("\(logTag) in \(#function) mediaGalleryDataSource was unexpectedly nil") |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |                 return CGSize.zero |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |             } |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |             return mediaGalleryDataSource.hasFetchedMostRecent ? CGSize.zero : CGSize(width: 0, height: 100) |  |  |  |  | 
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |         default: |  |  |  |         default: | 
			
		
	
		
		
			
				
					
					|  |  |  |             return CGSize(width: 0, height: kHeaderHeight) |  |  |  |             return kMonthHeaderSize | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |         } |  |  |  |         } | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  |     // MARK: MediaGalleryDelegate |  |  |  |     // MARK: MediaGalleryDelegate | 
			
		
	
	
		
		
			
				
					|  |  | @ -518,19 +549,20 @@ fileprivate protocol MediaGalleryCellDelegate: class { | 
			
		
	
		
		
			
				
					
					|  |  |  |     func didTapCell(_ cell: MediaGalleryCell, item: MediaGalleryItem) |  |  |  |     func didTapCell(_ cell: MediaGalleryCell, item: MediaGalleryItem) | 
			
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | fileprivate class MediaGalleryLoadingHeader: UICollectionViewCell { |  |  |  | fileprivate class MediaGalleryStaticHeader: UICollectionViewCell { | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     static let reuseIdentifier = "MediaGalleryLoadingHeader" |  |  |  |     static let reuseIdentifier = "MediaGalleryStaticHeader" | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     let label = UILabel() |  |  |  |     let label = UILabel() | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     override init(frame: CGRect) { |  |  |  |     override init(frame: CGRect) { | 
			
		
	
		
		
			
				
					
					|  |  |  |         super.init(frame: frame) |  |  |  |         super.init(frame: frame) | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |         // TODO add spinnner, start/stop animating on will/end display |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         addSubview(label) |  |  |  |         addSubview(label) | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |         label.autoCenterInSuperview() |  |  |  |         label.textAlignment = .center | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         label.numberOfLines = 0 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         label.autoPinEdgesToSuperviewMargins() | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     @available(*, unavailable, message: "Unimplemented") |  |  |  |     @available(*, unavailable, message: "Unimplemented") | 
			
		
	
	
		
		
			
				
					|  |  | 
 |