Access Media Gallery from conversation settings
// FREEBIE
This commit is contained in:
parent
f733c07d07
commit
ae8dbeb8dd
|
@ -1485,7 +1485,7 @@ typedef enum : NSUInteger {
|
|||
|
||||
OWSConversationSettingsViewController *settingsVC = [OWSConversationSettingsViewController new];
|
||||
settingsVC.conversationSettingsViewDelegate = self;
|
||||
[settingsVC configureWithThread:self.thread];
|
||||
[settingsVC configureWithThread:self.thread uiDatabaseConnection:self.uiDatabaseConnection];
|
||||
settingsVC.showVerificationOnAppear = showVerification;
|
||||
[self.navigationController pushViewController:settingsVC animated:YES];
|
||||
}
|
||||
|
@ -2034,10 +2034,9 @@ typedef enum : NSUInteger {
|
|||
TSMessage *mediaMessage = (TSMessage *)viewItem.interaction;
|
||||
|
||||
MediaGalleryViewController *vc = [[MediaGalleryViewController alloc] initWithThread:self.thread
|
||||
mediaMessage:mediaMessage
|
||||
uiDatabaseConnection:self.uiDatabaseConnection];
|
||||
|
||||
[vc presentDetailViewFromViewController:self replacingView:imageView];
|
||||
[vc presentDetailViewFromViewController:self mediaMessage:mediaMessage replacingView:imageView];
|
||||
}
|
||||
|
||||
- (void)didTapVideoViewItem:(ConversationViewItem *)viewItem
|
||||
|
@ -2057,10 +2056,9 @@ typedef enum : NSUInteger {
|
|||
TSMessage *mediaMessage = (TSMessage *)viewItem.interaction;
|
||||
|
||||
MediaGalleryViewController *vc = [[MediaGalleryViewController alloc] initWithThread:self.thread
|
||||
mediaMessage:mediaMessage
|
||||
uiDatabaseConnection:self.uiDatabaseConnection];
|
||||
|
||||
[vc presentDetailViewFromViewController:self replacingView:imageView];
|
||||
[vc presentDetailViewFromViewController:self mediaMessage:mediaMessage replacingView:imageView];
|
||||
}
|
||||
|
||||
- (void)didTapAudioViewItem:(ConversationViewItem *)viewItem attachmentStream:(TSAttachmentStream *)attachmentStream
|
||||
|
|
|
@ -141,40 +141,6 @@ public struct GalleryDate: Hashable, Comparable, Equatable {
|
|||
public static func == (lhs: GalleryDate, rhs: GalleryDate) -> Bool {
|
||||
return lhs.month == rhs.month && lhs.year == rhs.year
|
||||
}
|
||||
|
||||
// // MARK: Sequence / IteratorProtocol
|
||||
// public func until(_ toDate: GalleryDate) -> GalleryDateSequence {
|
||||
// return GalleryDateSequence(from: self, to: toDate)
|
||||
// }
|
||||
//
|
||||
// public class GalleryDateSequence: Sequence, IteratorProtocol {
|
||||
// public typealias Element = GalleryDate
|
||||
//
|
||||
// var currentDate: GalleryDate
|
||||
// let toDate: GalleryDate
|
||||
//
|
||||
// init(from: GalleryDate, to: GalleryDate) {
|
||||
// self.currentDate = from
|
||||
// self.toDate = to
|
||||
// }
|
||||
//
|
||||
// public func next() -> GalleryDate? {
|
||||
// guard currentDate < toDate else {
|
||||
// return nil
|
||||
// }
|
||||
//
|
||||
// let nextDate: GalleryDate = {
|
||||
// if currentDate.month == 12 {
|
||||
// return GalleryDate(year: currentDate.year + 1, month: 1)
|
||||
// } else {
|
||||
// return GalleryDate(year: currentDate.year, month: currentDate.month + 1)
|
||||
// }
|
||||
// }()
|
||||
// currentDate = nextDate
|
||||
// return nextDate
|
||||
// }
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
protocol MediaGalleryDataSource: class {
|
||||
|
@ -192,33 +158,30 @@ protocol MediaGalleryDataSource: class {
|
|||
func galleryItem(before currentItem: MediaGalleryItem) -> MediaGalleryItem?
|
||||
func galleryItem(after currentItem: MediaGalleryItem) -> MediaGalleryItem?
|
||||
|
||||
func showAllMedia()
|
||||
|
||||
// TODO this doesn't seem very "data-source"
|
||||
func showAllMedia(focusedItem: MediaGalleryItem)
|
||||
func dismissSelf(animated isAnimated: Bool, completion: (() -> Void)?)
|
||||
}
|
||||
|
||||
class MediaGalleryViewController: UINavigationController, MediaGalleryDataSource, MediaTileViewControllerDelegate {
|
||||
|
||||
private var pageViewController: MediaPageViewController?
|
||||
// private let tileViewController: MediaTileViewController
|
||||
//
|
||||
|
||||
private let uiDatabaseConnection: YapDatabaseConnection
|
||||
private let mediaGalleryFinder: OWSMediaGalleryFinder
|
||||
|
||||
// FIXME get rid of `!`
|
||||
private var initialGalleryItem: MediaGalleryItem!
|
||||
private var initialDetailItem: MediaGalleryItem?
|
||||
private let thread: TSThread
|
||||
private let includeGallery: Bool
|
||||
|
||||
// we start with a small range size for quick loading.
|
||||
private let fetchRangeSize: UInt = 10
|
||||
|
||||
convenience init(thread: TSThread, mediaMessage: TSMessage, uiDatabaseConnection: YapDatabaseConnection) {
|
||||
self.init(thread: thread, mediaMessage: mediaMessage, uiDatabaseConnection: uiDatabaseConnection, includeGallery: true)
|
||||
convenience init(thread: TSThread, uiDatabaseConnection: YapDatabaseConnection) {
|
||||
self.init(thread: thread, uiDatabaseConnection: uiDatabaseConnection, includeGallery: true)
|
||||
}
|
||||
|
||||
init(thread: TSThread, mediaMessage: TSMessage, uiDatabaseConnection: YapDatabaseConnection, includeGallery: Bool) {
|
||||
init(thread: TSThread, uiDatabaseConnection: YapDatabaseConnection, includeGallery: Bool) {
|
||||
self.thread = thread
|
||||
assert(uiDatabaseConnection.isInLongLivedReadTransaction())
|
||||
self.uiDatabaseConnection = uiDatabaseConnection
|
||||
|
@ -226,14 +189,6 @@ class MediaGalleryViewController: UINavigationController, MediaGalleryDataSource
|
|||
self.mediaGalleryFinder = OWSMediaGalleryFinder(thread: thread)
|
||||
|
||||
super.init(nibName: nil, bundle: nil)
|
||||
|
||||
uiDatabaseConnection.read { transaction in
|
||||
self.initialGalleryItem = self.buildGalleryItem(message: mediaMessage, transaction: transaction)!
|
||||
}
|
||||
|
||||
// For a speedy load, we only fetch a few items on either side of
|
||||
// the initial message
|
||||
ensureGalleryItemsLoaded(.around, item: self.initialGalleryItem, amount: 10)
|
||||
}
|
||||
|
||||
required init?(coder aDecoder: NSCoder) {
|
||||
|
@ -268,6 +223,10 @@ class MediaGalleryViewController: UINavigationController, MediaGalleryDataSource
|
|||
|
||||
// MARK: Present/Dismiss
|
||||
|
||||
private var currentPage: MediaGalleryPage? {
|
||||
return self.pageViewController!.currentPage
|
||||
}
|
||||
|
||||
private var replacingView: UIView?
|
||||
private var presentationView: UIImageView!
|
||||
private var presentationViewConstraints: [NSLayoutConstraint] = []
|
||||
|
@ -275,9 +234,27 @@ class MediaGalleryViewController: UINavigationController, MediaGalleryDataSource
|
|||
// TODO rename to replacingOriginRect
|
||||
private var originRect: CGRect?
|
||||
|
||||
public func presentDetailView(fromViewController: UIViewController, replacingView: UIView) {
|
||||
public func presentDetailView(fromViewController: UIViewController, mediaMessage: TSMessage, replacingView: UIView) {
|
||||
var galleryItem: MediaGalleryItem?
|
||||
uiDatabaseConnection.read { transaction in
|
||||
galleryItem = self.buildGalleryItem(message: mediaMessage, transaction: transaction)!
|
||||
}
|
||||
|
||||
let pageViewController = MediaPageViewController(initialItem: self.initialGalleryItem, mediaGalleryDataSource: self, uiDatabaseConnection: self.uiDatabaseConnection, includeGallery: self.includeGallery)
|
||||
guard let initialDetailItem = galleryItem else {
|
||||
owsFail("\(logTag) in \(#function) unexpectedly failed to build initialDetailItem.")
|
||||
return
|
||||
}
|
||||
|
||||
presentDetailView(fromViewController: fromViewController, initialDetailItem: initialDetailItem, replacingView: replacingView)
|
||||
}
|
||||
|
||||
public func presentDetailView(fromViewController: UIViewController, initialDetailItem: MediaGalleryItem, replacingView: UIView) {
|
||||
// For a speedy load, we only fetch a few items on either side of
|
||||
// the initial message
|
||||
ensureGalleryItemsLoaded(.around, item: initialDetailItem, amount: 10)
|
||||
self.initialDetailItem = initialDetailItem
|
||||
|
||||
let pageViewController = MediaPageViewController(initialItem: initialDetailItem, mediaGalleryDataSource: self, uiDatabaseConnection: self.uiDatabaseConnection, includeGallery: self.includeGallery)
|
||||
|
||||
self.pageViewController = pageViewController
|
||||
self.setViewControllers([pageViewController], animated: false)
|
||||
|
@ -289,7 +266,7 @@ class MediaGalleryViewController: UINavigationController, MediaGalleryDataSource
|
|||
|
||||
// loadView hasn't necessarily been called yet.
|
||||
self.loadViewIfNeeded()
|
||||
self.presentationView.image = self.initialGalleryItem.fullSizedImage
|
||||
self.presentationView.image = initialDetailItem.fullSizedImage
|
||||
self.applyInitialMediaViewConstraints()
|
||||
|
||||
// We want to animate the tapped media from it's position in the previous VC
|
||||
|
@ -360,8 +337,51 @@ class MediaGalleryViewController: UINavigationController, MediaGalleryDataSource
|
|||
}
|
||||
}
|
||||
|
||||
private var currentPage: MediaGalleryPage? {
|
||||
return self.pageViewController!.currentPage
|
||||
// If we're using a navigationController other than self to present the views
|
||||
// e.g. the conversation settings view controller
|
||||
var fromNavController: UINavigationController?
|
||||
|
||||
func pushTileView(fromNavController: UINavigationController) {
|
||||
var mostRecentItem: MediaGalleryItem?
|
||||
self.uiDatabaseConnection.read { transaction in
|
||||
if let message = self.mediaGalleryFinder.mostRecentMediaMessage(transaction: transaction) {
|
||||
mostRecentItem = self.buildGalleryItem(message: message, transaction: transaction)
|
||||
}
|
||||
}
|
||||
|
||||
if let mostRecentItem = mostRecentItem {
|
||||
mediaTileViewController.focusedItem = mostRecentItem
|
||||
ensureGalleryItemsLoaded(.around, item: mostRecentItem, amount: 100)
|
||||
}
|
||||
self.fromNavController = fromNavController
|
||||
fromNavController.pushViewController(mediaTileViewController, animated: true)
|
||||
}
|
||||
|
||||
func showAllMedia(focusedItem: MediaGalleryItem) {
|
||||
// TODO fancy animation - zoom media item into it's tile in the all media grid
|
||||
ensureGalleryItemsLoaded(.around, item: focusedItem, amount: 100)
|
||||
|
||||
if let fromNavController = self.fromNavController {
|
||||
// If from conversation settings view, we've already pushed
|
||||
fromNavController.popViewController(animated: true)
|
||||
} else {
|
||||
// If from conversation view
|
||||
mediaTileViewController.focusedItem = focusedItem
|
||||
self.pushViewController(mediaTileViewController, animated: true)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: MediaTileViewControllerDelegate
|
||||
|
||||
func mediaTileViewController(_ viewController: MediaTileViewController, didTapView tappedView: UIView, mediaGalleryItem: MediaGalleryItem) {
|
||||
if self.fromNavController != nil {
|
||||
// If from conversation settings view, we've already pushed
|
||||
self.presentDetailView(fromViewController: mediaTileViewController, initialDetailItem: mediaGalleryItem, replacingView: tappedView)
|
||||
} else {
|
||||
// If from conversation view
|
||||
self.pageViewController!.currentItem = mediaGalleryItem
|
||||
self.popViewController(animated: true)
|
||||
}
|
||||
}
|
||||
|
||||
public func dismissSelf(animated isAnimated: Bool, completion: (() -> Void)? = nil) {
|
||||
|
@ -384,7 +404,7 @@ class MediaGalleryViewController: UINavigationController, MediaGalleryDataSource
|
|||
|
||||
// Move the presentationView back to it's initial position, i.e. where
|
||||
// it sits on the screen in the conversation view.
|
||||
let changedItems = currentPage.galleryItem != initialGalleryItem
|
||||
let changedItems = currentPage.galleryItem != self.initialDetailItem
|
||||
if changedItems {
|
||||
self.presentationView.image = currentPage.image
|
||||
self.applyOffscreenMediaViewConstraints()
|
||||
|
@ -493,16 +513,11 @@ class MediaGalleryViewController: UINavigationController, MediaGalleryDataSource
|
|||
|
||||
// MARK: MediaGalleryDataSource
|
||||
|
||||
func showAllMedia() {
|
||||
|
||||
ensureGalleryItemsLoaded(.around, item: self.initialGalleryItem, amount: 100)
|
||||
|
||||
// TODO fancy animation - zoom media item into it's tile in the all media grid
|
||||
let allMediaController = MediaTileViewController(mediaGalleryDataSource: self, uiDatabaseConnection: self.uiDatabaseConnection)
|
||||
allMediaController.delegate = self
|
||||
|
||||
self.pushViewController(allMediaController, animated: true)
|
||||
}
|
||||
lazy var mediaTileViewController: MediaTileViewController = {
|
||||
let vc = MediaTileViewController(mediaGalleryDataSource: self, uiDatabaseConnection: self.uiDatabaseConnection)
|
||||
vc.delegate = self
|
||||
return vc
|
||||
}()
|
||||
|
||||
var galleryItems: [MediaGalleryItem] = []
|
||||
var sections: [GalleryDate: [MediaGalleryItem]] = [:]
|
||||
|
@ -689,12 +704,4 @@ class MediaGalleryViewController: UINavigationController, MediaGalleryDataSource
|
|||
}
|
||||
return Int(count)
|
||||
}
|
||||
|
||||
// MARK: MediaTileViewControllerDelegate
|
||||
|
||||
func mediaTileViewController(_ viewController: MediaTileViewController, didTapMediaGalleryItem mediaGalleryItem: MediaGalleryItem) {
|
||||
self.pageViewController!.currentItem = mediaGalleryItem
|
||||
self.popViewController(animated: true)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -181,7 +181,7 @@ class MediaPageViewController: UIPageViewController, UIPageViewControllerDataSou
|
|||
public func didPressAllMediaButton(sender: Any) {
|
||||
Logger.debug("\(logTag) in \(#function)")
|
||||
|
||||
self.mediaGalleryDataSource.showAllMedia()
|
||||
self.mediaGalleryDataSource.showAllMedia(focusedItem: currentItem)
|
||||
}
|
||||
|
||||
@objc
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
import Foundation
|
||||
|
||||
public protocol MediaTileViewControllerDelegate: class {
|
||||
func mediaTileViewController(_ viewController: MediaTileViewController, didTapMediaGalleryItem mediaGalleryItem: MediaGalleryItem)
|
||||
func mediaTileViewController(_ viewController: MediaTileViewController, didTapView tappedView: UIView, mediaGalleryItem: MediaGalleryItem)
|
||||
}
|
||||
|
||||
public class MediaTileViewController: UICollectionViewController, MediaGalleryCellDelegate {
|
||||
|
@ -19,6 +19,7 @@ public class MediaTileViewController: UICollectionViewController, MediaGalleryCe
|
|||
private var galleryDates: [GalleryDate] {
|
||||
return mediaGalleryDataSource.sectionDates
|
||||
}
|
||||
public var focusedItem: MediaGalleryItem?
|
||||
|
||||
private let uiDatabaseConnection: YapDatabaseConnection
|
||||
|
||||
|
@ -81,6 +82,33 @@ public class MediaTileViewController: UICollectionViewController, MediaGalleryCe
|
|||
scrollToBottom(animated: false)
|
||||
}
|
||||
|
||||
private func indexPath(galleryItem: MediaGalleryItem) -> IndexPath? {
|
||||
guard let sectionIdx = galleryDates.index(of: galleryItem.galleryDate) else {
|
||||
return nil
|
||||
}
|
||||
guard let rowIdx = galleryItems[galleryItem.galleryDate]!.index(of: galleryItem) else {
|
||||
return nil
|
||||
}
|
||||
|
||||
return IndexPath(row: rowIdx, section: sectionIdx + 1)
|
||||
}
|
||||
|
||||
override public func viewWillAppear(_ animated: Bool) {
|
||||
super.viewWillAppear(animated)
|
||||
|
||||
guard let focusedItem = self.focusedItem else {
|
||||
return
|
||||
}
|
||||
|
||||
guard let indexPath = self.indexPath(galleryItem: focusedItem) else {
|
||||
owsFail("\(logTag) unexpectedly unable to find indexPath for focusedItem: \(focusedItem)")
|
||||
return
|
||||
}
|
||||
|
||||
Logger.debug("\(logTag) scrolling to focused item at indexPath: \(indexPath)")
|
||||
self.collectionView?.scrollToItem(at: indexPath, at: .centeredVertically, animated: false)
|
||||
}
|
||||
|
||||
// MARK: UIColletionViewDelegate
|
||||
|
||||
override public func scrollViewDidScroll(_ scrollView: UIScrollView) {
|
||||
|
@ -234,7 +262,7 @@ public class MediaTileViewController: UICollectionViewController, MediaGalleryCe
|
|||
|
||||
public func didTapCell(_ cell: MediaGalleryCell, item: MediaGalleryItem) {
|
||||
Logger.debug("\(logTag) in \(#function)")
|
||||
self.delegate?.mediaTileViewController(self, didTapMediaGalleryItem: item)
|
||||
self.delegate?.mediaTileViewController(self, didTapView: cell.imageView, mediaGalleryItem: item)
|
||||
}
|
||||
|
||||
// MARK: Lazy Loading
|
||||
|
@ -461,7 +489,7 @@ public class MediaGalleryCell: UICollectionViewCell {
|
|||
|
||||
static let reuseIdentifier = "MediaGalleryCell"
|
||||
|
||||
private let imageView: UIImageView
|
||||
public let imageView: UIImageView
|
||||
private var tapGesture: UITapGestureRecognizer!
|
||||
|
||||
private var item: MediaGalleryItem?
|
||||
|
|
|
@ -762,7 +762,7 @@ class MessageDetailViewController: OWSViewController, UIScrollViewDelegate, Medi
|
|||
return
|
||||
}
|
||||
|
||||
let mediaGalleryViewController = MediaGalleryViewController(thread: self.thread, mediaMessage: self.message, uiDatabaseConnection: self.uiDatabaseConnection, includeGallery: false)
|
||||
mediaGalleryViewController.presentDetailView(fromViewController: self, replacingView: fromView)
|
||||
let mediaGalleryViewController = MediaGalleryViewController(thread: self.thread, uiDatabaseConnection: self.uiDatabaseConnection, includeGallery: false)
|
||||
mediaGalleryViewController.presentDetailView(fromViewController: self, mediaMessage: self.message, replacingView: fromView)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class TSThread;
|
||||
@class YapDatabaseConnection;
|
||||
|
||||
@interface OWSConversationSettingsViewController : OWSTableViewController
|
||||
|
||||
|
@ -16,7 +17,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
@property (nonatomic) BOOL showVerificationOnAppear;
|
||||
|
||||
- (void)configureWithThread:(TSThread *)thread;
|
||||
- (void)configureWithThread:(TSThread *)thread uiDatabaseConnection:(YapDatabaseConnection *)uiDatabaseConnection;
|
||||
|
||||
@end
|
||||
|
||||
|
|
|
@ -40,6 +40,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
@interface OWSConversationSettingsViewController () <ContactEditingDelegate, ContactsViewHelperDelegate>
|
||||
|
||||
@property (nonatomic) TSThread *thread;
|
||||
@property (nonatomic) YapDatabaseConnection *uiDatabaseConnection;
|
||||
|
||||
@property (nonatomic) NSArray<NSNumber *> *disappearingMessagesDurations;
|
||||
@property (nonatomic) OWSDisappearingMessagesConfiguration *disappearingMessagesConfiguration;
|
||||
|
@ -139,10 +140,11 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
return [self.thread isKindOfClass:[TSGroupThread class]];
|
||||
}
|
||||
|
||||
- (void)configureWithThread:(TSThread *)thread
|
||||
- (void)configureWithThread:(TSThread *)thread uiDatabaseConnection:(YapDatabaseConnection *)uiDatabaseConnection
|
||||
{
|
||||
OWSAssert(thread);
|
||||
self.thread = thread;
|
||||
self.uiDatabaseConnection = uiDatabaseConnection;
|
||||
|
||||
if ([self.thread isKindOfClass:[TSContactThread class]]) {
|
||||
self.title = NSLocalizedString(
|
||||
|
@ -262,6 +264,13 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
mainSection.customHeaderView = [self mainSectionHeader];
|
||||
mainSection.customHeaderHeight = @(100.f);
|
||||
|
||||
[mainSection addItem:[OWSTableItem itemWithCustomCellBlock:^{
|
||||
return [weakSelf disclosureCellWithName:MediaStrings.allMedia iconName:@"actionsheet_camera_roll_black"];
|
||||
}
|
||||
actionBlock:^{
|
||||
[weakSelf showMediaGallery];
|
||||
}]];
|
||||
|
||||
if ([self.thread isKindOfClass:[TSContactThread class]] && self.contactsManager.supportsContactEditing
|
||||
&& !self.hasExistingContact) {
|
||||
[mainSection addItem:[OWSTableItem itemWithCustomCellBlock:^{
|
||||
|
@ -330,13 +339,6 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
}]];
|
||||
}
|
||||
|
||||
[mainSection addItem:[OWSTableItem itemWithCustomCellBlock:^{
|
||||
return [weakSelf disclosureCellWithName:MediaStrings.allMedia iconName:@"actionsheet_camera_roll_black"];
|
||||
}
|
||||
actionBlock:^{
|
||||
[weakSelf showMediaGallery];
|
||||
}]];
|
||||
|
||||
[mainSection
|
||||
addItem:[OWSTableItem itemWithCustomCellBlock:^{
|
||||
UITableViewCell *cell = [UITableViewCell new];
|
||||
|
@ -1163,7 +1165,10 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
{
|
||||
DDLogDebug(@"%@ in showMediaGallery", self.logTag);
|
||||
|
||||
// [[AllMediaViewController alloc] initWithThread:self.thread];
|
||||
MediaGalleryViewController *vc =
|
||||
[[MediaGalleryViewController alloc] initWithThread:self.thread uiDatabaseConnection:self.uiDatabaseConnection];
|
||||
|
||||
[vc pushTileViewFromNavController:self.navigationController];
|
||||
}
|
||||
#pragma mark - Notifications
|
||||
|
||||
|
|
Loading…
Reference in New Issue