|  |  |  | // Copyright © 2023 Rangeproof Pty Ltd. All rights reserved. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import UIKit | 
					
						
							|  |  |  | import SessionUIKit | 
					
						
							|  |  |  | import SessionUtilitiesKit | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | final class MediaInfoVC: BaseVC, SessionCarouselViewDelegate { | 
					
						
							|  |  |  |     internal static let mediaSize: CGFloat = UIScreen.main.bounds.width - 2 * Values.veryLargeSpacing | 
					
						
							|  |  |  |     internal static let arrowSize: CGSize = CGSize(width: 20, height: 30) | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     private let attachments: [Attachment] | 
					
						
							|  |  |  |     private let isOutgoing: Bool | 
					
						
							|  |  |  |     private let threadId: String | 
					
						
							|  |  |  |     private let threadVariant: SessionThread.Variant | 
					
						
							|  |  |  |     private let interactionId: Int64 | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     private var currentPage: Int = 0 | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     // MARK: - UI | 
					
						
							|  |  |  |     private lazy var mediaInfoView: MediaInfoView = MediaInfoView(attachment: nil) | 
					
						
							|  |  |  |     private lazy var mediaCarouselView: SessionCarouselView = { | 
					
						
							|  |  |  |         let slices: [MediaPreviewView] = self.attachments.map { | 
					
						
							|  |  |  |             MediaPreviewView( | 
					
						
							|  |  |  |                 attachment: $0, | 
					
						
							|  |  |  |                 isOutgoing: self.isOutgoing | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         let result: SessionCarouselView = SessionCarouselView( | 
					
						
							|  |  |  |             info: SessionCarouselView.Info( | 
					
						
							|  |  |  |                 slices: slices, | 
					
						
							|  |  |  |                 copyOfFirstSlice: slices.first?.copyView(), | 
					
						
							|  |  |  |                 copyOfLastSlice: slices.last?.copyView(), | 
					
						
							|  |  |  |                 sliceSize: CGSize( | 
					
						
							|  |  |  |                     width: Self.mediaSize, | 
					
						
							|  |  |  |                     height: Self.mediaSize | 
					
						
							|  |  |  |                 ), | 
					
						
							|  |  |  |                 shouldShowPageControl: true, | 
					
						
							|  |  |  |                 pageControlStyle: SessionCarouselView.PageControlStyle( | 
					
						
							|  |  |  |                     size: .medium, | 
					
						
							|  |  |  |                     backgroundColor: .init(white: 0, alpha: 0.4), | 
					
						
							|  |  |  |                     bottomInset: Values.mediumSpacing | 
					
						
							|  |  |  |                 ), | 
					
						
							|  |  |  |                 shouldShowArrows: true, | 
					
						
							|  |  |  |                 arrowsSize: Self.arrowSize, | 
					
						
							|  |  |  |                 cornerRadius: 8 | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |         result.set(.height, to: Self.mediaSize) | 
					
						
							|  |  |  |         result.delegate = self | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         return result | 
					
						
							|  |  |  |     }() | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     private lazy var fullScreenButton: UIButton = { | 
					
						
							|  |  |  |         let result: UIButton = UIButton(type: .custom) | 
					
						
							|  |  |  |         result.setImage( | 
					
						
							|  |  |  |             UIImage(systemName: "arrow.up.left.and.arrow.down.right")? | 
					
						
							|  |  |  |                 .withRenderingMode(.alwaysTemplate), | 
					
						
							|  |  |  |             for: .normal | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |         result.themeTintColor = .textPrimary | 
					
						
							|  |  |  |         result.backgroundColor = .init(white: 0, alpha: 0.4) | 
					
						
							|  |  |  |         result.layer.cornerRadius = 14 | 
					
						
							|  |  |  |         result.set(.width, to: 28) | 
					
						
							|  |  |  |         result.set(.height, to: 28) | 
					
						
							|  |  |  |         result.addTarget(self, action: #selector(showMediaFullScreen), for: .touchUpInside) | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         return result | 
					
						
							|  |  |  |     }() | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     // MARK: - Initialization | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     init( | 
					
						
							|  |  |  |         attachments: [Attachment], | 
					
						
							|  |  |  |         isOutgoing: Bool, | 
					
						
							|  |  |  |         threadId: String, | 
					
						
							|  |  |  |         threadVariant: SessionThread.Variant, | 
					
						
							|  |  |  |         interactionId: Int64 | 
					
						
							|  |  |  |     ) { | 
					
						
							|  |  |  |         self.threadId = threadId | 
					
						
							|  |  |  |         self.threadVariant = threadVariant | 
					
						
							|  |  |  |         self.interactionId = interactionId | 
					
						
							|  |  |  |         self.isOutgoing = isOutgoing | 
					
						
							|  |  |  |         self.attachments = attachments | 
					
						
							|  |  |  |         super.init(nibName: nil, bundle: nil) | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     override init(nibName: String?, bundle: Bundle?) { | 
					
						
							|  |  |  |         preconditionFailure("Use init(attachments:) instead.") | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     required init?(coder: NSCoder) { | 
					
						
							|  |  |  |         preconditionFailure("Use init(attachments:) instead.") | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     // MARK: - Lifecycle | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     override func viewDidLoad() { | 
					
						
							|  |  |  |         super.viewDidLoad() | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         ViewControllerUtilities.setUpDefaultSessionStyle( | 
					
						
							|  |  |  |             for: self, | 
					
						
							|  |  |  |             title: "message_info_title".localized(), | 
					
						
							|  |  |  |             hasCustomBackButton: false | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         let mediaStackView: UIStackView = UIStackView() | 
					
						
							|  |  |  |         mediaStackView.axis = .horizontal | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         mediaInfoView.update(attachment: attachments[0]) | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         mediaCarouselView.addSubview(fullScreenButton) | 
					
						
							|  |  |  |         fullScreenButton.pin(.trailing, to: .trailing, of: mediaCarouselView, withInset: -(Values.smallSpacing + Values.veryLargeSpacing)) | 
					
						
							|  |  |  |         fullScreenButton.pin(.bottom, to: .bottom, of: mediaCarouselView, withInset: -Values.smallSpacing) | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         let stackView: UIStackView = UIStackView(arrangedSubviews: [ mediaCarouselView, mediaInfoView ]) | 
					
						
							|  |  |  |         stackView.axis = .vertical | 
					
						
							|  |  |  |         stackView.alignment = .center | 
					
						
							|  |  |  |         stackView.spacing = Values.largeSpacing | 
					
						
							|  |  |  |          | 
					
						
							|  |  |  |         self.view.addSubview(stackView) | 
					
						
							|  |  |  |         stackView.pin([ UIView.HorizontalEdge.leading, UIView.HorizontalEdge.trailing ], to: self.view) | 
					
						
							|  |  |  |         stackView.pin(.top, to: .top, of: self.view, withInset: Values.veryLargeSpacing) | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     // MARK: - Interaction | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     @objc func showMediaFullScreen() { | 
					
						
							|  |  |  |         let attachment = self.attachments[self.currentPage] | 
					
						
							|  |  |  |         let viewController: UIViewController? = MediaGalleryViewModel.createDetailViewController( | 
					
						
							|  |  |  |             for: self.threadId, | 
					
						
							|  |  |  |             threadVariant: self.threadVariant, | 
					
						
							|  |  |  |             interactionId: self.interactionId, | 
					
						
							|  |  |  |             selectedAttachmentId: attachment.id, | 
					
						
							|  |  |  |             options: [ .sliderEnabled ] | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |         if let viewController: UIViewController = viewController { | 
					
						
							|  |  |  |             viewController.transitioningDelegate = nil | 
					
						
							|  |  |  |             self.present(viewController, animated: true) | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     // MARK: - SessionCarouselViewDelegate | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |     func carouselViewDidScrollToNewSlice(currentPage: Int) { | 
					
						
							|  |  |  |         self.currentPage = currentPage | 
					
						
							|  |  |  |         mediaInfoView.update(attachment: attachments[currentPage]) | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } |